Skip to content

Commit

Permalink
Critical bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Mqzn committed Mar 4, 2025
1 parent 1d55b2a commit b0ab826
Show file tree
Hide file tree
Showing 30 changed files with 270 additions and 57 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

allprojects {
group = "dev.velix"
version = "1.6.1"
version = "1.7.0"

ext {
def kyoriVersion = "4.17.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.base.Charsets;
import com.mojang.authlib.GameProfile;
import dev.velix.imperat.BukkitSource;
import dev.velix.imperat.Imperat;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
Expand All @@ -29,6 +30,7 @@ public class ParameterOfflinePlayer extends BaseParameterType<BukkitSource, Offl

protected final boolean ifCachedOnly;

private final PlayerSuggestionResolver playerSuggestionResolver = new PlayerSuggestionResolver();
public ParameterOfflinePlayer(boolean ifCachedOnly) {
super(TypeWrap.of(OfflinePlayer.class));
this.ifCachedOnly = ifCachedOnly;
Expand Down Expand Up @@ -73,6 +75,16 @@ public boolean matchesInput(String input, CommandParameter<BukkitSource> paramet
return input.length() <= 16;
}

@Override
public @NotNull OfflinePlayer fromString(Imperat<BukkitSource> imperat, String input) {
return Bukkit.getOfflinePlayer(input);
}

@Override
public SuggestionResolver<BukkitSource> getSuggestionResolver() {
return playerSuggestionResolver;
}

private final static class PlayerSuggestionResolver implements SuggestionResolver<BukkitSource> {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.velix.imperat.type;

import dev.velix.imperat.BukkitSource;
import dev.velix.imperat.Imperat;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
Expand All @@ -16,6 +17,7 @@
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Objects;

public class ParameterPlayer extends BaseParameterType<BukkitSource, Player> {

Expand Down Expand Up @@ -49,6 +51,11 @@ public boolean matchesInput(String input, CommandParameter<BukkitSource> paramet
return input.length() <= 16;
}

@Override
public @NotNull Player fromString(Imperat<BukkitSource> imperat, String input) {
return Objects.requireNonNull(Bukkit.getPlayer(input));
}

/**
* Returns the suggestion resolver associated with this parameter type.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.velix.imperat.type;

import dev.velix.imperat.BukkitSource;
import dev.velix.imperat.Imperat;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
Expand Down Expand Up @@ -143,6 +144,11 @@ public SuggestionResolver<BukkitSource> getSuggestionResolver() {
return suggestionResolver;
}

@Override
public @NotNull TargetSelector fromString(Imperat<BukkitSource> imperat, String input) {
return TargetSelector.empty();
}

private final class TargetSelectorSuggestionResolver implements SuggestionResolver<BukkitSource> {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.velix.imperat.type;

import dev.velix.imperat.BukkitSource;
import dev.velix.imperat.Imperat;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
import dev.velix.imperat.context.internal.CommandInputStream;
Expand Down Expand Up @@ -80,4 +81,9 @@ public SuggestionResolver<BukkitSource> getSuggestionResolver() {
}

}

@Override
public @NotNull World fromString(Imperat<BukkitSource> imperat, String input) {
return Objects.requireNonNull(Bukkit.getWorld(input));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.velix.imperat.type;

import dev.velix.imperat.BungeeSource;
import dev.velix.imperat.Imperat;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
Expand Down Expand Up @@ -52,6 +53,11 @@ public boolean matchesInput(String input, CommandParameter<BungeeSource> paramet
return ProxyServer.getInstance().getPlayer(input) != null;
}

@Override
public @NotNull ProxiedPlayer fromString(Imperat<BungeeSource> imperat, String input) {
return ProxyServer.getInstance().getPlayer(input);
}

/**
* Returns the suggestion resolver associated with this parameter type.
*
Expand Down
2 changes: 2 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ dependencies {
compileOnly "org.jetbrains:annotations:24.1.0"
annotationProcessor "org.jetbrains:annotations:24.1.0"

implementation 'org.ow2.asm:asm:9.6'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import dev.velix.imperat.help.CommandHelp;
import dev.velix.imperat.supplier.OptionalValueSupplier;
import dev.velix.imperat.util.TypeUtility;
import dev.velix.imperat.util.TypeWrap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -57,11 +58,10 @@ public static <S extends Source> Object[] loadParameterInstances(
paramsInstances[0] = context.getResolvedSource(firstParam.getType());
}


for (int i = 1, p = 0; i < method.size(); i++, p++) {
ParameterElement actualParameter = method.getParameterAt(i);

assert actualParameter != null;

var contextResolver = dispatcher.config().getMethodParamContextResolver(actualParameter);

if (contextResolver != null) {
Expand All @@ -87,6 +87,7 @@ public static <S extends Source> Object[] loadParameterInstances(
}

String name = parameter.name();

if (parameter.isFlag()) {
paramsInstances[i] = context.getFlagValue(name);
} else {
Expand Down Expand Up @@ -150,16 +151,21 @@ else if (switchAnnotation != null)
}

@SuppressWarnings("unchecked")
public static <T> @NotNull OptionalValueSupplier<T> deduceOptionalValueSupplier(
public static <S extends Source, T> @NotNull OptionalValueSupplier<T> deduceOptionalValueSupplier(
Imperat<S> imperat,
Parameter parameter,
Default defaultAnnotation,
DefaultProvider provider,
OptionalValueSupplier<T> fallback
) {
) throws ImperatException {

if (defaultAnnotation != null) {
String def = defaultAnnotation.value();
return (OptionalValueSupplier<T>) OptionalValueSupplier.of(def);
var type = imperat.config().getParameterType(TypeWrap.of(parameter.getType()).getType());
if (type == null) {
return (OptionalValueSupplier<T>) OptionalValueSupplier.empty(TypeWrap.of(parameter.getType()));
}
return (OptionalValueSupplier<T>) OptionalValueSupplier.of(type.fromString(imperat, def));
} else if (provider != null) {
Class<? extends OptionalValueSupplier<?>> supplierClass = provider.value();
try {
Expand All @@ -173,21 +179,36 @@ else if (switchAnnotation != null)
return fallback;
}

public static int loadMethodPriority(Method method) {
int count = method.getParameterCount();
if (AnnotationHelper.isMethodHelp(method)) {
count--;
/*public static <S extends Source> int loadMethodPriority(Method method, ImperatConfig<S> config) {
int actualParamInputs = 0;
for(var param : method.getParameters()) {
if(config.hasContextResolver(param.getType()) || config.hasSourceResolver(param.getType())) {
continue;
}
actualParamInputs++;
}
if (method.isAnnotationPresent(Usage.class)) {
if(method.isAnnotationPresent(Usage.class) && actualParamInputs >= 1) {
//MAIN USAGE
return -100;
}
else if (method.isAnnotationPresent(Usage.class)) {
//if default -> -1 else -> 0;
return count == 1 ? -1 : 0;
return 1;
} else if (method.isAnnotationPresent(SubCommand.class)) {
return 2 + count;
if(method.getAnnotation(SubCommand.class).attachDirectly()) {
return -2;
}
else {
return -1;
}
}
return 100;
}
return 0;
}
*/

public static boolean isHelpParameter(Parameter element) {
return TypeUtility.areRelatedTypes(element.getType(), CommandHelp.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
import dev.velix.imperat.annotations.base.element.selector.ElementSelector;
import dev.velix.imperat.command.Command;
import dev.velix.imperat.context.Source;
import dev.velix.imperat.util.ImperatDebugger;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@ApiStatus.Internal
final class AnnotationReaderImpl<S extends Source> implements AnnotationReader<S> {

private final static Comparator<Method> METHOD_COMPARATOR = Comparator.comparingInt(AnnotationHelper::loadMethodPriority);
//private final Comparator<Method> METHOD_COMPARATOR;

private final Imperat<S> imperat;
private final AnnotationParser<S> parser;
Expand All @@ -38,6 +38,7 @@ final class AnnotationReaderImpl<S extends Source> implements AnnotationReader<S
this.parser = parser;
this.rootCommandClass = new RootCommandClass<>(instance.getClass(), instance);
this.methodSelector = methodSelector;
//METHOD_COMPARATOR = Comparator.comparingInt(m -> AnnotationHelper.loadMethodPriority(m, imperat.config()));
this.classElement = read(imperat);
}

Expand All @@ -53,9 +54,14 @@ private ClassElement readClass(
) {
ClassElement root = new ClassElement(parser, parent, clazz);
//Adding methods with their parameters
Method[] methods = clazz.getDeclaredMethods();
Arrays.sort(methods, METHOD_COMPARATOR);

List<Method> methods;
try {
methods = MethodOrderHelper.getMethodsInSourceOrder(clazz);
} catch (Exception e) {
ImperatDebugger.error(AnnotationReaderImpl.class, "readClass", e);
throw new RuntimeException(e);
}
//Arrays.sort(methods, METHOD_COMPARATOR);
for (Method method : methods) {
MethodElement methodElement = new MethodElement(imperat, parser, root, method);
if (methodSelector.canBeSelected(imperat, parser, methodElement, false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public void execute(S source,
source, context, method
);
for (int i = 0; i < instances.length; i++) {
ImperatDebugger.debug("Object #%s = '%s'", i, instances[i]);
var instance = instances[i];
ImperatDebugger.debug("Object #%s = '%s', type='%s'", i, instance, instance != null ? instances[i].getClass().getName() : "N/A");
}

try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package dev.velix.imperat.annotations.base;

import org.objectweb.asm.*;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MethodOrderHelper {
public static List<Method> getMethodsInSourceOrder(Class<?> clazz) throws Exception {
String className = clazz.getName().replace('.', '/') + ".class";
try (InputStream stream = clazz.getClassLoader().getResourceAsStream(className)) {
if (stream == null) {
throw new IOException("Class resource not found: " + className);
}

// First pass: Get method order from ASM
ClassReader reader = new ClassReader(stream);
MethodOrderVisitor visitor = new MethodOrderVisitor();
reader.accept(visitor, ClassReader.SKIP_DEBUG);

// Create map of method signatures to reflection Method objects
Map<String, Method> methodMap = new HashMap<>();
for (Method method : clazz.getDeclaredMethods()) {
String key = method.getName() + Type.getMethodDescriptor(method);
methodMap.put(key, method);
}

// Build ordered list based on ASM visitation order
List<Method> orderedMethods = new ArrayList<>();
for (MethodSignature signature : visitor.getMethodSignatures()) {
Method method = methodMap.get(signature.name + signature.descriptor);
if (method != null && !method.isSynthetic()) {
orderedMethods.add(method);
}
}

return orderedMethods;
}
}

private static class MethodOrderVisitor extends ClassVisitor {
private final List<MethodSignature> methodSignatures = new ArrayList<>();

public MethodOrderVisitor() {
super(Opcodes.ASM9);
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
// Record method signature in visitation order
methodSignatures.add(new MethodSignature(name, descriptor));
return super.visitMethod(access, name, descriptor, signature, exceptions);
}

public List<MethodSignature> getMethodSignatures() {
return methodSignatures;
}
}

private static class MethodSignature {
final String name;
final String descriptor;

MethodSignature(String name, String descriptor) {
this.name = name;
this.descriptor = descriptor;
}
}
}
Loading

0 comments on commit b0ab826

Please sign in to comment.