Skip to content

Commit

Permalink
Support minecraft 1.21.3 old enums
Browse files Browse the repository at this point in the history
  • Loading branch information
Rollczi committed Jan 6, 2025
1 parent d9c899e commit 609d02a
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 9 deletions.
4 changes: 2 additions & 2 deletions examples/bukkit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ tasks.shadowJar {

tasks.withType<JavaCompile> {
options.compilerArgs.add("-parameters")
options.release = 17
options.release = 21
}

sourceSets.test {
Expand All @@ -54,6 +54,6 @@ sourceSets.test {
}

tasks.runServer {
minecraftVersion("1.21")
minecraftVersion("1.21.4")
allJvmArgs = listOf("-DPaper.IgnoreJavaVersion=true")
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.rollczi.example.bukkit;

import dev.rollczi.example.bukkit.argument.GameModeArgument;
import dev.rollczi.example.bukkit.command.CatCommand;
import dev.rollczi.example.bukkit.command.ConvertCommand;
import dev.rollczi.example.bukkit.command.FlyCommand;
import dev.rollczi.example.bukkit.command.GameModeCommand;
Expand Down Expand Up @@ -67,6 +68,7 @@ public void onEnable() {
new NumberCommand(),
new CurrencyCommand(currencyService),
new CurrencyBalanceCommand(currencyService),
new CatCommand(),
new UserCommand()
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dev.rollczi.example.bukkit.command;

import dev.rollczi.litecommands.annotations.argument.Arg;
import dev.rollczi.litecommands.annotations.command.Command;
import dev.rollczi.litecommands.annotations.context.Context;
import dev.rollczi.litecommands.annotations.execute.Execute;
import org.bukkit.Location;
import org.bukkit.entity.Cat;
import org.bukkit.entity.EntityType;

@Command(name = "cat")
public class CatCommand {

@Execute
void executeCat(@Context Location currentLocation, @Arg Cat.Type type) {
Cat cat = (Cat) currentLocation.getWorld().spawnEntity(currentLocation, EntityType.CAT);
cat.setCatType(type);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void execute(
@Arg("item") Material item,
@OptionalArg("amount") Integer amount
) {
if (amount != null) {
if (amount == null) {
amount = 1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import dev.rollczi.litecommands.LiteCommandsFactory;
import dev.rollczi.litecommands.bukkit.argument.LocationArgument;
import dev.rollczi.litecommands.bukkit.argument.OfflinePlayerArgument;
import dev.rollczi.litecommands.bukkit.argument.OldEnumAccessor;
import dev.rollczi.litecommands.bukkit.argument.OldEnumArgument;
import dev.rollczi.litecommands.bukkit.argument.PlayerArgument;
import dev.rollczi.litecommands.bukkit.argument.WorldArgument;
import dev.rollczi.litecommands.bukkit.context.LocationContext;
import dev.rollczi.litecommands.bukkit.context.PlayerOnlyContextProvider;
import dev.rollczi.litecommands.bukkit.context.WorldContext;
import dev.rollczi.litecommands.bukkit.util.BukkitFallbackPrefixUtil;
import dev.rollczi.litecommands.message.MessageRegistry;
import dev.rollczi.litecommands.reflect.type.TypeRange;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
Expand Down Expand Up @@ -75,6 +78,11 @@ public static <B extends LiteCommandsBuilder<CommandSender, LiteBukkitSettings,
.context(Location.class, new LocationContext(messageRegistry))

.result(String.class, new StringHandler());

if (OldEnumAccessor.isAvailable()) {
TypeRange<Object> upwards = (TypeRange<Object>) TypeRange.upwards(OldEnumAccessor.getTypeOrThrow());
builder.advanced().argument(upwards, new OldEnumArgument());
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ public class LiteBukkitSettings implements PlatformSettings {
private BukkitCommandsRegistry commandsRegistry;
private TabComplete tabCompleter;

public LiteBukkitSettings() {
public LiteBukkitSettings(BukkitCommandsRegistry commandsRegistry) {
this.commandsRegistry = commandsRegistry;
}

LiteBukkitSettings(Server server) {
public LiteBukkitSettings(Server server) {
this.commandsRegistry = BukkitCommandsRegistryImpl.create(server);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package dev.rollczi.litecommands.bukkit.argument;

import dev.rollczi.litecommands.reflect.LiteCommandsReflectException;
import dev.rollczi.litecommands.reflect.ReflectUtil;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;

public class OldEnumAccessor {

private static final Map<Class<?>, Method> VALUE_OF_METHODS = new HashMap<>();
private static final Map<Class<?>, Method> NAME_METHODS = new HashMap<>();
private static final Map<Class<?>, Method> VALUES_METHODS = new HashMap<>();

public static boolean isAvailable() {
return getType().isPresent();
}

public static Class<?> getTypeOrThrow() {
return getType().orElseThrow(() -> new IllegalStateException("OldEnum is not available"));
}

public static Optional<Class<?>> getType() {
try {
return Optional.of(Class.forName("org.bukkit.util.OldEnum"));
} catch (ClassNotFoundException classNotFoundException) {
return Optional.empty();
}
}

public static Object invokeValueOf(Class<?> type, String source) {
if (!isInstanceOfOldEnum(type)) {
throw new IllegalArgumentException("Type is not an instance of OldEnum");
}

Method valueOfMethod = VALUE_OF_METHODS.computeIfAbsent(type, key -> ReflectUtil.getMethod(type, "valueOf", String.class));
try {
return ReflectUtil.invokeStaticMethod(valueOfMethod, source);
} catch (LiteCommandsReflectException exception) {
throw exception.toRuntimeException();
}
}

public static String invokeName(Object source) {
Class<?> type = source.getClass();
if (!isInstanceOfOldEnum(type)) {
throw new IllegalArgumentException("Type is not an instance of OldEnum");
}

Method nameMethod = NAME_METHODS.computeIfAbsent(type, key -> ReflectUtil.getMethod(type, "name"));
try {
return ReflectUtil.invokeMethod(nameMethod, source);
} catch (LiteCommandsReflectException exception) {
throw exception.toRuntimeException();
}
}

public static Object[] invokeValues(Class<?> type) {
if (!isInstanceOfOldEnum(type)) {
throw new IllegalArgumentException("Type is not an instance of OldEnum");
}

Method valuesMethod = VALUES_METHODS.computeIfAbsent(type, key -> ReflectUtil.getMethod(type, "values"));
try {
return ReflectUtil.invokeStaticMethod(valuesMethod);
} catch (LiteCommandsReflectException exception) {
throw exception.toRuntimeException();
}
}

private static @NotNull Boolean isInstanceOfOldEnum(Class<?> type) {
return getType()
.map(oldEnum -> oldEnum.isAssignableFrom(type))
.orElse(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.rollczi.litecommands.bukkit.argument;

import dev.rollczi.litecommands.argument.Argument;
import dev.rollczi.litecommands.argument.parser.ParseResult;
import dev.rollczi.litecommands.argument.resolver.ArgumentResolver;
import dev.rollczi.litecommands.invalidusage.InvalidUsage;
import dev.rollczi.litecommands.invocation.Invocation;
import dev.rollczi.litecommands.suggestion.SuggestionContext;
import dev.rollczi.litecommands.suggestion.SuggestionResult;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.command.CommandSender;

public class OldEnumArgument extends ArgumentResolver<CommandSender, Object> {

private final Map<Class<?>, SuggestionResult> cachedOldEnumSuggestions = new HashMap<>();

@Override
public boolean canParse(Argument<Object> argument) {
return OldEnumAccessor.getType().map(type -> type.isAssignableFrom(argument.getType().getRawType()))
.orElseThrow(() -> new IllegalStateException("OldEnumArgument can't be used without on old bukkit version"));
}

@Override
protected ParseResult<Object> parse(Invocation<CommandSender> invocation, Argument<Object> context, String argument) {
try {
return ParseResult.success(OldEnumAccessor.invokeValueOf(context.getType().getRawType(), argument));
} catch (IllegalArgumentException ignored) {
return ParseResult.failure(InvalidUsage.Cause.INVALID_ARGUMENT);
}
}

@Override
public SuggestionResult suggest(Invocation<CommandSender> invocation, Argument<Object> argument, SuggestionContext context) {
Class<?> oldEnumClass = argument.getType().getRawType();

return cachedOldEnumSuggestions.computeIfAbsent(oldEnumClass, key -> {
Object[] oldEnums = OldEnumAccessor.invokeValues(oldEnumClass);
if (oldEnums.length == 0) {
return SuggestionResult.empty();
}

return Arrays.stream(oldEnums)
.map(oldEnum -> OldEnumAccessor.invokeName(oldEnum))
.collect(SuggestionResult.collector());
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,11 @@ public LiteCommandsException(String message, List<? extends Throwable> exception
exceptions.forEach(exception -> addSuppressed(exception));
}

public RuntimeException toRuntimeException() {
if (getCause() instanceof Exception) {
return (RuntimeException) getCause();
}
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.function.Function;
import java.util.function.Supplier;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.UnknownNullability;

public interface ParseResult<EXCEPTED> extends RequirementFutureResult<EXCEPTED> {

Expand Down Expand Up @@ -71,7 +72,7 @@ static <EXPECTED> ParseAsyncResult<EXPECTED> completableFuture(CompletableFuture
}

@ApiStatus.Experimental
static <T, EXPECTED> ParseAsyncResult<EXPECTED> completableFuture(CompletableFuture<T> future, Function<T, ? extends ParseResult<EXPECTED>> mapper) {
static <T, EXPECTED> ParseAsyncResult<EXPECTED> completableFuture(CompletableFuture<T> future, Function<@UnknownNullability T, ? extends ParseResult<EXPECTED>> mapper) {
return new ParseAsyncResult<>(future.thenApply(mapper));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ public Iterator<Class<?>> iterator() {
private class TypeIterator implements Iterator<Class<?>> {

private Class<?> next;
private Class<?> lastSuperclass;
private final Queue<Class<?>> interfaces = new LinkedList<>();
private final Set<Class<?>> visitedInterfaces = new HashSet<>();

private TypeIterator() {
this.next = baseType;
this.lastSuperclass = baseType;
this.interfaces.addAll(ReflectIndex.getInterfaces(baseType));
}

@Override
Expand Down Expand Up @@ -60,10 +63,11 @@ public Class<?> next() {
return nextToReturn;
}

Class<?> superclass = nextToReturn.getSuperclass();
Class<?> superclass = this.lastSuperclass.getSuperclass();

if (superclass != null) {
this.next = superclass;
this.lastSuperclass = superclass;
interfaces.addAll(ReflectIndex.getInterfaces(superclass));
return nextToReturn;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -147,8 +148,11 @@ public static <T> T invokeMethod(Method method, Object instance, Object... param
try {
return (T) method.invoke(instance, params);
}
catch (Exception exception) {
throw new LiteCommandsReflectException("Unable to invoke method " + method.getName() + " in " + instance.getClass(), exception);
catch (InvocationTargetException invocationTargetException) {
throw new LiteCommandsReflectException("Unable to invoke method " + method.getName() + " in " + instance.getClass(), invocationTargetException.getCause());
}
catch (IllegalAccessException exception) {
throw new LiteCommandsReflectException("Cannot access method " + method.getName() + " in " + instance.getClass(), exception);
}
}

Expand Down

0 comments on commit 609d02a

Please sign in to comment.