diff --git a/libraries/commands/build.gradle b/libraries/commands/build.gradle new file mode 100644 index 00000000..e98ba2c6 --- /dev/null +++ b/libraries/commands/build.gradle @@ -0,0 +1 @@ +setUpLibrary(project) diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/build.gradle b/libraries/commands/commands-mc1.12-mc1.12.2/build.gradle new file mode 100644 index 00000000..31511a9c --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/build.gradle @@ -0,0 +1,10 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.13.2', + 'lifecycle-events-mc13w36a-09051446-mc1.13', + 'networking-mc14w31a-mc1.13-pre2', + 'resource-loader-mc13w26a-mc1.12.2' +) + +dependencies { + include(modImplementation("com.mojang:brigadier:${project.brigadier_version}")) +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/gradle.properties b/libraries/commands/commands-mc1.12-mc1.12.2/gradle.properties new file mode 100644 index 00000000..d34b7267 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/gradle.properties @@ -0,0 +1,7 @@ +environment = * +min_mc_version = 1.12 +max_mc_version = 1.12.2 +mc_version_range = >=1.12 <=1.12.2 + +feather_build = 16 +brigadier_version = 1.0.18 diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/AbstractCommandSourceStack.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/AbstractCommandSourceStack.java new file mode 100644 index 00000000..e1972dff --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/AbstractCommandSourceStack.java @@ -0,0 +1,152 @@ +package net.ornithemc.osl.commands.api; + +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.function.BinaryOperator; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.ResultConsumer; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.Entity; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.text.Formatting; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.ornithemc.osl.commands.api.argument.AnchorArgument; + +public abstract class AbstractCommandSourceStack> implements SuggestionProvider { + + public static final SimpleCommandExceptionType NOT_PLAYER_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("permissions.requires.player")); + public static final SimpleCommandExceptionType NOT_ENTITY_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("permissions.requires.entity")); + + protected final BrigadierCommandSource source; + protected final Vec3d pos; + protected final int permissions; + protected final String name; + protected final Text displayName; + protected final boolean silent; + protected final Entity entity; + protected final ResultConsumer callback; + protected final AnchorArgument.Anchor anchor; + protected final Vec2f rotation; + + protected AbstractCommandSourceStack(BrigadierCommandSource source, Vec3d pos, Vec2f rotation, int permissions, String name, Text displayName, Entity entity, boolean silent, ResultConsumer callback, AnchorArgument.Anchor anchor) { + this.source = source; + this.pos = pos; + this.silent = silent; + this.entity = entity; + this.permissions = permissions; + this.name = name; + this.displayName = displayName; + this.callback = callback; + this.anchor = anchor; + this.rotation = rotation; + } + + public abstract S withEntity(Entity entity); + + public abstract S withPos(Vec3d pos); + + public abstract S withRotation(Vec2f rotation); + + public abstract S withCallback(ResultConsumer callback); + + public abstract S withCallback(ResultConsumer callback, BinaryOperator> chooser); + + public abstract S silent(); + + public abstract S withPermissions(int permissions); + + public abstract S withMaxPermissions(int maxPermissions); + + public abstract S withAnchor(AnchorArgument.Anchor anchor); + + public abstract S withFacing(Entity entity, AnchorArgument.Anchor anchor) throws CommandSyntaxException; + + public abstract S withFacing(Vec3d target) throws CommandSyntaxException; + + public Text getDisplayName() { + return this.displayName; + } + + public String getName() { + return this.name; + } + + @Override + public boolean hasPermissions(int permissions) { + return this.permissions >= permissions; + } + + public Vec3d getPos() { + return this.pos; + } + + public abstract World getWorld(); + + public Entity getEntity() { + return this.entity; + } + + public Entity getEntityOrThrow() throws CommandSyntaxException { + if (this.entity == null) { + throw NOT_ENTITY_EXCEPTION.create(); + } + + return this.entity; + } + + public ServerPlayerEntity getPlayerOrThrow() throws CommandSyntaxException { + if (!(this.entity instanceof ServerPlayerEntity)) { + throw NOT_PLAYER_EXCEPTION.create(); + } + + return (ServerPlayerEntity) this.entity; + } + + public Vec2f getRotation() { + return this.rotation; + } + + public AnchorArgument.Anchor getAnchor() { + return this.anchor; + } + + public void sendFailure(Text message) { + if (this.source.sendCommandFailure() && !this.silent) { + this.source.sendMessage(new LiteralText("").append(message).setStyle(new Style().setColor(Formatting.RED))); + } + } + + public void onCommandComplete(CommandContext ctx, boolean success, int result) { + if (this.callback != null) { + this.callback.onCommandComplete(ctx, success, result); + } + } + + @Override + public CompletableFuture suggest(CommandContext ctx, SuggestionsBuilder builder) { + return null; + } + + @Override + public Collection getCoordinates(boolean absolute) { + return Collections.singleton(SuggestionProvider.Coordinate.DEFAULT_GLOBAL); + } + + @Override + public Collection getTeams() { + return getWorld().getScoreboard().getTeamNames(); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandManager.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandManager.java new file mode 100644 index 00000000..0cf41b0b --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandManager.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.commands.api; + +import java.util.function.Predicate; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class BrigadierCommandManager { + + public static Predicate validator(Parser parser) { + return s -> { + try { + parser.parse(new StringReader(s)); + return true; + } catch (CommandSyntaxException e) { + return false; + } + }; + } + + @FunctionalInterface + public interface Parser { + + void parse(StringReader reader) throws CommandSyntaxException; + + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandSource.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandSource.java new file mode 100644 index 00000000..688fb54e --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/BrigadierCommandSource.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.commands.api; + +import net.minecraft.server.command.source.CommandSource; + +public interface BrigadierCommandSource extends CommandSource { + + boolean sendCommandSuccess(); + + boolean sendCommandFailure(); + + boolean sendCommandSuccessToOps(); + + AbstractCommandSourceStack createCommandSourceStack(); + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java new file mode 100644 index 00000000..4b41d2ec --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.commands.api; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.Command; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; +import net.ornithemc.osl.core.api.events.Event; + +public class CommandEvents { + + public static final Event>> REGISTER_SERVER_COMMANDS = Event.biConsumer(); + public static final Event>> REGISTER_SERVER_BRIGADIER_COMMANDS = Event.consumer(); + + public static final Event>> REGISTER_CLIENT_BRIGADIER_COMMANDS = Event.consumer(); + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/SuggestionProvider.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/SuggestionProvider.java new file mode 100644 index 00000000..8dac52a2 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/SuggestionProvider.java @@ -0,0 +1,207 @@ +package net.ornithemc.osl.commands.api; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import com.google.common.base.Strings; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.resource.Identifier; + +public interface SuggestionProvider { + + Collection getPlayerNames(); + + default Collection getSelectedEntities() { + return Collections.emptyList(); + } + + Collection getTeams(); + + CompletableFuture suggest(CommandContext ctx, SuggestionsBuilder builder); + + Collection getCoordinates(boolean absolute); + + boolean hasPermissions(int permissions); + + static void filterResources(Iterable it, String id, Function idGetter, Consumer action) { + boolean hasColon = id.indexOf(':') > -1; + for (T object : it) { + Identifier identifier = idGetter.apply(object); + if (hasColon) { + String string = identifier.toString(); + if (!string.startsWith(id)) + continue; + action.accept(object); + continue; + } + if (!identifier.getNamespace().startsWith(id) + && (!identifier.getNamespace().equals("minecraft") || !identifier.getPath().startsWith(id))) + continue; + action.accept(object); + } + } + + static void filterResources(Iterable it, String id1, String id2, Function idGetter, Consumer action) { + if (id1.isEmpty()) { + it.forEach(action); + } else { + String prefix = Strings.commonPrefix(id1, id2); + if (!prefix.isEmpty()) { + String target = id1.substring(prefix.length()); + SuggestionProvider.filterResources(it, target, idGetter, action); + } + } + } + + static CompletableFuture suggestResource(Iterable ids, SuggestionsBuilder builder, String id2) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + SuggestionProvider.filterResources(ids, target, id2, id -> id, resource -> builder.suggest(id2 + resource)); + return builder.buildFuture(); + } + + static CompletableFuture suggestResource(Iterable ids, SuggestionsBuilder builder) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + SuggestionProvider.filterResources(ids, target, id -> id, resource -> builder.suggest(resource.toString())); + return builder.buildFuture(); + } + + static CompletableFuture suggestResource(Iterable ids, SuggestionsBuilder builder, Function idGetter, Function suggestionGetter) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + SuggestionProvider.filterResources(ids, target, idGetter, resource -> builder.suggest(((Identifier) idGetter.apply(resource)).toString(), suggestionGetter.apply(resource))); + return builder.buildFuture(); + } + + static CompletableFuture suggestResource(Stream ids, SuggestionsBuilder builder) { + return SuggestionProvider.suggestResource(ids::iterator, builder); + } + + static CompletableFuture suggestResource(Stream ids, SuggestionsBuilder builder, Function idGetter, Function suggestionGetter) { + return SuggestionProvider.suggestResource(ids::iterator, builder, idGetter, suggestionGetter); + } + + static CompletableFuture suggestCoordinates(String s, Collection coordinates, SuggestionsBuilder builder, Predicate validator) { + ArrayList suggestions; + block4: { + String[] strings; + block5: { + block3: { + suggestions = new ArrayList<>(); + if (!Strings.isNullOrEmpty(s)) + break block3; + for (Coordinate coordinate : coordinates) { + String string = coordinate.x + " " + coordinate.y + " " + coordinate.z; + if (!validator.test(string)) + continue; + suggestions.add(coordinate.x); + suggestions.add(coordinate.x + " " + coordinate.y); + suggestions.add(string); + } + break block4; + } + strings = s.split(" "); + if (strings.length != 1) + break block5; + for (Coordinate coordinate2 : coordinates) { + String string2 = strings[0] + " " + coordinate2.y + " " + coordinate2.z; + if (!validator.test(string2)) + continue; + suggestions.add(strings[0] + " " + coordinate2.y); + suggestions.add(string2); + } + break block4; + } + if (strings.length != 2) + break block4; + for (Coordinate coordinate2 : coordinates) { + String string2 = strings[0] + " " + strings[1] + " " + coordinate2.z; + if (!validator.test(string2)) + continue; + suggestions.add(string2); + } + } + return SuggestionProvider.suggestMatching(suggestions, builder); + } + + static CompletableFuture suggestHorizontalCoordinates(String s, Collection coordinates, SuggestionsBuilder builder, Predicate validator) { + ArrayList suggestions; + block3: { + block2: { + suggestions = new ArrayList<>(); + if (!Strings.isNullOrEmpty(s)) + break block2; + for (Coordinate coordinate : coordinates) { + String string = coordinate.x + " " + coordinate.z; + if (!validator.test(string)) + continue; + suggestions.add(coordinate.x); + suggestions.add(string); + } + break block3; + } + String[] strings = s.split(" "); + if (strings.length != 1) + break block3; + for (Coordinate coordinate2 : coordinates) { + String string2 = strings[0] + " " + coordinate2.z; + if (!validator.test(string2)) + continue; + suggestions.add(string2); + } + } + return SuggestionProvider.suggestMatching(suggestions, builder); + } + + static CompletableFuture suggestMatching(Iterable suggestions,SuggestionsBuilder builder) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + for (String suggestion : suggestions) { + if (suggestion.toLowerCase(Locale.ROOT).startsWith(target)) { + builder.suggest(suggestion); + } + } + return builder.buildFuture(); + } + + static CompletableFuture suggestMatching(Stream suggestions, SuggestionsBuilder builder) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + suggestions.filter(s -> s.toLowerCase(Locale.ROOT).startsWith(target)).forEach(builder::suggest); + return builder.buildFuture(); + } + + static CompletableFuture suggestMatching(String[] suggestions, SuggestionsBuilder builder) { + String target = builder.getRemaining().toLowerCase(Locale.ROOT); + for (String suggestion : suggestions) { + if (suggestion.toLowerCase(Locale.ROOT).startsWith(target)) { + builder.suggest(suggestion); + } + } + return builder.buildFuture(); + } + + public class Coordinate { + + public static final Coordinate DEFAULT_LOCAL = new Coordinate("^", "^", "^"); + public static final Coordinate DEFAULT_GLOBAL = new Coordinate("~", "~", "~"); + + public final String x; + public final String y; + public final String z; + + public Coordinate(String x, String y, String z) { + this.x = x; + this.y = y; + this.z = z; + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AnchorArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AnchorArgument.java new file mode 100644 index 00000000..3ac912a2 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AnchorArgument.java @@ -0,0 +1,103 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.Entity; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.commands.api.argument.AnchorArgument.Anchor; + +public class AnchorArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("eyes", "feet"); + private static final DynamicCommandExceptionType INVALID_EXCEPTION = new DynamicCommandExceptionType(anchor -> (Message)new TranslatableText("argument.anchor.invalid", anchor)); + + public static AnchorArgument anchor() { + return new AnchorArgument(); + } + + public static Anchor getAnchor(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Anchor.class); + } + + @Override + public Anchor parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String name = reader.readUnquotedString(); + Anchor anchor = Anchor.byName(name); + + if (anchor == null) { + reader.setCursor(cursor); + throw INVALID_EXCEPTION.createWithContext(reader, name); + } + + return anchor; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(Anchor.BY_NAME.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public enum Anchor { + + FEET("feet", (pos, entity) -> pos), + EYES("eyes", (pos, entity) -> new Vec3d(pos.x, pos.y + entity.getEyeHeight(), pos.z)); + + private static final Map BY_NAME; + + private final String name; + private final BiFunction transform; + + private Anchor(String name, BiFunction transform) { + this.name = name; + this.transform = transform; + } + + public static Anchor byName(String name) { + return BY_NAME.get(name); + } + + public Vec3d apply(Entity entity) { + return this.transform.apply(new Vec3d(entity.x, entity.y, entity.z), entity); + } + + public Vec3d apply(AbstractCommandSourceStack source) { + Entity entity = source.getEntity(); + if (entity == null) { + return source.getPos(); + } + return this.transform.apply(source.getPos(), entity); + } + + static { + BY_NAME = new HashMap<>(); + + for (Anchor anchor : Anchor.values()) { + BY_NAME.put(anchor.name, anchor); + } + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AxesArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AxesArgument.java new file mode 100644 index 00000000..c6c77619 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/AxesArgument.java @@ -0,0 +1,61 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Direction.Axis;; + +public class AxesArgument implements ArgumentType> { + + private static final Collection EXAMPLES = Arrays.asList("xyz", "x"); + private static final SimpleCommandExceptionType INVALID_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("arguments.swizzle.invalid")); + + public static AxesArgument axes() { + return new AxesArgument(); + } + + @SuppressWarnings("unchecked") + public static EnumSet getAxes(CommandContext ctx, String arg) { + return ctx.getArgument(arg, EnumSet.class); + } + + @Override + public EnumSet parse(StringReader reader) throws CommandSyntaxException { + EnumSet axes = EnumSet.noneOf(Axis.class); + while (reader.canRead() && reader.peek() != ' ') { + Axis axis; + switch (reader.read()) { + case 'x': + axis = Axis.X; + break; + case 'y': + axis = Axis.Y; + break; + case 'z': + axis = Axis.Z; + break; + default: + throw INVALID_EXCEPTION.create(); + } + if (axes.contains(axis)) { + throw INVALID_EXCEPTION.create(); + } + axes.add(axis); + } + return axes; + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockArgument.java new file mode 100644 index 00000000..d070d544 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockArgument.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +public class BlockArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("stone", "minecraft:stone", "stone[foo=bar]", "foo{bar=baz}"); + + public static BlockArgument block() { + return new BlockArgument(); + } + + public static BlockInput getBlock(CommandContext ctx, String arg) { + return ctx.getArgument(arg, BlockInput.class); + } + + @Override + public BlockInput parse(StringReader reader) throws CommandSyntaxException { + BlockStateParser parser = new BlockStateParser(reader, false).parse(true); + return new BlockInput(parser.getState(), parser.getProperties().keySet(), parser.getNbt()); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + StringReader reader = new StringReader(builder.getInput()); + reader.setCursor(builder.getStart()); + BlockStateParser parser = new BlockStateParser(reader, false); + try { + parser.parse(true); + } catch (CommandSyntaxException e) { + } + return parser.addSuggestions(builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockInput.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockInput.java new file mode 100644 index 00000000..c5cca6e1 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockInput.java @@ -0,0 +1,72 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Set; +import java.util.function.Predicate; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.pattern.BlockPointer; +import net.minecraft.block.state.BlockState; +import net.minecraft.block.state.property.Property; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class BlockInput implements Predicate { + + private final BlockState state; + private final Set> properties; + private final NbtCompound nbt; + + public BlockInput(BlockState state, Set> properties, NbtCompound nbt) { + this.state = state; + this.properties = properties; + this.nbt = nbt; + } + + public BlockState getState() { + return this.state; + } + + @Override + public boolean test(BlockPointer ptr) { + BlockState state = ptr.getState(); + + if (state.getBlock() != this.state.getBlock()) { + return false; + } + for (Property property : this.properties) { + if (state.get(property) != this.state.get(property)) { + return false; + } + } + if (this.nbt != null) { + BlockEntity blockEntity = ptr.getBlockEntity(); + + if (blockEntity != null) { + return NbtUtils.matches(this.nbt, blockEntity.writeNbt(new NbtCompound()), true); + } + } + + return true; + } + + public boolean set(World world, BlockPos pos, int flags) { + if (!world.setBlockState(pos, this.state, flags)) { + return false; + } + if (this.nbt != null) { + BlockEntity blockEntity = world.getBlockEntity(pos); + + if (blockEntity != null) { + NbtCompound nbt = this.nbt.copy(); + nbt.putInt("x", pos.getX()); + nbt.putInt("y", pos.getY()); + nbt.putInt("z", pos.getZ()); + blockEntity.readNbt(nbt); + } + } + + return true; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockPosArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockPosArgument.java new file mode 100644 index 00000000..1f53b57f --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockPosArgument.java @@ -0,0 +1,74 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.BlockPos; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandManager; +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.commands.impl.interfaces.mixin.IWorld; + +public class BlockPosArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("0 0 0", "~ ~ ~", "^ ^ ^", "^1 ^ ^-5", "~0.5 ~1 ~-5"); + public static final SimpleCommandExceptionType UNLOADED_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos.unloaded")); + public static final SimpleCommandExceptionType OUT_OF_WORLD_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos.outofworld")); + + public static BlockPosArgument blockPos() { + return new BlockPosArgument(); + } + + public static BlockPos getBlockPos(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, Coordinates.class).getBlockPos(ctx.getSource()); + } + + public static BlockPos getLoadedBlockPos(CommandContext> ctx, String arg) throws CommandSyntaxException { + BlockPos pos = getBlockPos(ctx, arg); + if (!ctx.getSource().getWorld().isChunkLoaded(pos)) { + throw UNLOADED_EXCEPTION.create(); + } + if (!((IWorld)ctx.getSource().getWorld()).osl$commands$contains(pos)) { + throw OUT_OF_WORLD_EXCEPTION.create(); + } + return pos; + } + + @Override + public Coordinates parse(StringReader reader) throws CommandSyntaxException { + if (reader.canRead() && reader.peek() == '^') { + return LocalCoordinates.parse(reader); + } + return GlobalCoordinates.parseInt(reader); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof SuggestionProvider) { + String s = builder.getRemaining(); + Collection coordinates = !s.isEmpty() && s.charAt(0) == '^' + ? Collections.singleton(SuggestionProvider.Coordinate.DEFAULT_LOCAL) + : ((SuggestionProvider)ctx.getSource()).getCoordinates(false); + return SuggestionProvider.suggestCoordinates(s, coordinates, builder, BrigadierCommandManager.validator(this::parse)); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockStateParser.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockStateParser.java new file mode 100644 index 00000000..2cf64a51 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/BlockStateParser.java @@ -0,0 +1,312 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Predicate; + +import com.google.common.base.Optional; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.block.Block; +import net.minecraft.block.state.BlockState; +import net.minecraft.block.state.StateDefinition; +import net.minecraft.block.state.property.Property; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.resource.loader.api.ResourceUtils; + +public class BlockStateParser { + + public static final DynamicCommandExceptionType INVALID_ID_EXCEPTION = new DynamicCommandExceptionType(id -> (Message)new TranslatableText("argument.block.id.invalid", id)); + public static final Dynamic2CommandExceptionType INVALID_DATA_EXCEPTION = new Dynamic2CommandExceptionType((id, metadata) -> (Message)new TranslatableText("argument.block.data.invalid", id, metadata)); + public static final Dynamic2CommandExceptionType UNKNOWN_PROPERTY_EXCEPTION = new Dynamic2CommandExceptionType((id, property) -> (Message)new TranslatableText("argument.block.property.unknown", id, property)); + public static final Dynamic2CommandExceptionType DUPLICATE_PROPERTY_EXCEPTION = new Dynamic2CommandExceptionType((id, property) -> (Message)new TranslatableText("argument.block.property.duplicate", property, id)); + public static final Dynamic3CommandExceptionType INVALID_PROPERTY_EXCEPTION = new Dynamic3CommandExceptionType((id, property, value) -> (Message)new TranslatableText("argument.block.property.invalid", id, value, property)); + public static final Dynamic2CommandExceptionType NO_VALUE_EXCEPTION = new Dynamic2CommandExceptionType((id, property) -> (Message)new TranslatableText("argument.block.property.novalue", id, property)); + public static final SimpleCommandExceptionType UNCLOSED_PROPERTY_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.block.property.unclosed", new Object[0])); + + private static final Function> NO_SUGGESTIONS = SuggestionsBuilder::buildFuture; + + private final StringReader reader; + private final boolean legacy; + private final Map, Comparable> properties = new HashMap<>(); + + private Identifier id = new Identifier(""); + private StateDefinition definition; + private BlockState state; + private NbtCompound nbt; + private Function> suggestions = NO_SUGGESTIONS; + + public BlockStateParser(StringReader reader, boolean legacy) { + this.reader = reader; + this.legacy = legacy; + } + + public Map, Comparable> getProperties() { + return this.properties; + } + + public BlockState getState() { + return this.state; + } + + public NbtCompound getNbt() { + return this.nbt; + } + + public BlockStateParser parse() throws CommandSyntaxException { + return parse(false); + } + + public BlockStateParser parse(boolean parseNbt) throws CommandSyntaxException { + if (!this.legacy) { + this.suggestions = this::suggestBlockId; + } + this.parseBlock(); + if (legacy) { + this.suggestions = this::suggestNextProperty; + this.parseProperties(); + this.suggestions = NO_SUGGESTIONS; + } else { + this.suggestions = this::suggestStartPropertiesOrNbt; + if (this.reader.canRead() && this.reader.peek() == '[') { + this.parseProperties(); + this.suggestions = this::suggestNbtStart; + } + if (parseNbt && this.reader.canRead() && this.reader.peek() == '{') { + this.suggestions = NO_SUGGESTIONS; + this.parseNbt(); + } + } + return this; + } + + private CompletableFuture suggestPropertyOrEnd(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty()) { + builder.suggest(String.valueOf(']')); + } + return this.suggestProperty(builder); + } + + private CompletableFuture suggestProperty(SuggestionsBuilder builder) { + String s = builder.getRemaining().toLowerCase(Locale.ROOT); + for (Property property : this.state.properties()) { + if (!this.properties.containsKey(property) && property.getName().startsWith(s)) { + builder.suggest(property.getName() + '='); + } + } + return builder.buildFuture(); + } + + private CompletableFuture suggestNbtStart(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty() && this.state.getBlock().hasBlockEntity()) { + builder.suggest(String.valueOf('{')); + } + return builder.buildFuture(); + } + + private CompletableFuture suggestPropertyValueSeparator(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty()) { + builder.suggest(String.valueOf('=')); + } + return builder.buildFuture(); + } + + private CompletableFuture suggestNextPropertyOrEnd(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty()) { + builder.suggest(String.valueOf(']')); + } + return this.suggestNextProperty(builder); + } + + private CompletableFuture suggestNextProperty(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty() && this.properties.size() < this.state.properties().size()) { + builder.suggest(String.valueOf(',')); + } + return builder.buildFuture(); + } + + private static > SuggestionsBuilder suggestValues(SuggestionsBuilder builder, Property property) { + for (T value : property.values()) { + if (value instanceof Integer) { + builder.suggest((Integer)value); + continue; + } + builder.suggest(property.getName(value)); + } + return builder; + } + + private CompletableFuture suggestStartPropertiesOrNbt(SuggestionsBuilder builder) { + if (builder.getRemaining().isEmpty()) { + if (!this.state.getBlock().stateDefinition().properties().isEmpty()) { + builder.suggest(String.valueOf('[')); + } + if (this.state.getBlock().hasBlockEntity()) { + builder.suggest(String.valueOf('{')); + } + } + return builder.buildFuture(); + } + + private CompletableFuture suggestBlockId(SuggestionsBuilder builder) { + SuggestionProvider.suggestResource(Block.REGISTRY.keySet(), builder); + return builder.buildFuture(); + } + + private void skipBackwards(Predicate condition) throws CommandSyntaxException { + int cursor = this.reader.getCursor(); + do { + this.reader.setCursor(--cursor); + } while (cursor >= 0 && condition.test(this.reader.peek())); + this.reader.setCursor(++cursor); + } + + public void parseBlock() throws CommandSyntaxException { + if (this.legacy) { + skipBackwards(Character::isWhitespace); + skipBackwards(ResourceUtils::isValidChar); + } + int cursor = this.reader.getCursor(); + this.id = IdentifierParser.parse(this.reader); + if (!Block.REGISTRY.containsKey(this.id)) { + this.reader.setCursor(cursor); + throw INVALID_ID_EXCEPTION.createWithContext(this.reader, this.id.toString()); + } + Block block = Block.REGISTRY.get(this.id); + this.definition = block.stateDefinition(); + this.state = block.defaultState(); + if (this.legacy) { + this.reader.skipWhitespace(); + } + } + + public void parseProperties() throws CommandSyntaxException { + if (this.legacy && Character.isDigit(this.reader.peek())) { + this.suggestions = NO_SUGGESTIONS; + int cursor = this.reader.getCursor(); + int metadata = this.reader.readInt(); + if (metadata < 0 || metadata > 15) { + this.reader.setCursor(cursor); + throw INVALID_DATA_EXCEPTION.createWithContext(this.reader, this.id, metadata); + } + this.state = this.definition.getBlock().getStateFromMetadata(metadata); + for (Property property : this.definition.properties()) { + this.properties.put(property, this.state.get(property)); + } + } else { + if (this.legacy) { + this.suggestions = this::suggestProperty; + } else { + this.reader.skip(); + this.suggestions = this::suggestPropertyOrEnd; + this.reader.skipWhitespace(); + } + while (this.reader.canRead() && (this.legacy ? !Character.isWhitespace(this.reader.peek()) : this.reader.peek() != ']')) { + if (!this.legacy) { + this.reader.skipWhitespace(); + } + int propertyNameStart = this.reader.getCursor(); + String propertyName = this.reader.readString(); + Property property = this.definition.getProperty(propertyName); + if (property == null) { + this.reader.setCursor(propertyNameStart); + throw UNKNOWN_PROPERTY_EXCEPTION.createWithContext(this.reader, this.id.toString(), propertyName); + } + if (this.properties.containsKey(property)) { + this.reader.setCursor(propertyNameStart); + throw DUPLICATE_PROPERTY_EXCEPTION.createWithContext(this.reader, this.id.toString(), propertyName); + } + if (!this.legacy) { + this.reader.skipWhitespace(); + } + this.suggestions = this::suggestPropertyValueSeparator; + if (!this.reader.canRead() || this.reader.peek() != '=') { + throw NO_VALUE_EXCEPTION.createWithContext(this.reader, this.id.toString(), propertyName); + } + this.reader.skip(); + if (!this.legacy) { + this.reader.skipWhitespace(); + } + this.suggestions = builder -> BlockStateParser.suggestValues(builder, property).buildFuture(); + int valueNameStart = this.reader.getCursor(); + this.setValue(property, this.reader.readString(), valueNameStart); + if (this.legacy) { + this.suggestions = this::suggestNextProperty; + } else { + this.suggestions = this::suggestNextPropertyOrEnd; + this.reader.skipWhitespace(); + } + if (this.reader.canRead()) { + if (this.reader.peek() == ',') { + this.reader.skip(); + this.suggestions = this::suggestProperty; + } else if (!this.legacy && this.reader.peek() != ']') { + throw UNCLOSED_PROPERTY_EXCEPTION.createWithContext(this.reader); + } + } + } + if (!this.legacy) { + if (!this.reader.canRead()) { + throw UNCLOSED_PROPERTY_EXCEPTION.createWithContext(this.reader); + } + this.reader.skip(); + } + } + } + + public void parseNbt() throws CommandSyntaxException { + this.nbt = new SnbtParser(this.reader).readCompound(); + } + + private > void setValue(Property property, String valueName, int cursor) throws CommandSyntaxException { + Optional value = property.getValue(valueName); + if (!value.isPresent()) { + this.reader.setCursor(cursor); + throw INVALID_PROPERTY_EXCEPTION.createWithContext(this.reader, this.id.toString(), property.getName(), valueName); + } + this.state = this.state.set(property, value.get()); + this.properties.put(property, value.get()); + } + + public static String serialize(BlockState state) { + StringBuilder sb = new StringBuilder(Block.REGISTRY.getKey(state.getBlock()).toString()); + if (!state.properties().isEmpty()) { + boolean bl = false; + for (Map.Entry, Comparable> entry : state.values().entrySet()) { + if (bl) { + sb.append(','); + } + serializeProperty(sb, entry.getKey(), entry.getValue()); + bl = true; + } + } + return sb.toString(); + } + + @SuppressWarnings("unchecked") + private static > void serializeProperty(StringBuilder sb, Property property, Comparable value) { + sb.append(property.getName()); + sb.append('='); + sb.append(property.getName((T)value)); + } + + public CompletableFuture addSuggestions(SuggestionsBuilder builder) { + return this.suggestions.apply(builder.createOffset(this.reader.getCursor())); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ColorArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ColorArgument.java new file mode 100644 index 00000000..8def0a23 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ColorArgument.java @@ -0,0 +1,60 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.text.Formatting; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class ColorArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("red", "green"); + public static final DynamicCommandExceptionType INVALID_COLOR_EXCEPTION = new DynamicCommandExceptionType(color -> (Message)new TranslatableText("argument.color.invalid", color)); + + private ColorArgument() { + } + + public static ColorArgument color() { + return new ColorArgument(); + } + + public static Formatting getColor(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Formatting.class); + } + + @Override + public Formatting parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String name = reader.readUnquotedString(); + Formatting formatting = Formatting.byName(name); + + if (formatting == null || formatting.isModifier()) { + reader.setCursor(cursor); + throw INVALID_COLOR_EXCEPTION.createWithContext(reader, name); + } + + return formatting; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(Formatting.getNames(true, false), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinate.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinate.java new file mode 100644 index 00000000..585d34e1 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinate.java @@ -0,0 +1,98 @@ +package net.ornithemc.osl.commands.api.argument; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.text.TranslatableText; + +public class Coordinate { + + public static final SimpleCommandExceptionType NOT_DOUBLE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos.missing.double", new Object[0])); + public static final SimpleCommandExceptionType NOT_INT_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos.missing.int", new Object[0])); + + private final boolean relative; + private final double coordinate; + + public Coordinate(boolean relative, double coordinate) { + this.relative = relative; + this.coordinate = coordinate; + } + + public double get(double offset) { + if (this.relative) { + return this.coordinate + offset; + } + return this.coordinate; + } + + public static Coordinate parseDouble(StringReader reader, boolean centered) throws CommandSyntaxException { + if (reader.canRead() && reader.peek() == '^') { + throw Vec3dArgument.MIXED_TYPE_EXCEPTION.createWithContext(reader); + } + if (!reader.canRead()) { + throw NOT_DOUBLE_EXCEPTION.createWithContext(reader); + } + boolean relative = Coordinate.parseRelative(reader); + int cursor = reader.getCursor(); + double d = reader.canRead() && reader.peek() != ' ' ? reader.readDouble() : 0.0; + String string = reader.getString().substring(cursor, reader.getCursor()); + if (relative && string.isEmpty()) { + return new Coordinate(true, 0.0); + } + if (!string.contains(".") && !relative && centered) { + d += 0.5; + } + return new Coordinate(relative, d); + } + + public static Coordinate parseInt(StringReader reader) throws CommandSyntaxException { + if (reader.canRead() && reader.peek() == '^') { + throw Vec3dArgument.MIXED_TYPE_EXCEPTION.createWithContext(reader); + } + if (!reader.canRead()) { + throw NOT_INT_EXCEPTION.createWithContext(reader); + } + boolean bl = Coordinate.parseRelative(reader); + double d = reader.canRead() && reader.peek() != ' ' ? (bl ? reader.readDouble() : (double) reader.readInt()) + : 0.0; + return new Coordinate(bl, d); + } + + private static boolean parseRelative(StringReader reader) { + if (reader.peek() == '~') { + reader.skip(); + return true; + } else { + return false; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Coordinate)) { + return false; + } + Coordinate coordinate = (Coordinate) obj; + if (this.relative != coordinate.relative) { + return false; + } + return Double.compare(coordinate.coordinate, this.coordinate) == 0; + } + + @Override + public int hashCode() { + int i = this.relative ? 1 : 0; + long l = Double.doubleToLongBits(this.coordinate); + i = 31 * i + (int) (l ^ l >>> 32); + return i; + } + + public boolean isRelative() { + return this.relative; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinates.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinates.java new file mode 100644 index 00000000..80833fd8 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Coordinates.java @@ -0,0 +1,25 @@ +package net.ornithemc.osl.commands.api.argument; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public interface Coordinates { + + Vec3d getPosition(AbstractCommandSourceStack source); + + Vec2f getRotation(AbstractCommandSourceStack source); + + default BlockPos getBlockPos(AbstractCommandSourceStack source) { + return new BlockPos(this.getPosition(source)); + } + + boolean isXRelative(); + + boolean isYRelative(); + + boolean isZRelative(); + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/DimensionTypeArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/DimensionTypeArgument.java new file mode 100644 index 00000000..745d53f1 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/DimensionTypeArgument.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.text.TranslatableText; +import net.minecraft.world.dimension.DimensionType; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class DimensionTypeArgument implements ArgumentType { + + private static final Collection EXAMPLES = Stream.of(DimensionType.OVERWORLD, DimensionType.NETHER).map(dimension -> dimension.getKey()).collect(Collectors.toList()); + public static final DynamicCommandExceptionType INVALID_EXCEPTION = new DynamicCommandExceptionType(dimension -> (Message)new TranslatableText("argument.dimension.invalid", dimension)); + + public static DimensionTypeArgument dimension() { + return new DimensionTypeArgument(); + } + + public static DimensionType getDimension(CommandContext ctx, String arg) { + return ctx.getArgument(arg, DimensionType.class); + } + + @Override + public DimensionType parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String key = reader.readUnquotedString(); + DimensionType dimension = DimensionType.byKey(key); + + if (dimension == null) { + reader.setCursor(cursor); + throw INVALID_EXCEPTION.createWithContext(reader, key); + } + + return dimension; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(Stream.of(DimensionType.values()).map(DimensionType::getKey), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EnchantmentArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EnchantmentArgument.java new file mode 100644 index 00000000..bcde5630 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EnchantmentArgument.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class EnchantmentArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("unbreaking", "silk_touch"); + public static final DynamicCommandExceptionType UNKNOWN_ENCHANTMENT_EXCEPTION = new DynamicCommandExceptionType(enchantment -> (Message)new TranslatableText("enchantment.unknown", enchantment)); + + public static EnchantmentArgument enchantment() { + return new EnchantmentArgument(); + } + + public static Enchantment getEnchantment(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Enchantment.class); + } + + @Override + public Enchantment parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + Identifier key = IdentifierParser.parse(reader); + Enchantment enchantment = Enchantment.REGISTRY.get(key); + + if (enchantment == null) { + reader.setCursor(cursor); + throw UNKNOWN_ENCHANTMENT_EXCEPTION.createWithContext(reader, key); + } + + return enchantment; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestResource(Enchantment.REGISTRY.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntityArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntityArgument.java new file mode 100644 index 00000000..ee2dd734 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntityArgument.java @@ -0,0 +1,164 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.commands.api.serdes.ArgumentSerializer; + +public class EntityArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("Player", "0123", "@e", "@e[type=foo]", "dd12be42-52a9-4a91-a8a1-11c01849e498"); + public static final SimpleCommandExceptionType TOO_MANY_ENTITIES_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.toomany")); + public static final SimpleCommandExceptionType TOO_MANY_PLAYERS_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.player.toomany")); + public static final SimpleCommandExceptionType NOT_PLAYER_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.player.entities")); + public static final SimpleCommandExceptionType ENTITY_NOT_FOUND_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.notfound.entity")); + public static final SimpleCommandExceptionType PLAYER_NOT_FOUND_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.notfound.player")); + public static final SimpleCommandExceptionType SELECTOR_NOT_ALLOWED_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.selector.not_allowed")); + + private final boolean single; + private final boolean players; + + protected EntityArgument(boolean single, boolean players) { + this.single = single; + this.players = players; + } + + public static EntityArgument entity() { + return new EntityArgument(true, false); + } + + public static Entity getEntity(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, EntitySelector.class).findSingleEntity(ctx.getSource()); + } + + public static EntityArgument entities() { + return new EntityArgument(false, false); + } + + public static Collection getEntities(CommandContext> ctx, String arg) throws CommandSyntaxException { + Collection collection = EntityArgument.getOptionalEntities(ctx, arg); + if (collection.isEmpty()) { + throw ENTITY_NOT_FOUND_EXCEPTION.create(); + } + return collection; + } + + public static Collection getOptionalEntities(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, EntitySelector.class).findEntities(ctx.getSource()); + } + + public static Collection getOptionalPlayers(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, EntitySelector.class).findPlayers(ctx.getSource()); + } + + public static EntityArgument player() { + return new EntityArgument(true, true); + } + + public static PlayerEntity getPlayer(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, EntitySelector.class).findSinglePlayer(ctx.getSource()); + } + + public static EntityArgument players() { + return new EntityArgument(false, true); + } + + public static Collection getPlayers(CommandContext> ctx, String arg) throws CommandSyntaxException { + List players = ctx.getArgument(arg, EntitySelector.class).findPlayers(ctx.getSource()); + if (players.isEmpty()) { + throw PLAYER_NOT_FOUND_EXCEPTION.create(); + } + return players; + } + + @Override + public EntitySelector parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + EntitySelectorParser parser = new EntitySelectorParser(reader); + EntitySelector selector = parser.parse(); + + if (selector.getMax() > 1 && this.single) { + reader.setCursor(cursor); + + if (this.players) { + throw TOO_MANY_PLAYERS_EXCEPTION.createWithContext(reader); + } else { + throw TOO_MANY_ENTITIES_EXCEPTION.createWithContext(reader); + } + } + if (selector.hasNonPlayers() && this.players && !selector.hasSelf()) { + reader.setCursor(cursor); + throw NOT_PLAYER_EXCEPTION.createWithContext(reader); + } + + return selector; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof SuggestionProvider) { + StringReader reader = new StringReader(builder.getInput()); + reader.setCursor(builder.getStart()); + SuggestionProvider suggestionProvider = (SuggestionProvider)ctx.getSource(); + EntitySelectorParser parser = new EntitySelectorParser(reader, suggestionProvider.hasPermissions(2)); + + try { + parser.parse(); + } catch (CommandSyntaxException e) { + } + + return parser.addSuggestions(builder, nameBuilder -> { + Collection suggestions = suggestionProvider.getPlayerNames(); + if (!this.players) { + suggestions.addAll(suggestionProvider.getSelectedEntities()); + } + SuggestionProvider.suggestMatching(suggestions, nameBuilder); + }); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public static class Serializer implements ArgumentSerializer { + + @Override + public void serialize(EntityArgument arg, PacketByteBuf buffer) { + byte flags = 0; + if (arg.single) { + flags = (byte)(flags | 1); + } + if (arg.players) { + flags = (byte)(flags | 2); + } + buffer.writeByte(flags); + } + + @Override + public EntityArgument deserialize(PacketByteBuf buffer) { + byte flags = buffer.readByte(); + return new EntityArgument((flags & 1) != 0, (flags & 2) != 0); + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelector.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelector.java new file mode 100644 index 00000000..2f9d43aa --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelector.java @@ -0,0 +1,287 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Formatting; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; + +public class EntitySelector { + + private final int max; + private final boolean allowNonPlayers; + private final boolean restrictOtherWorlds; + private final Predicate predicate; + private final Float minDistance; + private final Float maxDistance; + private final Function position; + private final Box bounds; + private final BiConsumer> order; + private final boolean allowSelf; + private final String name; + private final UUID uuid; + private final Class type; + private final boolean selector; + + public EntitySelector(int max, boolean allowNonPlayers, boolean allowFromOtherWorlds, Predicate predicate, Float minDistance, Float maxDistance, Function position, Box bounds, BiConsumer> order, boolean allowSelf, String name, UUID uuid, Class type, boolean selector) { + this.max = max; + this.allowNonPlayers = allowNonPlayers; + this.restrictOtherWorlds = allowFromOtherWorlds; + this.predicate = predicate; + this.minDistance = minDistance; + this.maxDistance = maxDistance; + this.position = position; + this.bounds = bounds; + this.order = order; + this.allowSelf = allowSelf; + this.name = name; + this.uuid = uuid; + this.type = type; + this.selector = selector; + } + + public int getMax() { + return this.max; + } + + public boolean hasNonPlayers() { + return this.allowNonPlayers; + } + + public boolean hasSelf() { + return this.allowSelf; + } + + public boolean isRestrictOtherWorlds() { + return this.restrictOtherWorlds; + } + + private void checkPermissions(AbstractCommandSourceStack source) throws CommandSyntaxException { + if (this.selector && !source.hasPermissions(2)) { + throw EntityArgument.SELECTOR_NOT_ALLOWED_EXCEPTION.create(); + } + } + + public Entity findSingleEntity(AbstractCommandSourceStack source) throws CommandSyntaxException { + this.checkPermissions(source); + List entities = this.findEntities(source); + if (entities.isEmpty()) { + throw EntityArgument.ENTITY_NOT_FOUND_EXCEPTION.create(); + } + if (entities.size() > 1) { + throw EntityArgument.TOO_MANY_ENTITIES_EXCEPTION.create(); + } + return entities.get(0); + } + + public List findEntities(AbstractCommandSourceStack source) throws CommandSyntaxException { + this.checkPermissions(source); + if (!this.allowNonPlayers) { + return this.findPlayers(source); + } + if (this.name != null) { + if (source instanceof CommandSourceStack) { + CommandSourceStack serverSource = (CommandSourceStack)source; + PlayerEntity player = serverSource.getServer().getPlayerManager().get(this.name); + if (player != null) { + return Arrays.asList(player); + } + } + if (source instanceof ClientCommandSourceStack) { + ClientCommandSourceStack clientSource = (ClientCommandSourceStack)source; + for (PlayerEntity player : clientSource.getWorld().players) { + if (this.name.equals(player.getName())) { + return Arrays.asList(player); + } + } + } + return Collections.emptyList(); + } + if (this.uuid != null) { + if (source instanceof CommandSourceStack) { + CommandSourceStack serverSource = (CommandSourceStack)source; + for (ServerWorld world : serverSource.getServer().worlds) { + Entity entity = world.getEntity(this.uuid); + if (entity != null) { + return Arrays.asList(entity); + } + } + } + if (source instanceof ClientCommandSourceStack) { + ClientCommandSourceStack clientSource = (ClientCommandSourceStack)source; + for (Entity entity : clientSource.getWorld().getEntities()) { + if (this.uuid.equals(entity.getUuid())) { + return Arrays.asList(entity); + } + } + } + return Collections.emptyList(); + } + Vec3d vec3d = this.position.apply(source.getPos()); + Predicate predicate = this.getPredicate(vec3d); + if (this.allowSelf) { + if (source.getEntity() != null && predicate.test(source.getEntity())) { + return Arrays.asList(source.getEntity()); + } + return Collections.emptyList(); + } + ArrayList list = new ArrayList<>(); + if (this.isRestrictOtherWorlds() || !(source instanceof CommandSourceStack)) { + this.collectEntities(list, source.getWorld(), vec3d, predicate); + } else { + for (ServerWorld world : ((CommandSourceStack)source).getServer().worlds) { + this.collectEntities(list, world, vec3d, predicate); + } + } + return this.sortAndLimit(vec3d, list); + } + + private void collectEntities(List entities, World world, Vec3d pos, Predicate filter) { + if (this.bounds != null) { + entities.addAll(world.getEntities(this.type, this.bounds.move(pos), filter::test)); + } else { + entities.addAll(world.getEntities(this.type, filter::test)); + } + } + + public PlayerEntity findSinglePlayer(AbstractCommandSourceStack source) throws CommandSyntaxException { + this.checkPermissions(source); + List list = this.findPlayers(source); + if (list.size() != 1) { + throw EntityArgument.PLAYER_NOT_FOUND_EXCEPTION.create(); + } + return list.get(0); + } + + public List findPlayers(AbstractCommandSourceStack source) throws CommandSyntaxException { + this.checkPermissions(source); + if (this.name != null) { + if (source instanceof CommandSourceStack) { + CommandSourceStack serverSource = (CommandSourceStack)source; + PlayerEntity player = serverSource.getServer().getPlayerManager().get(this.name); + if (player != null) { + return Arrays.asList(player); + } + } + if (source instanceof ClientCommandSourceStack) { + ClientCommandSourceStack clientSource = (ClientCommandSourceStack)source; + for (PlayerEntity player : clientSource.getWorld().players) { + if (this.name.equals(player.getName())) { + return Arrays.asList(player); + } + } + } + return Collections.emptyList(); + } + if (this.uuid != null) { + if (source instanceof CommandSourceStack) { + CommandSourceStack serverSource = (CommandSourceStack)source; + PlayerEntity player = serverSource.getServer().getPlayerManager().get(this.uuid); + if (player != null) { + return Arrays.asList(player); + } + } + if (source instanceof ClientCommandSourceStack) { + ClientCommandSourceStack clientSource = (ClientCommandSourceStack)source; + for (PlayerEntity player : clientSource.getWorld().players) { + if (this.uuid.equals(player.getUuid())) { + return Arrays.asList(player); + } + } + } + return Collections.emptyList(); + } + Vec3d pos = this.position.apply(source.getPos()); + Predicate predicate = this.getPredicate(pos); + if (this.allowSelf) { + if (source.getEntity() instanceof PlayerEntity && predicate.test(source.getEntity())) { + return Arrays.asList((PlayerEntity)source.getEntity()); + } + return Collections.emptyList(); + } + List players; + if (this.isRestrictOtherWorlds()) { + players = source.getWorld().getPlayers(PlayerEntity.class, predicate::test); + } else { + players = new ArrayList<>(); + if (source instanceof CommandSourceStack) { + CommandSourceStack serverSource = (CommandSourceStack)source; + for (PlayerEntity player : serverSource.getServer().getPlayerManager().getAll()) { + if (predicate.test(player)) { + players.add(player); + } + } + } + if (source instanceof ClientCommandSourceStack) { + ClientCommandSourceStack clientSource = (ClientCommandSourceStack)source; + for (PlayerEntity player : clientSource.getWorld().players) { + if (predicate.test(player)) { + players.add(player); + } + } + } + } + return this.sortAndLimit(pos, players); + } + + private Predicate getPredicate(Vec3d pos) { + Predicate predicate = this.predicate; + if (this.bounds != null) { + Box bounds = this.bounds.move(pos); + predicate = predicate.and(entity -> bounds.intersects(entity.getShape())); + } + if (this.minDistance != null || this.maxDistance != null) { + predicate = predicate.and(entity -> { + double distance = pos.distanceTo(entity.getSourcePos()); + return (this.minDistance == null || distance >= this.minDistance) && (this.maxDistance == null || distance <= this.maxDistance); + }); + } + return predicate; + } + + private List sortAndLimit(Vec3d pos, List entities) { + if (entities.size() > 1) { + this.order.accept(pos, entities); + } + return entities.subList(0, Math.min(this.max, entities.size())); + } + + public static Text joinNames(List entities) { + if (entities.isEmpty()) { + return new LiteralText(""); + } + if (entities.size() == 1) { + return entities.get(0).getDisplayName(); + } + LiteralText text = new LiteralText(""); + boolean addSeparator = false; + for (int i = 0; i < entities.size(); i++) { + if (addSeparator) { + text.append(new LiteralText(", ").setStyle(new Style().setColor(Formatting.GRAY))); + } + text.append(entities.get(i).getDisplayName()); + addSeparator = true; + } + return text; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorOptions.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorOptions.java new file mode 100644 index 00000000..b7607af6 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorOptions.java @@ -0,0 +1,344 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.function.Predicate; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.Entities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.LivingEntity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.resource.Identifier; +import net.minecraft.scoreboard.team.AbstractTeam; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.GameMode; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class EntitySelectorOptions { + + private static final Map OPTIONS = new HashMap<>(); + public static final DynamicCommandExceptionType UNKNOWN_EXCEPTION = new DynamicCommandExceptionType(option -> (Message)new TranslatableText("argument.entity.options.unknown", option)); + public static final DynamicCommandExceptionType NOT_APPLICABLE_EXCEPTION = new DynamicCommandExceptionType(option -> (Message)new TranslatableText("argument.entity.options.inapplicable", option)); + public static final SimpleCommandExceptionType NEGATIVE_DISTANCE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.options.distance.negative")); + public static final SimpleCommandExceptionType NEGATIVE_XP_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.options.level.negative")); + public static final SimpleCommandExceptionType LIMIT_TOO_SMALL_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.entity.options.limit.toosmall")); + public static final DynamicCommandExceptionType UNKNOWN_ORDER_EXCEPTION = new DynamicCommandExceptionType(order -> (Message)new TranslatableText("argument.entity.options.sort.irreversible", order)); + public static final DynamicCommandExceptionType INVALID_GAME_MODE_EXCEPTION = new DynamicCommandExceptionType(gameMode -> (Message)new TranslatableText("argument.entity.options.mode.invalid", gameMode)); + public static final DynamicCommandExceptionType INVALID_ENTITY_TYPE_EXCEPTION = new DynamicCommandExceptionType(type -> (Message)new TranslatableText("argument.entity.options.type.invalid", type)); + + private static void register(String name, Modifier modifier, Predicate predicate, Text description) { + OPTIONS.put(name, new Option(modifier, predicate, description)); + } + + public static void init() { + if (!OPTIONS.isEmpty()) { + return; + } + EntitySelectorOptions.register("name", parser -> { + int cursor = parser.getReader().getCursor(); + boolean invert = parser.shouldInvertValue(); + String name = parser.getReader().readString(); + if (parser.hasNotName() && !invert) { + parser.getReader().setCursor(cursor); + throw NOT_APPLICABLE_EXCEPTION.createWithContext(parser.getReader(), "name"); + } + if (invert) { + parser.setHasNotName(true); + } else { + parser.setHasName(true); + } + parser.addPredicate(entity -> entity.getName().equals(name) != invert); + }, parser -> !parser.hasName(), new TranslatableText("argument.entity.options.name.description")); + EntitySelectorOptions.register("rm", parser -> { + int cursor = parser.getReader().getCursor(); + float distance = parser.getReader().readFloat(); + if (distance < 0.0F) { + parser.getReader().setCursor(cursor); + throw NEGATIVE_DISTANCE_EXCEPTION.createWithContext(parser.getReader()); + } + if (parser.getMaxDistance() != null && distance > parser.getMaxDistance()) { + // TODO + } + parser.setRestrictOtherWorlds(); + parser.setMinDistance(distance); + }, parser -> parser.getMinDistance() != null, new TranslatableText("argument.entity.options.distance.min.description")); + EntitySelectorOptions.register("r", parser -> { + int cursor = parser.getReader().getCursor(); + float distance = parser.getReader().readFloat(); + if (distance < 0.0F) { + parser.getReader().setCursor(cursor); + throw NEGATIVE_DISTANCE_EXCEPTION.createWithContext(parser.getReader()); + } + if (parser.getMinDistance() != null && distance < parser.getMinDistance()) { + // TODO + } + parser.setRestrictOtherWorlds(); + parser.setMaxDistance(distance); + }, parser -> parser.getMaxDistance() != null, new TranslatableText("argument.entity.options.distance.max.description")); + EntitySelectorOptions.register("lm", parser -> { + int cursor = parser.getReader().getCursor(); + int xp = parser.getReader().readInt(); + if (xp < 0) { + parser.getReader().setCursor(cursor); + throw NEGATIVE_XP_EXCEPTION.createWithContext(parser.getReader()); + } + if (parser.getMaxXp() != null && xp > parser.getMaxXp()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMinXp(xp); + }, parser -> parser.getMinXp() != null, new TranslatableText("argument.entity.options.level.min.description")); + EntitySelectorOptions.register("l", parser -> { + int cursor = parser.getReader().getCursor(); + int xp = parser.getReader().readInt(); + if (xp < 0) { + parser.getReader().setCursor(cursor); + throw NEGATIVE_XP_EXCEPTION.createWithContext(parser.getReader()); + } + if (parser.getMinXp() != null && xp < parser.getMinXp()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMaxXp(xp); + }, parser -> parser.getMinXp() != null, new TranslatableText("argument.entity.options.level.max.description")); + EntitySelectorOptions.register("x", parser -> { + parser.setRestrictOtherWorlds(); + parser.setX(parser.getReader().readDouble()); + }, parser -> parser.getX() == null, new TranslatableText("argument.entity.options.x.description")); + EntitySelectorOptions.register("y", parser -> { + parser.setRestrictOtherWorlds(); + parser.setY(parser.getReader().readDouble()); + }, parser -> parser.getY() == null, new TranslatableText("argument.entity.options.y.description")); + EntitySelectorOptions.register("z", parser -> { + parser.setRestrictOtherWorlds(); + parser.setZ(parser.getReader().readDouble()); + }, parser -> parser.getZ() == null, new TranslatableText("argument.entity.options.z.description")); + EntitySelectorOptions.register("dx", parser -> { + parser.setRestrictOtherWorlds(); + parser.setDx(parser.getReader().readDouble()); + }, parser -> parser.getDx() == null, new TranslatableText("argument.entity.options.dx.description")); + EntitySelectorOptions.register("dy", parser -> { + parser.setRestrictOtherWorlds(); + parser.setDy(parser.getReader().readDouble()); + }, parser -> parser.getDy() == null, new TranslatableText("argument.entity.options.dy.description")); + EntitySelectorOptions.register("dz", parser -> { + parser.setRestrictOtherWorlds(); + parser.setDz(parser.getReader().readDouble()); + }, parser -> parser.getDz() == null, new TranslatableText("argument.entity.options.dz.description")); + EntitySelectorOptions.register("rxm", parser -> { + int cursor = parser.getReader().getCursor(); + int pitch = parser.getReader().readInt(); + pitch = (int)MathHelper.wrapDegrees(pitch); + if (parser.getMaxPitch() != null && pitch > parser.getMaxPitch()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMinPitch(pitch); + }, parser -> parser.getMinPitch() != null, new TranslatableText("argument.entity.options.x_rotation.min.description")); + EntitySelectorOptions.register("rx", parser -> { + int cursor = parser.getReader().getCursor(); + int pitch = parser.getReader().readInt(); + pitch = (int)MathHelper.wrapDegrees(pitch); + if (parser.getMinPitch() != null && pitch < parser.getMinPitch()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMaxPitch(pitch); + }, parser -> parser.getMaxPitch() != null, new TranslatableText("argument.entity.options.x_rotation.max.description")); + EntitySelectorOptions.register("rym", parser -> { + int cursor = parser.getReader().getCursor(); + int yaw = parser.getReader().readInt(); + yaw = (int)MathHelper.wrapDegrees(yaw); + if (parser.getMaxYaw() != null && yaw > parser.getMaxYaw()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMinYaw(yaw); + }, parser -> parser.getMinYaw() != null, new TranslatableText("argument.entity.options.y_rotation.min.description")); + EntitySelectorOptions.register("ry", parser -> { + int cursor = parser.getReader().getCursor(); + int yaw = parser.getReader().readInt(); + yaw = (int)MathHelper.wrapDegrees(yaw); + if (parser.getMinYaw() != null && yaw < parser.getMinYaw()) { + // TODO + } + parser.setAllowNonPlayers(false); + parser.setMaxYaw(yaw); + }, parser -> parser.getMaxYaw() != null, new TranslatableText("argument.entity.options.y_rotation.max.description")); + EntitySelectorOptions.register("c", parser -> { + int cursor = parser.getReader().getCursor(); + int limit = parser.getReader().readInt(); + if (limit < 1) { + parser.getReader().setCursor(cursor); + throw LIMIT_TOO_SMALL_EXCEPTION.createWithContext(parser.getReader()); + } + parser.setMax(limit); + parser.setHasLimit(true); + }, parser -> !parser.hasSelf() && !parser.hasLimit(), new TranslatableText("argument.entity.options.limit.description")); + EntitySelectorOptions.register("m", parser -> { + parser.setSuggestions((builder, nameSuggestions) -> { + String string = builder.getRemaining().toLowerCase(Locale.ROOT); + boolean invert = !parser.hasNotGameMode(); + boolean bl2 = true; + if (!string.isEmpty()) { + if (string.charAt(0) == '!') { + invert = false; + string = string.substring(1); + } else { + bl2 = false; + } + } + for (GameMode gameMode : GameMode.values()) { + if (gameMode == GameMode.NOT_SET || !gameMode.getKey().toLowerCase(Locale.ROOT).startsWith(string)) + continue; + if (bl2) { + builder.suggest('!' + gameMode.getKey()); + } + if (invert) { + builder.suggest(gameMode.getKey()); + } + } + return builder.buildFuture(); + }); + int cursor = parser.getReader().getCursor(); + boolean invert = parser.shouldInvertValue(); + if (parser.hasNotGameMode() && !invert) { + parser.getReader().setCursor(cursor); + throw NOT_APPLICABLE_EXCEPTION.createWithContext(parser.getReader(), "gamemode"); + } + String key = parser.getReader().readUnquotedString(); + GameMode gameMode = GameMode.byKeyOrDefault(key, GameMode.NOT_SET); + if (gameMode == GameMode.NOT_SET) { + parser.getReader().setCursor(cursor); + throw INVALID_GAME_MODE_EXCEPTION.createWithContext(parser.getReader(), key); + } + parser.setAllowNonPlayers(false); + parser.addPredicate(entity -> { + if (!(entity instanceof ServerPlayerEntity)) { + return false; + } + GameMode gameMode2 = ((ServerPlayerEntity) entity).interactionManager.getGameMode(); + return invert ? gameMode2 != gameMode : gameMode2 == gameMode; + }); + if (invert) { + parser.setHasNotGameMode(true); + } else { + parser.setHasGameMode(true); + } + }, parser -> !parser.hasGameMode(), new TranslatableText("argument.entity.options.gamemode.description")); + EntitySelectorOptions.register("team", parser -> { + boolean invert = parser.shouldInvertValue(); + String string = parser.getReader().readUnquotedString(); + parser.addPredicate(entity -> { + if (!(entity instanceof LivingEntity)) { + return false; + } + AbstractTeam abstractTeam = entity.getTeam(); + String string2 = abstractTeam == null ? "" : abstractTeam.getName(); + return string2.equals(string) != invert; + }); + if (invert) { + parser.setHasNotTeam(true); + } else { + parser.setHasTeam(true); + } + }, parser -> !parser.hasTeam(), new TranslatableText("argument.entity.options.team.description")); + EntitySelectorOptions.register("type", parser -> { + parser.setSuggestions((builder, nameSuggestions) -> { + SuggestionProvider.suggestResource(Entities.getIds(), builder, String.valueOf('!')); + if (!parser.hasNotType()) { + SuggestionProvider.suggestResource(Entities.getIds(), builder); + } + return builder.buildFuture(); + }); + int cursor = parser.getReader().getCursor(); + boolean invert = parser.shouldInvertValue(); + if (parser.hasNotType() && !invert) { + parser.getReader().setCursor(cursor); + throw NOT_APPLICABLE_EXCEPTION.createWithContext(parser.getReader(), "type"); + } + Identifier id = IdentifierParser.parse(parser.getReader()); + if (!Entities.exists(id)) { + parser.getReader().setCursor(cursor); + throw INVALID_ENTITY_TYPE_EXCEPTION.createWithContext(parser.getReader(), id.toString()); + } + Class type = Entities.REGISTRY.get(id); + if (PlayerEntity.class.isAssignableFrom(type) && !invert) { + parser.setAllowNonPlayers(false); + } + parser.addPredicate(entity -> Entities.is(entity, id) != invert); + if (invert) { + parser.setHasNotType(); + } else { + parser.setType(Entities.REGISTRY.get(id)); + } + }, parser -> !parser.hasType(), new TranslatableText("argument.entity.options.type.description")); + EntitySelectorOptions.register("nbt", parser -> { + boolean invert = parser.shouldInvertValue(); + NbtCompound nbt = new SnbtParser(parser.getReader()).readCompound(); + parser.addPredicate(entity -> { + ItemStack stack; + NbtCompound entityNbt = entity.writeEntityNbt(new NbtCompound()); + if (entity instanceof PlayerEntity + && !(stack = ((PlayerEntity)entity).inventory.getMainHandStack()).isEmpty()) { + entityNbt.put("SelectedItem", stack.writeNbt(new NbtCompound())); + } + return NbtUtils.matches(nbt, entityNbt, true) != invert; + }); + }, parser -> true, new TranslatableText("argument.entity.options.nbt.description")); + } + + public static Modifier get(EntitySelectorParser parser, String name, int cursor) throws CommandSyntaxException { + Option option = OPTIONS.get(name); + if (option != null) { + if (option.predicate.test(parser)) { + return option.modifier; + } + throw NOT_APPLICABLE_EXCEPTION.createWithContext(parser.getReader(), name); + } + parser.getReader().setCursor(cursor); + throw UNKNOWN_EXCEPTION.createWithContext(parser.getReader(), name); + } + + public static void suggest(EntitySelectorParser parser, SuggestionsBuilder builder) { + String string = builder.getRemaining().toLowerCase(Locale.ROOT); + for (Map.Entry entry : OPTIONS.entrySet()) { + if (!entry.getValue().predicate.test(parser) || !entry.getKey().toLowerCase(Locale.ROOT).startsWith(string)) + continue; + builder.suggest(entry.getKey() + '=', (Message) entry.getValue().description); + } + } + + public static class Option { + + public final Modifier modifier; + public final Predicate predicate; + public final Text description; + + public Option(Modifier modifier, Predicate predicate, Text description) { + this.modifier = modifier; + this.predicate = predicate; + this.description = description; + } + } + + public interface Modifier { + + void handle(EntitySelectorParser var1) throws CommandSyntaxException; + + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorParser.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorParser.java new file mode 100644 index 00000000..60241d67 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/EntitySelectorParser.java @@ -0,0 +1,580 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.ToDoubleFunction; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class EntitySelectorParser { + + public static final SimpleCommandExceptionType INVALID_EXCEPTION = new SimpleCommandExceptionType((Message) new TranslatableText("argument.entity.invalid", new Object[0])); + public static final DynamicCommandExceptionType UNKNOWN_SELECTOR_EXCEPTION = new DynamicCommandExceptionType(selector -> (Message) new TranslatableText("argument.entity.selector.unknown", selector)); + public static final SimpleCommandExceptionType SELECTOR_NOT_ALLOWED_EXCEPTION = new SimpleCommandExceptionType((Message) new TranslatableText("argument.entity.selector.not_allowed", new Object[0])); + public static final SimpleCommandExceptionType SELECTOR_MISSING_EXCEPTION = new SimpleCommandExceptionType((Message) new TranslatableText("argument.entity.selector.missing", new Object[0])); + public static final SimpleCommandExceptionType UNTERMINATED_OPTIONS_EXCEPTION = new SimpleCommandExceptionType((Message) new TranslatableText("argument.entity.options.unterminated", new Object[0])); + public static final DynamicCommandExceptionType OPTION_WITHOUT_VALUE_EXCEPTION = new DynamicCommandExceptionType(option -> (Message) new TranslatableText("argument.entity.options.valueless", option)); + public static final BiConsumer> ORDER_ARBITRARY = (pos, entities) -> { }; + public static final BiConsumer> ORDER_NEAREST = (pos, entities) -> entities.sort((entity1, entity2) -> Double.compare(pos.squaredDistanceTo(entity1.x, entity1.y, entity1.z), pos.squaredDistanceTo(entity2.x, entity2.y, entity2.z))); + public static final BiConsumer> ORDER_FURTHEST = (pos, entities) -> entities.sort((entity1, entity2) -> Double.compare(pos.squaredDistanceTo(entity2.x, entity2.y, entity2.z), pos.squaredDistanceTo(entity1.x, entity1.y, entity1.z))); + public static final BiConsumer> ORDER_RANDOM = (pos, entities) -> Collections.shuffle(entities); + public static final BiFunction, CompletableFuture> NO_SUGGESTIONS = (builder, nameSuggestions) -> builder.buildFuture(); + + private final StringReader reader; + private final boolean allowSelectors; + private int max; + private boolean allowNonPlayers; + private boolean restrictOtherWorlds; + private Float minDistance; + private Float maxDistance; + private Integer minXp; + private Integer maxXp; + private Double x; + private Double y; + private Double z; + private Double dx; + private Double dy; + private Double dz; + private Integer minPitch; + private Integer maxPitch; + private Integer minYaw; + private Integer maxYaw; + private Predicate predicate = entity -> true; + private BiConsumer> order = ORDER_ARBITRARY; + private boolean allowSelf; + private String name; + private int cursorStart; + private UUID uuid; + private BiFunction, CompletableFuture> suggestions = NO_SUGGESTIONS; + private boolean hasName; + private boolean hasNotName; + private boolean hasLimit; + private boolean hasOrder; + private boolean hasGameMode; + private boolean hasNotGameMode; + private boolean hasTeam; + private boolean hasNotTeam; + private Class type; + private boolean hasNotType; + private boolean hasScores; + private boolean hasAdvancements; + private boolean selector; + + public EntitySelectorParser(StringReader reader) { + this(reader, true); + } + + public EntitySelectorParser(StringReader reader, boolean allowSelectors) { + this.reader = reader; + this.allowSelectors = allowSelectors; + } + + public EntitySelector getSelector() { + Box box; + if (this.dx != null || this.dy != null || this.dz != null) { + box = this.getBounds(this.dx == null ? 0.0 : this.dx, this.dy == null ? 0.0 : this.dy, + this.dz == null ? 0.0 : this.dz); + } else if (this.maxDistance != null) { + float f = this.maxDistance.floatValue(); + box = new Box(-f, -f, -f, f + 1.0f, f + 1.0f, f + 1.0f); + } else { + box = null; + } + Function function = this.x == null && this.y == null && this.z == null ? pos -> pos + : pos -> new Vec3d(this.x == null ? pos.x : this.x, this.y == null ? pos.y : this.y, + this.z == null ? pos.z : this.z); + return new EntitySelector(this.max, this.allowNonPlayers, this.restrictOtherWorlds, this.predicate, + this.minDistance, this.maxDistance, function, box, this.order, this.allowSelf, this.name, this.uuid, + this.type == null ? Entity.class : this.type, this.selector); + } + + private Box getBounds(double dx, double dy, double dz) { + boolean bl = dx < 0.0; + boolean bl2 = dy < 0.0; + boolean bl3 = dz < 0.0; + double d = bl ? dx : 0.0; + double e = bl2 ? dy : 0.0; + double f = bl3 ? dz : 0.0; + double g = (bl ? 0.0 : dx) + 1.0; + double h = (bl2 ? 0.0 : dy) + 1.0; + double i = (bl3 ? 0.0 : dz) + 1.0; + return new Box(d, e, f, g, h, i); + } + + private void buildPredicate() { + if (this.minPitch != null || this.maxPitch != null) { + this.predicate = this.predicate.and(this.buildRotationPredicate(this.minPitch, this.maxPitch, entity -> entity.pitch)); + } + if (this.minYaw != null || this.maxYaw != null) { + this.predicate = this.predicate.and(this.buildRotationPredicate(this.minYaw, this.maxYaw, entity -> entity.yaw)); + } + if (this.minXp != null || this.maxXp != null) { + this.predicate = this.predicate.and(entity -> { + if (entity instanceof PlayerEntity) { + int xp = ((PlayerEntity)entity).xpLevel; + return (this.minXp == null || xp >= this.minXp) && (this.maxXp == null || xp <= this.maxXp); + } + return false; + }); + } + } + + private Predicate buildRotationPredicate(Integer min, Integer max, ToDoubleFunction getter) { + double d = MathHelper.wrapDegrees(min == null ? 0.0F : min.floatValue()); + double e = MathHelper.wrapDegrees(max == null ? 359.0F : max.floatValue()); + return entity -> { + double f = MathHelper.wrapDegrees(getter.applyAsDouble(entity)); + if (d > e) { + return f >= d || f <= e; + } + return f >= d && f <= e; + }; + } + + protected void parseSelector() throws CommandSyntaxException { + this.selector = true; + this.suggestions = this::suggestSelector; + if (!this.reader.canRead()) { + throw SELECTOR_MISSING_EXCEPTION.createWithContext(this.reader); + } + int i = this.reader.getCursor(); + char c = this.reader.read(); + if (c == 'p') { + this.max = 1; + this.allowNonPlayers = false; + this.order = ORDER_NEAREST; + this.setType(ServerPlayerEntity.class); + } else if (c == 'a') { + this.max = Integer.MAX_VALUE; + this.allowNonPlayers = false; + this.order = ORDER_ARBITRARY; + this.setType(ServerPlayerEntity.class); + } else if (c == 'r') { + this.max = 1; + this.allowNonPlayers = false; + this.order = ORDER_RANDOM; + this.setType(ServerPlayerEntity.class); + } else if (c == 's') { + this.max = 1; + this.allowNonPlayers = true; + this.allowSelf = true; + } else if (c == 'e') { + this.max = Integer.MAX_VALUE; + this.allowNonPlayers = true; + this.order = ORDER_ARBITRARY; + this.predicate = Entity::isAlive; + } else { + this.reader.setCursor(i); + throw UNKNOWN_SELECTOR_EXCEPTION.createWithContext(this.reader, '@' + String.valueOf(c)); + } + this.suggestions = this::suggestOptionsStart; + if (this.reader.canRead() && this.reader.peek() == '[') { + this.reader.skip(); + this.suggestions = this::suggestOptionsOrEnd; + this.parseOptions(); + } + } + + protected void parseNameOrUuid() throws CommandSyntaxException { + if (this.reader.canRead()) { + this.suggestions = this::suggestName; + } + int i = this.reader.getCursor(); + String string = this.reader.readString(); + try { + this.uuid = UUID.fromString(string); + this.allowNonPlayers = true; + } catch (IllegalArgumentException illegalArgumentException) { + if (string.isEmpty() || string.length() > 16) { + this.reader.setCursor(i); + throw INVALID_EXCEPTION.createWithContext(this.reader); + } + this.allowNonPlayers = false; + this.name = string; + } + this.max = 1; + } + + protected void parseOptions() throws CommandSyntaxException { + this.suggestions = this::suggestOptions; + this.reader.skipWhitespace(); + while (this.reader.canRead() && this.reader.peek() != ']') { + this.reader.skipWhitespace(); + int i = this.reader.getCursor(); + String string = this.reader.readString(); + EntitySelectorOptions.Modifier modifier = EntitySelectorOptions.get(this, string, i); + this.reader.skipWhitespace(); + if (!this.reader.canRead() || this.reader.peek() != '=') { + this.reader.setCursor(i); + throw OPTION_WITHOUT_VALUE_EXCEPTION.createWithContext(this.reader, string); + } + this.reader.skip(); + this.reader.skipWhitespace(); + this.suggestions = NO_SUGGESTIONS; + modifier.handle(this); + this.reader.skipWhitespace(); + this.suggestions = this::suggestNextOptionOrEnd; + if (!this.reader.canRead()) + continue; + if (this.reader.peek() == ',') { + this.reader.skip(); + this.suggestions = this::suggestOptions; + continue; + } + if (this.reader.peek() == ']') + break; + throw UNTERMINATED_OPTIONS_EXCEPTION.createWithContext(this.reader); + } + if (!this.reader.canRead()) { + throw UNTERMINATED_OPTIONS_EXCEPTION.createWithContext(this.reader); + } + this.reader.skip(); + this.suggestions = NO_SUGGESTIONS; + } + + public boolean shouldInvertValue() { + this.reader.skipWhitespace(); + if (this.reader.canRead() && this.reader.peek() == '!') { + this.reader.skip(); + this.reader.skipWhitespace(); + return true; + } + return false; + } + + public StringReader getReader() { + return this.reader; + } + + public void addPredicate(Predicate predicate) { + this.predicate = this.predicate.and(predicate); + } + + public void setRestrictOtherWorlds() { + this.restrictOtherWorlds = true; + } + + public Float getMinDistance() { + return this.minDistance; + } + + public void setMinDistance(Float distance) { + this.minDistance = distance; + } + + public Float getMaxDistance() { + return this.maxDistance; + } + + public void setMaxDistance(Float distance) { + this.maxDistance = distance; + } + + public Integer getMinXp() { + return this.minXp; + } + + public void setMinXp(Integer xp) { + this.minXp = xp; + } + + public Integer getMaxXp() { + return this.maxXp; + } + + public void setMaxXp(Integer xp) { + this.maxXp = xp; + } + + public Integer getMinPitch() { + return this.minPitch; + } + + public void setMinPitch(Integer pitch) { + this.minPitch = pitch; + } + + public Integer getMaxPitch() { + return this.maxPitch; + } + + public void setMaxPitch(Integer pitch) { + this.maxPitch = pitch; + } + + public Integer getMinYaw() { + return this.minYaw; + } + + public void setMinYaw(Integer yaw) { + this.minYaw = yaw; + } + + public Integer getMaxYaw() { + return this.maxYaw; + } + + public void setMaxYaw(Integer yaw) { + this.maxYaw = yaw; + } + + public Double getX() { + return this.x; + } + + public Double getY() { + return this.y; + } + + public Double getZ() { + return this.z; + } + + public void setX(double x) { + this.x = x; + } + + public void setY(double y) { + this.y = y; + } + + public void setZ(double z) { + this.z = z; + } + + public void setDx(double dx) { + this.dx = dx; + } + + public void setDy(double dy) { + this.dy = dy; + } + + public void setDz(double dz) { + this.dz = dz; + } + + public Double getDx() { + return this.dx; + } + + public Double getDy() { + return this.dy; + } + + public Double getDz() { + return this.dz; + } + + public void setMax(int max) { + this.max = max; + } + + public void setAllowNonPlayers(boolean allowNonPlayers) { + this.allowNonPlayers = allowNonPlayers; + } + + public void setOrder(BiConsumer> order) { + this.order = order; + } + + public EntitySelector parse() throws CommandSyntaxException { + this.cursorStart = this.reader.getCursor(); + this.suggestions = this::suggestSelectorOrName; + if (this.reader.canRead() && this.reader.peek() == '@') { + if (!this.allowSelectors) { + throw SELECTOR_NOT_ALLOWED_EXCEPTION.createWithContext(this.reader); + } + this.reader.skip(); + this.parseSelector(); + } else { + this.parseNameOrUuid(); + } + this.buildPredicate(); + return this.getSelector(); + } + + private static void suggestSelectors(SuggestionsBuilder builder) { + builder.suggest("@p", (Message) new TranslatableText("argument.entity.selector.nearestPlayer", new Object[0])); + builder.suggest("@a", (Message) new TranslatableText("argument.entity.selector.allPlayers", new Object[0])); + builder.suggest("@r", (Message) new TranslatableText("argument.entity.selector.randomPlayer", new Object[0])); + builder.suggest("@s", (Message) new TranslatableText("argument.entity.selector.self", new Object[0])); + builder.suggest("@e", (Message) new TranslatableText("argument.entity.selector.allEntities", new Object[0])); + } + + private CompletableFuture suggestSelectorOrName(SuggestionsBuilder builder, + Consumer nameSuggestions) { + nameSuggestions.accept(builder); + if (this.allowSelectors) { + EntitySelectorParser.suggestSelectors(builder); + } + return builder.buildFuture(); + } + + private CompletableFuture suggestName(SuggestionsBuilder builder, + Consumer nameSuggestions) { + SuggestionsBuilder suggestionsBuilder = builder.createOffset(this.cursorStart); + nameSuggestions.accept(suggestionsBuilder); + return builder.add(suggestionsBuilder).buildFuture(); + } + + private CompletableFuture suggestSelector(SuggestionsBuilder builder, + Consumer nameSuggestions) { + SuggestionsBuilder suggestionsBuilder = builder.createOffset(builder.getStart() - 1); + EntitySelectorParser.suggestSelectors(suggestionsBuilder); + builder.add(suggestionsBuilder); + return builder.buildFuture(); + } + + private CompletableFuture suggestOptionsStart(SuggestionsBuilder builder, + Consumer nameSuggestions) { + builder.suggest(String.valueOf('[')); + return builder.buildFuture(); + } + + private CompletableFuture suggestOptionsOrEnd(SuggestionsBuilder builder, + Consumer nameSuggestions) { + builder.suggest(String.valueOf(']')); + EntitySelectorOptions.suggest(this, builder); + return builder.buildFuture(); + } + + private CompletableFuture suggestOptions(SuggestionsBuilder builder, Consumer nameSuggestions) { + EntitySelectorOptions.suggest(this, builder); + return builder.buildFuture(); + } + + private CompletableFuture suggestNextOptionOrEnd(SuggestionsBuilder builder, + Consumer nameSuggestions) { + builder.suggest(String.valueOf(',')); + builder.suggest(String.valueOf(']')); + return builder.buildFuture(); + } + + public boolean hasSelf() { + return this.allowSelf; + } + + public void setSuggestions( + BiFunction, CompletableFuture> suggestions) { + this.suggestions = suggestions; + } + + public CompletableFuture addSuggestions(SuggestionsBuilder builder, + Consumer nameSuggestions) { + return this.suggestions.apply(builder.createOffset(this.reader.getCursor()), nameSuggestions); + } + + public boolean hasName() { + return this.hasName; + } + + public void setHasName(boolean hasName) { + this.hasName = hasName; + } + + public boolean hasNotName() { + return this.hasNotName; + } + + public void setHasNotName(boolean hasNotName) { + this.hasNotName = hasNotName; + } + + public boolean hasLimit() { + return this.hasLimit; + } + + public void setHasLimit(boolean hasLimit) { + this.hasLimit = hasLimit; + } + + public boolean hasOrder() { + return this.hasOrder; + } + + public void setHasOrder(boolean hasOrder) { + this.hasOrder = hasOrder; + } + + public boolean hasGameMode() { + return this.hasGameMode; + } + + public void setHasGameMode(boolean hasGameMode) { + this.hasGameMode = hasGameMode; + } + + public boolean hasNotGameMode() { + return this.hasNotGameMode; + } + + public void setHasNotGameMode(boolean hasNotGameMode) { + this.hasNotGameMode = hasNotGameMode; + } + + public boolean hasTeam() { + return this.hasTeam; + } + + public void setHasTeam(boolean hasTeam) { + this.hasTeam = hasTeam; + } + + public void setHasNotTeam(boolean hasNotTeam) { + this.hasNotTeam = hasNotTeam; + } + + public void setType(Class type) { + this.type = type; + } + + public void setHasNotType() { + this.hasNotType = true; + } + + public boolean hasType() { + return this.type != null; + } + + public boolean hasNotType() { + return this.hasNotType; + } + + public boolean hasScores() { + return this.hasScores; + } + + public void setHasScores(boolean hasScores) { + this.hasScores = hasScores; + } + + public boolean hasAdvancements() { + return this.hasAdvancements; + } + + public void setHasAdvancements(boolean hasAdvancements) { + this.hasAdvancements = hasAdvancements; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/FunctionArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/FunctionArgument.java new file mode 100644 index 00000000..d0d3a912 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/FunctionArgument.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; + +import net.minecraft.resource.Identifier; +import net.minecraft.server.command.function.CommandFunction; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.server.CommandSourceStack; + +public class FunctionArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo", "foo:bar", "#foo"); + private static final DynamicCommandExceptionType UNKNOWN_FUNCTION_EXCEPTION = new DynamicCommandExceptionType(function -> (Message)new TranslatableText("arguments.function.unknown", function)); + + public static FunctionArgument functions() { + return new FunctionArgument(); + } + + @Override + public Result parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + Identifier key = IdentifierParser.parse(reader); + return ctx -> { + CommandFunction function = ctx.getSource().getServer().getFunctions().get(key); + if (function == null) { + reader.setCursor(cursor); + throw UNKNOWN_FUNCTION_EXCEPTION.createWithContext(reader, key.toString()); + } + return Collections.singleton(function); + }; + } + + public static Collection getFunctions(CommandContext ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, Result.class).create(ctx); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public interface Result { + + Collection create(CommandContext ctx) throws CommandSyntaxException; + + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/GlobalCoordinates.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/GlobalCoordinates.java new file mode 100644 index 00000000..e1778124 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/GlobalCoordinates.java @@ -0,0 +1,115 @@ +package net.ornithemc.osl.commands.api.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public class GlobalCoordinates implements Coordinates { + + private final Coordinate x; + private final Coordinate y; + private final Coordinate z; + + public GlobalCoordinates(Coordinate x, Coordinate y, Coordinate z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public Vec3d getPosition(AbstractCommandSourceStack source) { + Vec3d pos = source.getPos(); + return new Vec3d(this.x.get(pos.x), this.y.get(pos.y), this.z.get(pos.z)); + } + + @Override + public Vec2f getRotation(AbstractCommandSourceStack source) { + Vec2f rot = source.getRotation(); + return new Vec2f((float) this.x.get(rot.x), (float) this.y.get(rot.y)); + } + + @Override + public boolean isXRelative() { + return this.x.isRelative(); + } + + @Override + public boolean isYRelative() { + return this.y.isRelative(); + } + + @Override + public boolean isZRelative() { + return this.z.isRelative(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof GlobalCoordinates)) { + return false; + } + GlobalCoordinates other = (GlobalCoordinates) obj; + if (!this.x.equals(other.x)) { + return false; + } + if (!this.y.equals(other.y)) { + return false; + } + return this.z.equals(other.z); + } + + public static GlobalCoordinates parseInt(StringReader reader) throws CommandSyntaxException { + int i = reader.getCursor(); + Coordinate coordinate = Coordinate.parseInt(reader); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + Coordinate coordinate2 = Coordinate.parseInt(reader); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + Coordinate coordinate3 = Coordinate.parseInt(reader); + return new GlobalCoordinates(coordinate, coordinate2, coordinate3); + } + + public static GlobalCoordinates parseDouble(StringReader reader, boolean centered) throws CommandSyntaxException { + int i = reader.getCursor(); + Coordinate coordinate = Coordinate.parseDouble(reader, centered); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + Coordinate coordinate2 = Coordinate.parseDouble(reader, false); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + Coordinate coordinate3 = Coordinate.parseDouble(reader, centered); + return new GlobalCoordinates(coordinate, coordinate2, coordinate3); + } + + public static GlobalCoordinates self() { + return new GlobalCoordinates(new Coordinate(true, 0.0), new Coordinate(true, 0.0), new Coordinate(true, 0.0)); + } + + @Override + public int hashCode() { + int hashCode = this.x.hashCode(); + hashCode = 31 * hashCode + this.y.hashCode(); + hashCode = 31 * hashCode + this.z.hashCode(); + return hashCode; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierArgument.java new file mode 100644 index 00000000..f2634de2 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierArgument.java @@ -0,0 +1,38 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; + +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +public class IdentifierArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo", "foo:bar", "012"); + public static final DynamicCommandExceptionType UNKNOWN_ID_EXCEPTION = new DynamicCommandExceptionType(id -> (Message)new TranslatableText("argument.id.unknown", id)); + + public static IdentifierArgument identifier() { + return new IdentifierArgument(); + } + + public static Identifier getId(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Identifier.class); + } + + @Override + public Identifier parse(StringReader reader) throws CommandSyntaxException { + return IdentifierParser.parse(reader); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierParser.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierParser.java new file mode 100644 index 00000000..85b08978 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/IdentifierParser.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.commands.api.argument; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.resource.loader.api.ResourceUtils; + +public class IdentifierParser { + + private static final SimpleCommandExceptionType INVALID_IDENTIFIER_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.id.invalid")); + + public static Identifier parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + + while (reader.canRead() && ResourceUtils.isValidChar(reader.peek())) { + reader.skip(); + } + + Identifier id = new Identifier(reader.getString().substring(cursor, reader.getCursor())); + + if (!ResourceUtils.isValidIdentifier(id)) { + reader.setCursor(cursor); + throw INVALID_IDENTIFIER_EXCEPTION.createWithContext(reader); + } + + return id; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockArgument.java new file mode 100644 index 00000000..8fd33f5b --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockArgument.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.block.Block; +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class LegacyBlockArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("stone", "minecraft:stone"); + public static final DynamicCommandExceptionType UNKNOWN_BLOCK_EXCEPTION = new DynamicCommandExceptionType(block -> (Message)new TranslatableText("block.unknown", block)); + + public static LegacyBlockArgument block() { + return new LegacyBlockArgument(); + } + + public static Block getBlock(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Block.class); + } + + @Override + public Block parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + Identifier key = IdentifierParser.parse(reader); + Block block = Block.REGISTRY.get(key); + + if (block == null) { + reader.setCursor(cursor); + throw UNKNOWN_BLOCK_EXCEPTION.createWithContext(reader, key); + } + + return block; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestResource(Block.REGISTRY.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockDataArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockDataArgument.java new file mode 100644 index 00000000..cfb77ef1 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LegacyBlockDataArgument.java @@ -0,0 +1,49 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.block.state.BlockState; + +public class LegacyBlockDataArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo=bar", "0"); + + public static LegacyBlockDataArgument blockState() { + return new LegacyBlockDataArgument(); + } + + public static BlockState getBlockState(CommandContext ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, BlockState.class); + } + + @Override + public BlockState parse(StringReader reader) throws CommandSyntaxException { + return new BlockStateParser(reader, true).parse().getState(); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + StringReader reader = new StringReader(builder.getInput()); + reader.setCursor(builder.getStart()); + BlockStateParser parser = new BlockStateParser(reader, true); + try { + parser.parse(); + } catch (CommandSyntaxException e) { + } + return parser.addSuggestions(builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LocalCoordinates.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LocalCoordinates.java new file mode 100644 index 00000000..59e03710 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/LocalCoordinates.java @@ -0,0 +1,111 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Objects; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public class LocalCoordinates implements Coordinates { + + private final double left; + private final double upwards; + private final double forwards; + + public LocalCoordinates(double left, double upwards, double forwards) { + this.left = left; + this.upwards = upwards; + this.forwards = forwards; + } + + @Override + public Vec3d getPosition(AbstractCommandSourceStack source) { + Vec2f vec2f = source.getRotation(); + Vec3d vec3d = source.getAnchor().apply(source); + float f = MathHelper.cos((vec2f.y + 90.0f) * ((float) Math.PI / 180)); + float g = MathHelper.sin((vec2f.y + 90.0f) * ((float) Math.PI / 180)); + float h = MathHelper.cos(-vec2f.x * ((float) Math.PI / 180)); + float i = MathHelper.sin(-vec2f.x * ((float) Math.PI / 180)); + float j = MathHelper.cos((-vec2f.x + 90.0f) * ((float) Math.PI / 180)); + float k = MathHelper.sin((-vec2f.x + 90.0f) * ((float) Math.PI / 180)); + Vec3d vec3d2 = new Vec3d(f * h, i, g * h); + Vec3d vec3d3 = new Vec3d(f * j, k, g * j); + Vec3d vec3d4 = vec3d2.cross(vec3d3).scale(-1.0); + double d = vec3d2.x * this.forwards + vec3d3.x * this.upwards + vec3d4.x * this.left; + double e = vec3d2.y * this.forwards + vec3d3.y * this.upwards + vec3d4.y * this.left; + double l = vec3d2.z * this.forwards + vec3d3.z * this.upwards + vec3d4.z * this.left; + return new Vec3d(vec3d.x + d, vec3d.y + e, vec3d.z + l); + } + + @Override + public Vec2f getRotation(AbstractCommandSourceStack source) { + return Vec2f.ZERO; + } + + @Override + public boolean isXRelative() { + return true; + } + + @Override + public boolean isYRelative() { + return true; + } + + @Override + public boolean isZRelative() { + return true; + } + + public static LocalCoordinates parse(StringReader reader) throws CommandSyntaxException { + int i = reader.getCursor(); + double d = LocalCoordinates.parseDouble(reader, i); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + double e = LocalCoordinates.parseDouble(reader, i); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(i); + throw Vec3dArgument.INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + double f = LocalCoordinates.parseDouble(reader, i); + return new LocalCoordinates(d, e, f); + } + + private static double parseDouble(StringReader reader, int pos) throws CommandSyntaxException { + if (!reader.canRead()) { + throw Coordinate.NOT_DOUBLE_EXCEPTION.createWithContext(reader); + } + if (reader.peek() != '^') { + reader.setCursor(pos); + throw Vec3dArgument.MIXED_TYPE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + return reader.canRead() && reader.peek() != ' ' ? reader.readDouble() : 0.0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LocalCoordinates)) { + return false; + } + LocalCoordinates other = (LocalCoordinates) obj; + return this.left == other.left && this.upwards == other.upwards && this.forwards == other.forwards; + } + + @Override + public int hashCode() { + return Objects.hash(this.left, this.upwards, this.forwards); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/MessageArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/MessageArgument.java new file mode 100644 index 00000000..bea0cfed --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/MessageArgument.java @@ -0,0 +1,126 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public class MessageArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("Hello world!", "foo", "@e", "Hello @p :)"); + + public static MessageArgument message() { + return new MessageArgument(); + } + + public static Text getMessage(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, Message.class).toText(ctx.getSource(), ctx.getSource().hasPermissions(2)); + } + + @Override + public Message parse(StringReader reader) throws CommandSyntaxException { + return Message.parseText(reader, true); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public static class Part { + + private final int start; + private final int end; + private final EntitySelector selector; + + public Part(int start, int end, EntitySelector selector) { + this.start = start; + this.end = end; + this.selector = selector; + } + + public int getStart() { + return this.start; + } + + public int getEnd() { + return this.end; + } + + public Text getText(AbstractCommandSourceStack source) throws CommandSyntaxException { + return EntitySelector.joinNames(this.selector.findEntities(source)); + } + } + + public static class Message { + + private final String text; + private final Part[] parts; + + public Message(String text, Part[] parts) { + this.text = text; + this.parts = parts; + } + + public Text toText(AbstractCommandSourceStack source, boolean op) throws CommandSyntaxException { + if (this.parts.length == 0 || !op) { + return new LiteralText(this.text); + } + LiteralText text = new LiteralText(this.text.substring(0, this.parts[0].getStart())); + int start = this.parts[0].getStart(); + for (Part part : this.parts) { + Text text2 = part.getText(source); + if (start < part.getStart()) { + text.append(this.text.substring(start, part.getStart())); + } + if (text2 != null) { + text.append(text2); + } + start = part.getEnd(); + } + if (start < this.text.length()) { + text.append(this.text.substring(start, this.text.length())); + } + return text; + } + + public static Message parseText(StringReader reader, boolean op) throws CommandSyntaxException { + String string = reader.getString().substring(reader.getCursor(), reader.getTotalLength()); + if (!op) { + reader.setCursor(reader.getTotalLength()); + return new Message(string, new Part[0]); + } + ArrayList parts = new ArrayList<>(); + int start = reader.getCursor(); + while (reader.canRead()) { + if (reader.peek() == '@') { + EntitySelector selector; + int cursor = reader.getCursor(); + try { + EntitySelectorParser parser = new EntitySelectorParser(reader); + selector = parser.parse(); + } catch (CommandSyntaxException e) { + if (e.getType() == EntitySelectorParser.SELECTOR_MISSING_EXCEPTION || e.getType() == EntitySelectorParser.UNKNOWN_SELECTOR_EXCEPTION) { + reader.setCursor(cursor + 1); + continue; + } + throw e; + } + parts.add(new Part(cursor - start, reader.getCursor() - start, selector)); + continue; + } + reader.skip(); + } + return new Message(string, parts.toArray(new Part[parts.size()])); + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ObjectiveArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ObjectiveArgument.java new file mode 100644 index 00000000..eb5fbd62 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ObjectiveArgument.java @@ -0,0 +1,85 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public class ObjectiveArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo", "*", "012"); + private static final DynamicCommandExceptionType NOT_FOUND_EXCEPTION = new DynamicCommandExceptionType(objective -> (Message)new TranslatableText("arguments.objective.notFound", objective)); + private static final DynamicCommandExceptionType READ_ONLY_EXCEPTION = new DynamicCommandExceptionType(objective -> (Message)new TranslatableText("arguments.objective.readonly", objective)); + public static final DynamicCommandExceptionType NAME_TOO_LONG_EXCEPTION = new DynamicCommandExceptionType(objective -> (Message)new TranslatableText("commands.scoreboard.objectives.add.longName", objective)); + + public static ObjectiveArgument objective() { + return new ObjectiveArgument(); + } + + public static ScoreboardObjective getObjective(CommandContext> ctx, String arg) throws CommandSyntaxException { + String name = ctx.getArgument(arg, String.class); + Scoreboard scoreboard = ctx.getSource().getWorld().getScoreboard(); + ScoreboardObjective objective = scoreboard.getObjective(name); + + if (objective == null) { + throw NOT_FOUND_EXCEPTION.create(name); + } + + return objective; + } + + public static ScoreboardObjective getWritableObjective(CommandContext> ctx, String arg) throws CommandSyntaxException { + ScoreboardObjective objective = getObjective(ctx, arg); + + if (objective.getCriterion().isReadOnly()) { + throw READ_ONLY_EXCEPTION.create(objective.getName()); + } + + return objective; + } + + @Override + public String parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String name = reader.readUnquotedString(); + + if (name.length() > 16) { + reader.setCursor(cursor); + throw NAME_TOO_LONG_EXCEPTION.createWithContext(reader, 16); + } + + return name; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof AbstractCommandSourceStack) { + return SuggestionProvider.suggestMatching(((AbstractCommandSourceStack)ctx.getSource()).getWorld().getScoreboard().getObjectives().stream().map(ScoreboardObjective::getName), builder); + } + if (ctx.getSource() instanceof SuggestionProvider) { + SuggestionProvider suggestionProvider = (SuggestionProvider)ctx.getSource(); + return suggestionProvider.suggest((CommandContext)ctx, builder); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/OperationArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/OperationArgument.java new file mode 100644 index 00000000..763d3101 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/OperationArgument.java @@ -0,0 +1,118 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.scoreboard.ScoreboardScore; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.MathHelper; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class OperationArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("=", ">", "<"); + private static final SimpleCommandExceptionType INVALID_OPERATION_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("arguments.operation.invalid")); + private static final SimpleCommandExceptionType DIVIDE_BY_ZERO_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("arguments.operation.div0")); + + public static OperationArgument operation() { + return new OperationArgument(); + } + + public static Operation getOperation(CommandContext ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, Operation.class); + } + + @Override + public Operation parse(StringReader reader) throws CommandSyntaxException { + if (reader.canRead()) { + int cursor = reader.getCursor(); + while (reader.canRead() && reader.peek() != ' ') { + reader.skip(); + } + return OperationArgument.getOperation(reader.getString().substring(cursor, reader.getCursor())); + } + throw INVALID_OPERATION_EXCEPTION.create(); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(new String[] { "=", "+=", "-=", "*=", "/=", "%=", "<", ">", "><" }, builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + private static Operation getOperation(String operation) throws CommandSyntaxException { + if (operation.equals("><")) { + return (score1, score2) -> { + int score = score1.get(); + score1.set(score2.get()); + score2.set(score); + }; + } + return OperationArgument.getSimpleOperation(operation); + } + + private static SimpleOperation getSimpleOperation(String operation) throws CommandSyntaxException { + switch (operation) { + case "=": + return (score1, score2) -> score2; + case "+=": + return (score1, score2) -> score1 + score2; + case "-=": + return (score1, score2) -> score1 - score2; + case "*=": + return (score1, score2) -> score1 * score2; + case "/=": + return (score1, score2) -> { + if (score2 == 0) { + throw DIVIDE_BY_ZERO_EXCEPTION.create(); + } + return MathHelper.floorDiv(score1, score2); + }; + case "%=": + return (score1, score2) -> { + if (score2 == 0) { + throw DIVIDE_BY_ZERO_EXCEPTION.create(); + } + return MathHelper.floorMod(score1, score2); + }; + case "<": + return Math::min; + case ">": + return Math::max; + } + throw INVALID_OPERATION_EXCEPTION.create(); + } + + @FunctionalInterface + interface SimpleOperation extends Operation { + + int apply(int score1, int score2) throws CommandSyntaxException; + + @Override + default void apply(ScoreboardScore score1, ScoreboardScore score2) throws CommandSyntaxException { + score1.set(this.apply(score1.get(), score2.get())); + } + } + + @FunctionalInterface + public interface Operation { + + void apply(ScoreboardScore score1, ScoreboardScore score2) throws CommandSyntaxException; + + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/RotationArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/RotationArgument.java new file mode 100644 index 00000000..989c07fe --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/RotationArgument.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.text.TranslatableText; + +public class RotationArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("0 0", "~ ~", "~-5 ~5"); + public static final SimpleCommandExceptionType INCOMPLETE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.rotation.incomplete")); + + public static RotationArgument rotation() { + return new RotationArgument(); + } + + public static Coordinates getRotation(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Coordinates.class); + } + + @Override + public Coordinates parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + if (!reader.canRead()) { + throw INCOMPLETE_EXCEPTION.createWithContext(reader); + } + Coordinate y = Coordinate.parseDouble(reader, false); + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(cursor); + throw INCOMPLETE_EXCEPTION.createWithContext(reader); + } + reader.skip(); + Coordinate z = Coordinate.parseDouble(reader, false); + return new GlobalCoordinates(z, y, new Coordinate(true, 0.0)); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardCriterionArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardCriterionArgument.java new file mode 100644 index 00000000..bb29d22a --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardCriterionArgument.java @@ -0,0 +1,66 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.scoreboard.criterion.ScoreboardCriterion; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; + +public class ScoreboardCriterionArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo", "foo.bar.baz", "minecraft:foo"); + public static final DynamicCommandExceptionType INVALID_CRITERION_EXCEPTION = new DynamicCommandExceptionType(name -> (Message)new TranslatableText("argument.criteria.invalid", name)); + + private ScoreboardCriterionArgument() { + } + + public static ScoreboardCriterionArgument criterion() { + return new ScoreboardCriterionArgument(); + } + + public static ScoreboardCriterion getCriterion(CommandContext ctx, String arg) { + return ctx.getArgument(arg, ScoreboardCriterion.class); + } + + @Override + public ScoreboardCriterion parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + + while (reader.canRead() && reader.peek() != ' ') { + reader.skip(); + } + + String name = reader.getString().substring(cursor, reader.getCursor()); + ScoreboardCriterion criterion = ScoreboardCriterion.BY_NAME.get(name); + + if (criterion == null) { + reader.setCursor(cursor); + throw INVALID_CRITERION_EXCEPTION.createWithContext(reader, name); + } + + return criterion; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(ScoreboardCriterion.BY_NAME.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardDisplaySlotArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardDisplaySlotArgument.java new file mode 100644 index 00000000..7a0e3e29 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/ScoreboardDisplaySlotArgument.java @@ -0,0 +1,60 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class ScoreboardDisplaySlotArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("sidebar", "foo.bar"); + public static final DynamicCommandExceptionType INVALID_DISPLAY_SLOT_EXCEPTION = new DynamicCommandExceptionType(slot -> (Message)new TranslatableText("argument.scoreboardDisplaySlot.invalid", slot)); + + private ScoreboardDisplaySlotArgument() { + } + + public static ScoreboardDisplaySlotArgument displaySlot() { + return new ScoreboardDisplaySlotArgument(); + } + + public static int getDisplaySlot(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Integer.class); + } + + @Override + public Integer parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String location = reader.readUnquotedString(); + int slot = Scoreboard.getDisplaySlot(location); + + if (slot == -1) { + reader.setCursor(cursor); + throw INVALID_DISPLAY_SLOT_EXCEPTION.createWithContext(reader, location); + } + + return slot; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestMatching(Scoreboard.getDisplayLocations(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/SnbtParser.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/SnbtParser.java new file mode 100644 index 00000000..e860dbd0 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/SnbtParser.java @@ -0,0 +1,258 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.nbt.NbtByte; +import net.minecraft.nbt.NbtByteArray; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtDouble; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtFloat; +import net.minecraft.nbt.NbtInt; +import net.minecraft.nbt.NbtIntArray; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtLong; +import net.minecraft.nbt.NbtLongArray; +import net.minecraft.nbt.NbtShort; +import net.minecraft.nbt.NbtString; +import net.minecraft.text.TranslatableText; + +public class SnbtParser { + + public static final SimpleCommandExceptionType TRAILING_DATA_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.nbt.trailing")); + public static final SimpleCommandExceptionType KEY_EXPECTED_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.nbt.expected.key")); + public static final SimpleCommandExceptionType VALUE_EXPECTED_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.nbt.expected.value")); + public static final Dynamic2CommandExceptionType MIXED_LIST_TYPE_EXCEPTION = new Dynamic2CommandExceptionType((type1, type2) -> (Message)new TranslatableText("argument.nbt.list.mixed", type1, type2)); + public static final Dynamic2CommandExceptionType MIXED_ARRAY_TYPE_EXCEPTION = new Dynamic2CommandExceptionType((type1, type2) -> (Message)new TranslatableText("argument.nbt.array.mixed", type1, type2)); + public static final DynamicCommandExceptionType INVALID_ARRAY_EXCEPTION = new DynamicCommandExceptionType(chr -> (Message)new TranslatableText("argument.nbt.array.invalid", chr)); + + private static final Pattern DOUBLE_PATTERN_NO_SUFFIX = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", 2); + private static final Pattern DOUBLE_PATTERN = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2); + private static final Pattern FLOAT_PATTERN = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", 2); + private static final Pattern BYTE_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", 2); + private static final Pattern LONG_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", 2); + private static final Pattern SHORT_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", 2); + private static final Pattern PRIMITIVE_PATTERN = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)"); + + private final StringReader reader; + + public static NbtCompound parse(String rawNbt) throws CommandSyntaxException { + return new SnbtParser(new StringReader(rawNbt)).parse(); + } + + NbtCompound parse() throws CommandSyntaxException { + NbtCompound nbt = this.readCompound(); + this.reader.skipWhitespace(); + if (this.reader.canRead()) { + throw TRAILING_DATA_EXCEPTION.createWithContext(this.reader); + } + return nbt; + } + + public SnbtParser(StringReader reader) { + this.reader = reader; + } + + protected String readKey() throws CommandSyntaxException { + this.reader.skipWhitespace(); + if (!this.reader.canRead()) { + throw KEY_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + return this.reader.readString(); + } + + protected NbtElement readElement() throws CommandSyntaxException { + this.reader.skipWhitespace(); + int i = this.reader.getCursor(); + if (this.reader.peek() == '\"') { + return new NbtString(this.reader.readQuotedString()); + } + String string = this.reader.readUnquotedString(); + if (string.isEmpty()) { + this.reader.setCursor(i); + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + return this.parseElement(string); + } + + private NbtElement parseElement(String s) { + try { + if (FLOAT_PATTERN.matcher(s).matches()) { + return new NbtFloat(Float.parseFloat(s.substring(0, s.length() - 1))); + } + if (BYTE_PATTERN.matcher(s).matches()) { + return new NbtByte(Byte.parseByte(s.substring(0, s.length() - 1))); + } + if (LONG_PATTERN.matcher(s).matches()) { + return new NbtLong(Long.parseLong(s.substring(0, s.length() - 1))); + } + if (SHORT_PATTERN.matcher(s).matches()) { + return new NbtShort(Short.parseShort(s.substring(0, s.length() - 1))); + } + if (PRIMITIVE_PATTERN.matcher(s).matches()) { + return new NbtInt(Integer.parseInt(s)); + } + if (DOUBLE_PATTERN.matcher(s).matches()) { + return new NbtDouble(Double.parseDouble(s.substring(0, s.length() - 1))); + } + if (DOUBLE_PATTERN_NO_SUFFIX.matcher(s).matches()) { + return new NbtDouble(Double.parseDouble(s)); + } + if ("true".equalsIgnoreCase(s)) { + return new NbtByte((byte)1); + } + if ("false".equalsIgnoreCase(s)) { + return new NbtByte((byte)0); + } + } catch (NumberFormatException numberFormatException) { + } + return new NbtString(s); + } + + protected NbtElement readValue() throws CommandSyntaxException { + this.reader.skipWhitespace(); + if (!this.reader.canRead()) { + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + char c = this.reader.peek(); + if (c == '{') { + return this.readCompound(); + } + if (c == '[') { + return this.readListOrArray(); + } + return this.readElement(); + } + + protected NbtElement readListOrArray() throws CommandSyntaxException { + if (this.reader.canRead(3) && this.reader.peek(1) != '\"' && this.reader.peek(2) == ';') { + return this.readArray(); + } + return this.readList(); + } + + public NbtCompound readCompound() throws CommandSyntaxException { + this.expect('{'); + NbtCompound nbtCompound = new NbtCompound(); + this.reader.skipWhitespace(); + while (this.reader.canRead() && this.reader.peek() != '}') { + int i = this.reader.getCursor(); + String string = this.readKey(); + if (string.isEmpty()) { + this.reader.setCursor(i); + throw KEY_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + this.expect(':'); + nbtCompound.put(string, this.readValue()); + if (!this.hasSeparator()) + break; + if (this.reader.canRead()) + continue; + throw KEY_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + this.expect('}'); + return nbtCompound; + } + + private NbtElement readList() throws CommandSyntaxException { + this.expect('['); + this.reader.skipWhitespace(); + if (!this.reader.canRead()) { + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + NbtList nbtList = new NbtList(); + byte i = -1; + while (this.reader.peek() != ']') { + int j = this.reader.getCursor(); + NbtElement nbtElement = this.readValue(); + byte k = nbtElement.getType(); + if (i < 0) { + i = k; + } else if (k != i) { + this.reader.setCursor(j); + throw MIXED_LIST_TYPE_EXCEPTION.createWithContext(this.reader, NbtElement.getName(k), NbtElement.getName(i)); + } + nbtList.add(nbtElement); + if (!this.hasSeparator()) + break; + if (this.reader.canRead()) + continue; + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + this.expect(']'); + return nbtList; + } + + private NbtElement readArray() throws CommandSyntaxException { + this.expect('['); + int i = this.reader.getCursor(); + char c = this.reader.read(); + this.reader.read(); + this.reader.skipWhitespace(); + if (!this.reader.canRead()) { + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + if (c == 'B') { + return new NbtByteArray(this.readArray((byte) 7, (byte) 1)); + } + if (c == 'L') { + return new NbtLongArray(this.readArray((byte) 12, (byte) 4)); + } + if (c == 'I') { + return new NbtIntArray(this.readArray((byte) 11, (byte) 3)); + } + this.reader.setCursor(i); + throw INVALID_ARRAY_EXCEPTION.createWithContext(this.reader, String.valueOf(c)); + } + + private List readArray(byte arrayType, byte elementType) throws CommandSyntaxException { + ArrayList list = new ArrayList<>(); + while (this.reader.peek() != ']') { + int i = this.reader.getCursor(); + NbtElement nbtElement = this.readValue(); + byte j = nbtElement.getType(); + if (j != elementType) { + this.reader.setCursor(i); + throw MIXED_ARRAY_TYPE_EXCEPTION.createWithContext(this.reader, NbtElement.getName(j), NbtElement.getName(arrayType)); + } + if (elementType == 1) { + list.add(((NbtByte)nbtElement).getByte()); + } else if (elementType == 4) { + list.add(((NbtLong)nbtElement).getLong()); + } else { + list.add(((NbtInt)nbtElement).getInt()); + } + if (!this.hasSeparator()) + break; + if (this.reader.canRead()) + continue; + throw VALUE_EXPECTED_EXCEPTION.createWithContext(this.reader); + } + this.expect(']'); + return (List)list; + } + + private boolean hasSeparator() { + this.reader.skipWhitespace(); + if (this.reader.canRead() && this.reader.peek() == ',') { + this.reader.skip(); + this.reader.skipWhitespace(); + return true; + } + return false; + } + + private void expect(char chr) throws CommandSyntaxException { + this.reader.skipWhitespace(); + this.reader.expect(chr); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/StatusEffectArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/StatusEffectArgument.java new file mode 100644 index 00000000..2d252ada --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/StatusEffectArgument.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.entity.living.effect.StatusEffect; +import net.minecraft.resource.Identifier; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class StatusEffectArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("spooky", "effect"); + public static final DynamicCommandExceptionType UNKNOWN_STATUS_EFFECT_EXCEPTION = new DynamicCommandExceptionType(effect -> (Message)new TranslatableText("effect.effectNotFound", effect)); + + public static StatusEffectArgument effect() { + return new StatusEffectArgument(); + } + + public static StatusEffect getEffect(CommandContext ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, StatusEffect.class); + } + + @Override + public StatusEffect parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + Identifier key = IdentifierParser.parse(reader); + StatusEffect effect = StatusEffect.REGISTRY.get(key); + + if (effect == null) { + reader.setCursor(cursor); + throw UNKNOWN_STATUS_EFFECT_EXCEPTION.create(key); + } + + return effect; + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + return SuggestionProvider.suggestResource(StatusEffect.REGISTRY.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TeamArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TeamArgument.java new file mode 100644 index 00000000..97dd0798 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TeamArgument.java @@ -0,0 +1,61 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.team.Team; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class TeamArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("foo", "123"); + private static final DynamicCommandExceptionType UNKNOWN_TEAM_EXCEPTION = new DynamicCommandExceptionType(team -> (Message)new TranslatableText("team.notFound", team)); + + public static TeamArgument team() { + return new TeamArgument(); + } + + public static Team getTeam(CommandContext> ctx, String arg) throws CommandSyntaxException { + String name = ctx.getArgument(arg, String.class); + Scoreboard scoreboard = ctx.getSource().getWorld().getScoreboard(); + Team team = scoreboard.getTeam(name); + + if (team == null) { + throw UNKNOWN_TEAM_EXCEPTION.create(name); + } + + return team; + } + + @Override + public String parse(StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof SuggestionProvider) { + return SuggestionProvider.suggestMatching(((SuggestionProvider)ctx.getSource()).getTeams(), builder); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TextArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TextArgument.java new file mode 100644 index 00000000..2a110377 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/TextArgument.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; + +import com.google.gson.JsonParseException; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; + +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class TextArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("\"hello world\"", "\"\"", "\"{\"text\":\"hello world\"}", "[\"\"]"); + public static final DynamicCommandExceptionType INVALID_TEXT_EXCEPTION = new DynamicCommandExceptionType(text -> (Message)new TranslatableText("argument.component.invalid", text)); + + private TextArgument() { + } + + public static Text getText(CommandContext ctx, String arg) { + return ctx.getArgument(arg, Text.class); + } + + public static TextArgument text() { + return new TextArgument(); + } + + @Override + public Text parse(StringReader reader) throws CommandSyntaxException { + try { + Text text = Text.Serializer.fromJson(reader.getRemaining()); + if (text == null) { + throw INVALID_TEXT_EXCEPTION.createWithContext(reader, "empty"); + } + return text; + } catch (JsonParseException e) { + String message = e.getCause() != null ? e.getCause().getMessage() : e.getMessage(); + throw INVALID_TEXT_EXCEPTION.createWithContext(reader, message); + } + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec2fArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec2fArgument.java new file mode 100644 index 00000000..a4a0f588 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec2fArgument.java @@ -0,0 +1,82 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandManager; +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class Vec2fArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("0 0", "~ ~", "0.1 -0.5", "~1 ~-2"); + public static final SimpleCommandExceptionType INCOMPLETE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos2d.incomplete", new Object[0])); + + private final boolean centerCorrect; + + public Vec2fArgument(boolean centerCorrect) { + this.centerCorrect = centerCorrect; + } + + public static Vec2fArgument vec2f() { + return new Vec2fArgument(true); + } + + public static Vec2f getVec2f(CommandContext> ctx, String arg) throws CommandSyntaxException { + Vec3d pos = ctx.getArgument(arg, Coordinates.class).getPosition(ctx.getSource()); + return new Vec2f((float)pos.x, (float)pos.z); + } + + @Override + public Coordinates parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + + if (!reader.canRead()) { + throw INCOMPLETE_EXCEPTION.createWithContext(reader); + } + + Coordinate x = Coordinate.parseDouble(reader, this.centerCorrect); + + if (!reader.canRead() || reader.peek() != ' ') { + reader.setCursor(cursor); + throw INCOMPLETE_EXCEPTION.createWithContext(reader); + } + + reader.skip(); + Coordinate z = Coordinate.parseDouble(reader, this.centerCorrect); + + return new GlobalCoordinates(x, new Coordinate(true, 0.0), z); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof SuggestionProvider) { + String s = builder.getRemaining(); + Collection coordinates = !s.isEmpty() && s.charAt(0) == '^' + ? Collections.singleton(SuggestionProvider.Coordinate.DEFAULT_LOCAL) + : ((SuggestionProvider) ctx.getSource()).getCoordinates(true); + return SuggestionProvider.suggestHorizontalCoordinates(s, coordinates, builder, BrigadierCommandManager.validator(this::parse)); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec3dArgument.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec3dArgument.java new file mode 100644 index 00000000..924399f1 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/argument/Vec3dArgument.java @@ -0,0 +1,76 @@ +package net.ornithemc.osl.commands.api.argument; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandManager; +import net.ornithemc.osl.commands.api.SuggestionProvider; + +public class Vec3dArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("0 0 0", "~ ~ ~", "^ ^ ^", "^1 ^ ^-5","0.1 -0.5 .9", "~0.5 ~1 ~-5"); + public static final SimpleCommandExceptionType INCOMPLETE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos3d.incomplete")); + public static final SimpleCommandExceptionType MIXED_TYPE_EXCEPTION = new SimpleCommandExceptionType((Message)new TranslatableText("argument.pos.mixed")); + + private final boolean centered; + + public Vec3dArgument(boolean centered) { + this.centered = centered; + } + + public static Vec3dArgument vec3d() { + return new Vec3dArgument(true); + } + + public static Vec3dArgument vec3d(boolean centered) { + return new Vec3dArgument(centered); + } + + public static Vec3d getVec3d(CommandContext> ctx, String arg) throws CommandSyntaxException { + return ctx.getArgument(arg, Coordinates.class).getPosition(ctx.getSource()); + } + + public static Coordinates getCoordinates(CommandContext> ctx, String arg) { + return ctx.getArgument(arg, Coordinates.class); + } + + @Override + public Coordinates parse(StringReader reader) throws CommandSyntaxException { + if (reader.canRead() && reader.peek() == '^') { + return LocalCoordinates.parse(reader); + } + return GlobalCoordinates.parseDouble(reader, this.centered); + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + if (ctx.getSource() instanceof SuggestionProvider) { + String s = builder.getRemaining(); + Collection coordinates = !s.isEmpty() && s.charAt(0) == '^' + ? Collections.singleton(SuggestionProvider.Coordinate.DEFAULT_LOCAL) + : ((SuggestionProvider) ctx.getSource()).getCoordinates(true); + return SuggestionProvider.suggestCoordinates(s, coordinates, builder, BrigadierCommandManager.validator(this::parse)); + } + return Suggestions.empty(); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java new file mode 100644 index 00000000..7dea1a92 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.commands.api.client; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; + +import net.ornithemc.osl.commands.impl.client.ClientCommandManagerImpl; + +public class ClientCommandManager { + + public static CommandDispatcher getDispatcher() { + return ClientCommandManagerImpl.getDispatcher(); + } + + public static LiteralArgumentBuilder literal(String name) { + return LiteralArgumentBuilder.literal(name); + } + + public static RequiredArgumentBuilder argument(String name, ArgumentType type) { + return RequiredArgumentBuilder.argument(name, type); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java new file mode 100644 index 00000000..61be0b3d --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java @@ -0,0 +1,160 @@ +package net.ornithemc.osl.commands.api.client; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.BinaryOperator; + +import com.mojang.brigadier.ResultConsumer; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.argument.AnchorArgument; + +public class ClientCommandSourceStack extends AbstractCommandSourceStack { + + private final ClientWorld world; + private final Minecraft minecraft; + + public ClientCommandSourceStack(BrigadierCommandSource source, Vec3d pos, Vec2f rotation, ClientWorld world, int permissions, String name, Text displayName, Entity entity) { + this(source, pos, rotation, world, permissions, name, displayName, entity, false, (ctx, success, result) -> { }, AnchorArgument.Anchor.FEET); + } + + public ClientCommandSourceStack(BrigadierCommandSource source, Vec3d pos, Vec2f rotation, ClientWorld world, int permissions, String name, Text displayName, Entity entity, boolean silent, ResultConsumer callback, AnchorArgument.Anchor anchor) { + super(source, pos, rotation, permissions, name, displayName, entity, silent, callback, anchor); + + this.world = world; + this.minecraft = Minecraft.getInstance(); + } + + @Override + public ClientCommandSourceStack withEntity(Entity entity) { + if (this.entity == entity) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, entity.getName(), entity.getDisplayName(), entity, this.silent, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withPos(Vec3d pos) { + if (this.pos.equals(pos)) { + return this; + } + + return new ClientCommandSourceStack(this.source, pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withRotation(Vec2f rotation) { + if (this.rotation.equals(rotation)) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, rotation, this.world, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withCallback(ResultConsumer callback) { + if (this.callback.equals(callback)) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.entity, this.silent, callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withCallback(ResultConsumer callback, BinaryOperator> chooser) { + return this.withCallback(chooser.apply(this.callback, callback)); + } + + @Override + public ClientCommandSourceStack silent() { + if (this.silent) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.entity, true, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withPermissions(int permissions) { + if (permissions == this.permissions) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withMaxPermissions(int maxPermissions) { + if (maxPermissions <= this.permissions) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, maxPermissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public ClientCommandSourceStack withAnchor(AnchorArgument.Anchor anchor) { + if (anchor == this.anchor) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, anchor); + } + + @Override + public ClientCommandSourceStack withFacing(Entity entity, AnchorArgument.Anchor anchor) throws CommandSyntaxException { + return this.withFacing(anchor.apply(entity)); + } + + @Override + public ClientCommandSourceStack withFacing(Vec3d target) throws CommandSyntaxException { + Vec3d anchorPos = this.anchor.apply(this); + + double dx = target.x - anchorPos.x; + double dy = target.y - anchorPos.y; + double dz = target.z - anchorPos.z; + double squaredDistance = MathHelper.sqrt(dx * dx + dz * dz); + + float rotX = MathHelper.wrapDegrees((float)(-(MathHelper.fastAtan2(dy, squaredDistance) * 57.2957763671875))); + float rotY = MathHelper.wrapDegrees((float)(MathHelper.fastAtan2(dz, dx) * 57.2957763671875) - 90.0f); + + return this.withRotation(new Vec2f(rotX, rotY)); + } + + @Override + public ClientWorld getWorld() { + return this.world; + } + + public Minecraft getMinecraft() { + return this.minecraft; + } + + public void sendSuccess(Text message) { + if (this.source.sendCommandSuccess() && !this.silent) { + this.source.sendMessage(message); + } + } + + @Override + public Collection getPlayerNames() { + List names = new ArrayList<>(); + for (PlayerEntity player : this.world.players) { + names.add(player.getName()); + } + return names; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializer.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializer.java new file mode 100644 index 00000000..120064ab --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializer.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.commands.api.serdes; + +import com.mojang.brigadier.arguments.ArgumentType; + +import net.minecraft.network.PacketByteBuf; + +public interface ArgumentSerializer> { + + void serialize(T arg, PacketByteBuf buffer); + + T deserialize(PacketByteBuf buffer); + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializers.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializers.java new file mode 100644 index 00000000..bb708856 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/ArgumentSerializers.java @@ -0,0 +1,239 @@ +package net.ornithemc.osl.commands.api.serdes; +/* +import java.util.Collection; +import java.util.Map; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.Maps; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.tree.ArgumentCommandNode; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import com.mojang.brigadier.tree.RootCommandNode; + +import net.minecraft.command.argument.AxesArgument; +import net.minecraft.command.argument.BlockArgument; +import net.minecraft.command.argument.BlockPosArgument; +import net.minecraft.command.argument.BlockPredicateArgument; +import net.minecraft.command.argument.ColorArgument; +import net.minecraft.command.argument.ColumnPosArgument; +import net.minecraft.command.argument.DimensionTypeArgument; +import net.minecraft.command.argument.EnchantmentArgument; +import net.minecraft.command.argument.EntityArgument; +import net.minecraft.command.argument.EntitySummonArgument; +import net.minecraft.command.argument.FunctionArgument; +import net.minecraft.command.argument.GameProfileArgument; +import net.minecraft.command.argument.IdentifierArgument; +import net.minecraft.command.argument.ItemArgument; +import net.minecraft.command.argument.ItemPredicateArgument; +import net.minecraft.command.argument.MessageArgument; +import net.minecraft.command.argument.NbtCompoundArgument; +import net.minecraft.command.argument.NbtPathArgument; +import net.minecraft.command.argument.ObjectiveArgument; +import net.minecraft.command.argument.OperationArgument; +import net.minecraft.command.argument.ParticleArgument; +import net.minecraft.command.argument.RangeArgument; +import net.minecraft.command.argument.RotationArgument; +import net.minecraft.command.argument.ScoreHolderArgument; +import net.minecraft.command.argument.ScoreboardCriterionArgument; +import net.minecraft.command.argument.ScoreboardDisplaySlotArgument; +import net.minecraft.command.argument.SlotArgument; +import net.minecraft.command.argument.StatusEffectArgument; +import net.minecraft.command.argument.TeamArgument; +import net.minecraft.command.argument.TextArgument; +import net.minecraft.command.argument.Vec2fArgument; +import net.minecraft.command.argument.Vec3dArgument; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.resource.Identifier; +import net.ornithemc.osl.commands.api.command.argument.AnchorArgument; +*/ +public class ArgumentSerializers {/* + private static final Logger LOGGER = LogManager.getLogger(); + private static final Map, Entry> BY_TYPE = Maps.newHashMap(); + private static final Map> BY_NAME = Maps.newHashMap(); + + public static > void register(Identifier name, Class type, + ArgumentSerializer serializer) { + if (BY_TYPE.containsKey(type)) { + throw new IllegalArgumentException("Class " + type.getName() + " already has a serializer!"); + } + if (BY_NAME.containsKey(name)) { + throw new IllegalArgumentException("'" + name + "' is already a registered serializer!"); + } + Entry entry = new Entry(type, serializer, name); + BY_TYPE.put(type, entry); + BY_NAME.put(name, entry); + } + + public static void init() { + BrigadierArgumentSerializers.init(); + ArgumentSerializers.register(new Identifier("minecraft:entity"), EntityArgument.class, + new EntityArgument.Serializer()); + ArgumentSerializers.register(new Identifier("minecraft:game_profile"), GameProfileArgument.class, + new EmptyArgumentSerializer(GameProfileArgument::gameProfiles)); + ArgumentSerializers.register(new Identifier("minecraft:block_pos"), BlockPosArgument.class, + new EmptyArgumentSerializer(BlockPosArgument::blockPos)); + ArgumentSerializers.register(new Identifier("minecraft:column_pos"), ColumnPosArgument.class, + new EmptyArgumentSerializer(ColumnPosArgument::columnPos)); + ArgumentSerializers.register(new Identifier("minecraft:vec3"), Vec3dArgument.class, + new EmptyArgumentSerializer(Vec3dArgument::vec3d)); + ArgumentSerializers.register(new Identifier("minecraft:vec2"), Vec2fArgument.class, + new EmptyArgumentSerializer(Vec2fArgument::vec2f)); + ArgumentSerializers.register(new Identifier("minecraft:block_state"), BlockArgument.class, + new EmptyArgumentSerializer(BlockArgument::block)); + ArgumentSerializers.register(new Identifier("minecraft:block_predicate"), BlockPredicateArgument.class, + new EmptyArgumentSerializer(BlockPredicateArgument::blockPredicate)); + ArgumentSerializers.register(new Identifier("minecraft:item_stack"), ItemArgument.class, + new EmptyArgumentSerializer(ItemArgument::item)); + ArgumentSerializers.register(new Identifier("minecraft:item_predicate"), ItemPredicateArgument.class, + new EmptyArgumentSerializer(ItemPredicateArgument::itemPredicate)); + ArgumentSerializers.register(new Identifier("minecraft:color"), ColorArgument.class, + new EmptyArgumentSerializer(ColorArgument::color)); + ArgumentSerializers.register(new Identifier("minecraft:component"), TextArgument.class, + new EmptyArgumentSerializer(TextArgument::text)); + ArgumentSerializers.register(new Identifier("minecraft:message"), MessageArgument.class, + new EmptyArgumentSerializer(MessageArgument::message)); + ArgumentSerializers.register(new Identifier("minecraft:nbt"), NbtCompoundArgument.class, + new EmptyArgumentSerializer(NbtCompoundArgument::nbtCompound)); + ArgumentSerializers.register(new Identifier("minecraft:nbt_path"), NbtPathArgument.class, + new EmptyArgumentSerializer(NbtPathArgument::nbtPath)); + ArgumentSerializers.register(new Identifier("minecraft:objective"), ObjectiveArgument.class, + new EmptyArgumentSerializer(ObjectiveArgument::objective)); + ArgumentSerializers.register(new Identifier("minecraft:objective_criteria"), ScoreboardCriterionArgument.class, + new EmptyArgumentSerializer(ScoreboardCriterionArgument::criterion)); + ArgumentSerializers.register(new Identifier("minecraft:operation"), OperationArgument.class, + new EmptyArgumentSerializer(OperationArgument::operation)); + ArgumentSerializers.register(new Identifier("minecraft:particle"), ParticleArgument.class, + new EmptyArgumentSerializer(ParticleArgument::particle)); + ArgumentSerializers.register(new Identifier("minecraft:rotation"), RotationArgument.class, + new EmptyArgumentSerializer(RotationArgument::rotation)); + ArgumentSerializers.register(new Identifier("minecraft:scoreboard_slot"), ScoreboardDisplaySlotArgument.class, + new EmptyArgumentSerializer(ScoreboardDisplaySlotArgument::displaySlot)); + ArgumentSerializers.register(new Identifier("minecraft:score_holder"), ScoreHolderArgument.class, + new ScoreHolderArgument.Serializer()); + ArgumentSerializers.register(new Identifier("minecraft:swizzle"), AxesArgument.class, + new EmptyArgumentSerializer(AxesArgument::axes)); + ArgumentSerializers.register(new Identifier("minecraft:team"), TeamArgument.class, + new EmptyArgumentSerializer(TeamArgument::team)); + ArgumentSerializers.register(new Identifier("minecraft:item_slot"), SlotArgument.class, + new EmptyArgumentSerializer(SlotArgument::slot)); + ArgumentSerializers.register(new Identifier("minecraft:resource_location"), IdentifierArgument.class, + new EmptyArgumentSerializer(IdentifierArgument::identifier)); + ArgumentSerializers.register(new Identifier("minecraft:mob_effect"), StatusEffectArgument.class, + new EmptyArgumentSerializer(StatusEffectArgument::effect)); + ArgumentSerializers.register(new Identifier("minecraft:function"), FunctionArgument.class, + new EmptyArgumentSerializer(FunctionArgument::functions)); + ArgumentSerializers.register(new Identifier("minecraft:entity_anchor"), AnchorArgument.class, + new EmptyArgumentSerializer(AnchorArgument::anchor)); + ArgumentSerializers.register(new Identifier("minecraft:int_range"), RangeArgument.Ints.class, + new RangeArgument.Ints.Serializer()); + ArgumentSerializers.register(new Identifier("minecraft:float_range"), RangeArgument.Floats.class, + new RangeArgument.Floats.Serializer()); + ArgumentSerializers.register(new Identifier("minecraft:item_enchantment"), EnchantmentArgument.class, + new EmptyArgumentSerializer(EnchantmentArgument::enchantment)); + ArgumentSerializers.register(new Identifier("minecraft:entity_summon"), EntitySummonArgument.class, + new EmptyArgumentSerializer(EntitySummonArgument::entity)); + ArgumentSerializers.register(new Identifier("minecraft:dimension"), DimensionTypeArgument.class, + new EmptyArgumentSerializer(DimensionTypeArgument::dimension)); + } + + @Nullable + private static Entry get(Identifier name) { + return BY_NAME.get(name); + } + + @Nullable + private static Entry get(ArgumentType argument) { + return BY_TYPE.get(argument.getClass()); + } + + public static > void serialize(PacketByteBuf buffer, T argument) { + Entry entry = ArgumentSerializers.get(argument); + if (entry == null) { + LOGGER.error("Could not serialize {} ({}) - will not be sent to client!", (Object) argument, + (Object) argument.getClass()); + buffer.writeIdentifier(new Identifier("")); + return; + } + buffer.writeIdentifier(entry.name); + entry.serializer.serialize(argument, buffer); + } + + @Nullable + public static ArgumentType deserialize(PacketByteBuf buffer) { + Identifier identifier = buffer.readIdentifier(); + Entry entry = ArgumentSerializers.get(identifier); + if (entry == null) { + LOGGER.error("Could not deserialize {}", (Object) identifier); + return null; + } + return entry.serializer.deserialize(buffer); + } + + private static > void serializeToJson(JsonObject json, T argument) { + Entry entry = ArgumentSerializers.get(argument); + if (entry == null) { + LOGGER.error("Could not serialize argument {} ({})!", (Object) argument, (Object) argument.getClass()); + json.addProperty("type", "unknown"); + } else { + json.addProperty("type", "argument"); + json.addProperty("parser", entry.name.toString()); + JsonObject jsonObject = new JsonObject(); + entry.serializer.serialize(argument, jsonObject); + if (jsonObject.size() > 0) { + json.add("properties", jsonObject); + } + } + } + + public static JsonObject serializeNodeToJson(CommandDispatcher dispatcher, CommandNode node) { + Collection collection; + JsonObject jsonObject = new JsonObject(); + if (node instanceof RootCommandNode) { + jsonObject.addProperty("type", "root"); + } else if (node instanceof LiteralCommandNode) { + jsonObject.addProperty("type", "literal"); + } else if (node instanceof ArgumentCommandNode) { + ArgumentSerializers.serializeToJson(jsonObject, ((ArgumentCommandNode) node).getType()); + } else { + LOGGER.error("Could not serialize node {} ({})!", (Object) node, (Object) node.getClass()); + jsonObject.addProperty("type", "unknown"); + } + JsonObject jsonObject2 = new JsonObject(); + for (CommandNode commandNode : node.getChildren()) { + jsonObject2.add(commandNode.getName(), ArgumentSerializers.serializeNodeToJson(dispatcher, commandNode)); + } + if (jsonObject2.size() > 0) { + jsonObject.add("children", jsonObject2); + } + if (node.getCommand() != null) { + jsonObject.addProperty("executable", true); + } + if (node.getRedirect() != null && !(collection = dispatcher.getPath(node.getRedirect())).isEmpty()) { + JsonArray jsonArray = new JsonArray(); + for (String string : collection) { + jsonArray.add(string); + } + jsonObject.add("redirect", jsonArray); + } + return jsonObject; + } + + static class Entry> { + public final Class type; + public final ArgumentSerializer serializer; + public final Identifier name; + + private Entry(Class type, ArgumentSerializer serializer, Identifier name) { + this.type = type; + this.serializer = serializer; + this.name = name; + } + } +*/} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/BrigadierArgumentSerializers.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/BrigadierArgumentSerializers.java new file mode 100644 index 00000000..d32768e4 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/BrigadierArgumentSerializers.java @@ -0,0 +1,37 @@ +package net.ornithemc.osl.commands.api.serdes; + +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.DoubleArgumentType; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; + +import net.minecraft.resource.Identifier; + +public class BrigadierArgumentSerializers { + + public static void init() { + /*ArgumentSerializers.register(new Identifier("brigadier:bool"), BoolArgumentType.class, new EmptyArgumentSerializer(BoolArgumentType::bool)); + ArgumentSerializers.register(new Identifier("brigadier:float"), FloatArgumentType.class, new FloatArgumentSerializer()); + ArgumentSerializers.register(new Identifier("brigadier:double"), DoubleArgumentType.class, new DoubleArgumentSerializer()); + ArgumentSerializers.register(new Identifier("brigadier:integer"), IntegerArgumentType.class, new IntegerArgumentSerializer()); + ArgumentSerializers.register(new Identifier("brigadier:string"), StringArgumentType.class, new StringArgumentSerializer());*/ + } + + public static byte minMaxFlags(boolean min, boolean max) { + byte flags = 0; + if (min) + flags = (byte)(flags | 1); + if (max) + flags = (byte)(flags | 2); + return flags; + } + + public static boolean hasMin(byte flags) { + return (flags & 1) != 0; + } + + public static boolean hasMax(byte flags) { + return (flags & 2) != 0; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/EmptyArgumentSerializer.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/EmptyArgumentSerializer.java new file mode 100644 index 00000000..c80eeec7 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/EmptyArgumentSerializer.java @@ -0,0 +1,25 @@ +package net.ornithemc.osl.commands.api.serdes; + +import java.util.function.Supplier; + +import com.mojang.brigadier.arguments.ArgumentType; + +import net.minecraft.network.PacketByteBuf; + +public class EmptyArgumentSerializer> implements ArgumentSerializer { + + private final Supplier constructor; + + public EmptyArgumentSerializer(Supplier constructor) { + this.constructor = constructor; + } + + @Override + public void serialize(T arg, PacketByteBuf buffer) { + } + + @Override + public T deserialize(PacketByteBuf buffer) { + return this.constructor.get(); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/FloatArgumentSerializer.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/FloatArgumentSerializer.java new file mode 100644 index 00000000..f479c095 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/serdes/FloatArgumentSerializer.java @@ -0,0 +1,29 @@ +package net.ornithemc.osl.commands.api.serdes; + +import com.mojang.brigadier.arguments.FloatArgumentType; + +import net.minecraft.network.PacketByteBuf; + +public class FloatArgumentSerializer implements ArgumentSerializer { + + @Override + public void serialize(FloatArgumentType floatArgumentType, PacketByteBuf packetByteBuf) { + boolean bl = floatArgumentType.getMinimum() != -3.4028235E38f; + boolean bl2 = floatArgumentType.getMaximum() != Float.MAX_VALUE; + packetByteBuf.writeByte(BrigadierArgumentSerializers.minMaxFlags(bl, bl2)); + if (bl) { + packetByteBuf.writeFloat(floatArgumentType.getMinimum()); + } + if (bl2) { + packetByteBuf.writeFloat(floatArgumentType.getMaximum()); + } + } + + @Override + public FloatArgumentType deserialize(PacketByteBuf buffer) { + byte b = buffer.readByte(); + float f = BrigadierArgumentSerializers.hasMin(b) ? buffer.readFloat() : -3.4028235E38f; + float g = BrigadierArgumentSerializers.hasMax(b) ? buffer.readFloat() : Float.MAX_VALUE; + return FloatArgumentType.floatArg(f, g); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/CommandSourceStack.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/CommandSourceStack.java new file mode 100644 index 00000000..4dd7c450 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/CommandSourceStack.java @@ -0,0 +1,183 @@ +package net.ornithemc.osl.commands.api.server; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.BinaryOperator; + +import com.mojang.brigadier.ResultConsumer; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.entity.Entity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Formatting; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.argument.AnchorArgument; + +public class CommandSourceStack extends AbstractCommandSourceStack { + + private final ServerWorld world; + private final MinecraftServer server; + + public CommandSourceStack(BrigadierCommandSource source, Vec3d pos, Vec2f rotation, ServerWorld world, int permissions, String name, Text displayName, MinecraftServer server, Entity entity) { + this(source, pos, rotation, world, permissions, name, displayName, server, entity, false, (ctx, success, result) -> { }, AnchorArgument.Anchor.FEET); + } + + public CommandSourceStack(BrigadierCommandSource source, Vec3d pos, Vec2f rotation, ServerWorld world, int permissions, String name, Text displayName, MinecraftServer server, Entity entity, boolean silent, ResultConsumer callback, AnchorArgument.Anchor anchor) { + super(source, pos, rotation, permissions, name, displayName, entity, silent, callback, anchor); + + this.world = world; + this.server = server; + } + + @Override + public CommandSourceStack withEntity(Entity entity) { + if (this.entity == entity) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, entity.getName(), entity.getDisplayName(), this.server, entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withPos(Vec3d pos) { + if (this.pos.equals(pos)) { + return this; + } + + return new CommandSourceStack(this.source, pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withRotation(Vec2f rotation) { + if (this.rotation.equals(rotation)) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, rotation, this.world, this.permissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withCallback(ResultConsumer callback) { + if (this.callback.equals(callback)) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.server, this.entity, this.silent, callback, this.anchor); + } + + @Override + public CommandSourceStack withCallback(ResultConsumer callback, BinaryOperator> chooser) { + return this.withCallback(chooser.apply(this.callback, callback)); + } + + @Override + public CommandSourceStack silent() { + if (this.silent) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.server, this.entity, true, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withPermissions(int permissions) { + if (permissions == this.permissions) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, permissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withMaxPermissions(int maxPermissions) { + if (maxPermissions <= this.permissions) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, maxPermissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withAnchor(AnchorArgument.Anchor anchor) { + if (anchor == this.anchor) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, this.world, this.permissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, anchor); + } + + public CommandSourceStack withWorld(ServerWorld world) { + if (world == this.world) { + return this; + } + + return new CommandSourceStack(this.source, this.pos, this.rotation, world, this.permissions, this.name, this.displayName, this.server, this.entity, this.silent, this.callback, this.anchor); + } + + @Override + public CommandSourceStack withFacing(Entity entity, AnchorArgument.Anchor anchor) throws CommandSyntaxException { + return this.withFacing(anchor.apply(entity)); + } + + @Override + public CommandSourceStack withFacing(Vec3d target) throws CommandSyntaxException { + Vec3d anchorPos = this.anchor.apply(this); + + double dx = target.x - anchorPos.x; + double dy = target.y - anchorPos.y; + double dz = target.z - anchorPos.z; + double squaredDistance = MathHelper.sqrt(dx * dx + dz * dz); + + float rotX = MathHelper.wrapDegrees((float)(-(MathHelper.fastAtan2(dy, squaredDistance) * 57.2957763671875))); + float rotY = MathHelper.wrapDegrees((float)(MathHelper.fastAtan2(dz, dx) * 57.2957763671875) - 90.0f); + + return this.withRotation(new Vec2f(rotX, rotY)); + } + + @Override + public ServerWorld getWorld() { + return this.world; + } + + public MinecraftServer getServer() { + return this.server; + } + + public void sendSuccess(Text message, boolean broadcastToOps) { + if (this.source.sendCommandSuccess() && !this.silent) { + this.source.sendMessage(message); + } + if (broadcastToOps && this.source.sendCommandSuccessToOps() && !this.silent) { + this.broadcastToOps(message); + } + } + + private void broadcastToOps(Text message) { + Text messageForOps = new TranslatableText("chat.type.admin", this.getDisplayName(), message).setStyle(new Style().setColor(Formatting.GRAY).setItalic(true)); + if (this.server.getSourceWorld().getGameRules().getBoolean("sendCommandFeedback")) { + for (ServerPlayerEntity serverPlayerEntity : this.server.getPlayerManager().getAll()) { + if (serverPlayerEntity != this.source && this.server.getPlayerManager().isOp(serverPlayerEntity.getGameProfile())) { + serverPlayerEntity.sendMessage(messageForOps); + } + } + } + if (this.source != this.server && this.server.getSourceWorld().getGameRules().getBoolean("logAdminCommands")) { + this.server.sendMessage(messageForOps); + } + } + + @Override + public Collection getPlayerNames() { + return Arrays.asList(this.server.getPlayerNames()); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/ServerCommandManager.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/ServerCommandManager.java new file mode 100644 index 00000000..5feb6dc6 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/api/server/ServerCommandManager.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.commands.api.server; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; + +import net.ornithemc.osl.commands.impl.server.ServerCommandManagerImpl; + +public class ServerCommandManager { + + public static CommandDispatcher getDispatcher() { + return ServerCommandManagerImpl.getDispatcher(); + } + + public static LiteralArgumentBuilder literal(String name) { + return LiteralArgumentBuilder.literal(name); + } + + public static RequiredArgumentBuilder argument(String name, ArgumentType type) { + return RequiredArgumentBuilder.argument(name, type); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/BrigadierCommandManagerImpl.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/BrigadierCommandManagerImpl.java new file mode 100644 index 00000000..8c7106d9 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/BrigadierCommandManagerImpl.java @@ -0,0 +1,88 @@ +package net.ornithemc.osl.commands.impl; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.BuiltInExceptionProvider; +import com.mojang.brigadier.exceptions.CommandExceptionType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.text.ClickEvent; +import net.minecraft.text.Formatting; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.profiler.Profiler; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; + +public class BrigadierCommandManagerImpl { + + public static > Integer run(CommandDispatcher dispatcher, S source, String command, Profiler profiler, boolean force) { + StringReader reader = new StringReader(command); + if (reader.canRead() && reader.peek() == '/') { + reader.skip(); + } + profiler.push(command); + try { + return dispatcher.execute(reader, source); + } catch (CommandSyntaxException e) { + if (!force && shouldIgnore(e.getType())) { + return null; + } + if (e.getRawMessage() instanceof Text) { + source.sendFailure((Text)e.getRawMessage()); + } else { + source.sendFailure(new LiteralText(e.getRawMessage().getString())); + } + if (e.getInput() != null && e.getCursor() >= 0) { + Text message = new LiteralText("") + .setStyle(new Style() + .setColor(Formatting.GRAY) + .setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command))); + int cursor = Math.min(e.getInput().length(), e.getCursor()); + if (cursor > 10) { + message.append("..."); + } + message.append(e.getInput().substring(Math.max(0, cursor - 10), cursor)); + if (cursor < e.getInput().length()) { + message.append(new LiteralText(e.getInput().substring(cursor)) + .setStyle(new Style() + .setColor(Formatting.RED) + .setUnderlined(true))); + } + message.append(new TranslatableText("command.context.here") + .setStyle(new Style() + .setColor(Formatting.RED) + .setItalic(true))); + source.sendFailure(message); + } + return 0; + } catch (Exception e) { + LiteralText message = new LiteralText(e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + /*if (LOGGER.isDebugEnabled()) { + StackTraceElement[] stackTrace = e.getStackTrace(); + for (StackTraceElement element : stackTrace) { + message + .append("\n\n") + .append(element.getMethodName()) + .append("\n ") + .append(element.getFileName()) + .append(":") + .append(String.valueOf(element.getLineNumber())); + } + }*/ + source.sendFailure(new TranslatableText("command.failed") + .setStyle(new Style().setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, message)))); + return 0; + } finally { + profiler.pop(); + } + } + + private static boolean shouldIgnore(CommandExceptionType type) { + BuiltInExceptionProvider exceptions = CommandSyntaxException.BUILT_IN_EXCEPTIONS; + return type == exceptions.dispatcherUnknownCommand() || type == exceptions.dispatcherParseException(); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java new file mode 100644 index 00000000..d4e72caa --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java @@ -0,0 +1,75 @@ +package net.ornithemc.osl.commands.impl.client; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.client.Minecraft; +import net.minecraft.server.command.source.CommandSource; + +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.CommandEvents; +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.impl.BrigadierCommandManagerImpl; + +public class ClientCommandManagerImpl { + + private static final Logger LOGGER = LogManager.getLogger(); + + private static Minecraft minecraft; + private static CommandDispatcher dispatcher; + + public static void setUp(Minecraft minecraft) { + if (ClientCommandManagerImpl.minecraft != null) { + throw new IllegalStateException("tried to set up client command manager while it was already set up!"); + } + + ClientCommandManagerImpl.minecraft = minecraft; + ClientCommandManagerImpl.dispatcher = new CommandDispatcher<>(); + + ClientCommandManagerImpl.init(); + } + + private static void init() { + CommandEvents.REGISTER_CLIENT_BRIGADIER_COMMANDS.invoker().accept(dispatcher); + + dispatcher.findAmbiguities((root, node1, node2, inputs) -> LOGGER.warn("Ambiguity between arguments {} and {} with inputs: {}", dispatcher.getPath(node1), dispatcher.getPath(node2), inputs)); + dispatcher.setConsumer((ctx, success, result) -> ctx.getSource().onCommandComplete(ctx, success, result)); + } + + public static void destroy(Minecraft minecraft) { + if (ClientCommandManagerImpl.minecraft == null) { + throw new IllegalStateException("tried to destroy client command manager while it was not set up!"); + } + + ClientCommandManagerImpl.minecraft = null; + ClientCommandManagerImpl.dispatcher = null; + } + + public static CommandDispatcher getDispatcher() { + return dispatcher; + } + + public static boolean run(String command) { + return run(minecraft.player, command); + } + + public static boolean run(CommandSource commandSource, String command) { + if (dispatcher == null || !(commandSource instanceof BrigadierCommandSource)) { + return false; + } + + BrigadierCommandSource brigadierSource = (BrigadierCommandSource)commandSource; + ClientCommandSourceStack source = (ClientCommandSourceStack)brigadierSource.createCommandSourceStack(); + + return BrigadierCommandManagerImpl.run(dispatcher, source, command, minecraft.profiler, false) != null; + } + + public static int run(ClientCommandSourceStack source, String command) { + if (dispatcher == null) { + throw new IllegalStateException("cannot run client commands because the command dispatcher is not set up!"); + } + return BrigadierCommandManagerImpl.run(dispatcher, source, command, minecraft.profiler, true); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java new file mode 100644 index 00000000..f66ded9a --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.commands.impl.client; + +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; + +public class ClientCommandsInitializer implements ClientModInitializer { + + @Override + public void initClient() { + ClientConnectionEvents.LOGIN.register(minecraft -> { + ClientCommandManagerImpl.setUp(minecraft); + }); + ClientConnectionEvents.DISCONNECT.register(minecraft -> { + ClientCommandManagerImpl.destroy(minecraft); + }); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IWorld.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IWorld.java new file mode 100644 index 00000000..232715c0 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IWorld.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.commands.impl.interfaces.mixin; + +import net.minecraft.util.math.BlockPos; + +public interface IWorld { + + boolean osl$commands$contains(BlockPos pos); + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java new file mode 100644 index 00000000..f2115cea --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.commands.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.entity.living.player.LocalClientPlayerEntity; + +import net.ornithemc.osl.commands.impl.client.ClientCommandManagerImpl; + +@Mixin(LocalClientPlayerEntity.class) +public class LocalClientPlayerEntityMixin { + + @Inject( + method = "sendChat", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$commands$runClientCommand(String message, CallbackInfo ci) { + if (ClientCommandManagerImpl.run(message)) { + ci.cancel(); + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java new file mode 100644 index 00000000..759fac53 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.handler.CommandManager; +import net.minecraft.server.command.handler.CommandRegistry; + +import net.ornithemc.osl.commands.api.CommandEvents; + +@Mixin(CommandManager.class) +public abstract class CommandManagerMixin extends CommandRegistry { + + @Inject( + method="", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/command/Command;setListener(Lnet/minecraft/server/command/handler/CommandListener;)V" + ) + ) + private void registerCommands(MinecraftServer server, CallbackInfo ci) { + CommandEvents.REGISTER_SERVER_COMMANDS.invoker().accept(server, this::register); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandRegistryMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandRegistryMixin.java new file mode 100644 index 00000000..9a45d32f --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandRegistryMixin.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.server.command.handler.CommandRegistry; +import net.minecraft.server.command.source.CommandSource; + +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; +import net.ornithemc.osl.commands.impl.server.ServerCommandManagerImpl; + +@Mixin(CommandRegistry.class) +public class CommandRegistryMixin { + + @Inject( + method = "run(Lnet/minecraft/server/command/source/CommandSource;Ljava/lang/String;)I", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$commands$runBrigadierCommand(CommandSource source, String command, CallbackInfoReturnable cir) { + if (source instanceof BrigadierCommandSource) { + CommandSourceStack brigadierSource = (CommandSourceStack)((BrigadierCommandSource)source).createCommandSourceStack(); + Integer result = ServerCommandManagerImpl.run(brigadierSource, command); + + if (result != null) { + cir.setReturnValue(result); + } + } + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/EntityMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/EntityMixin.java new file mode 100644 index 00000000..dbb32175 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/EntityMixin.java @@ -0,0 +1,51 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import net.ornithemc.osl.commands.api.AbstractCommandSourceStack; +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; + +@Mixin(Entity.class) +public abstract class EntityMixin implements BrigadierCommandSource { + + @Shadow private World world; + @Shadow private double x; + @Shadow private double y; + @Shadow private double z; + @Shadow private float pitch; + @Shadow private float yaw; + + @Override + public AbstractCommandSourceStack createCommandSourceStack() { + if (world.isClient) { + return new ClientCommandSourceStack(this, new Vec3d(this.x, this.y, this.z), new Vec2f(this.pitch, this.yaw), (ClientWorld)this.world, 0, this.getName(), this.getDisplayName(), (Entity)(Object)this); + } else { + return new CommandSourceStack(this, new Vec3d(this.x, this.y, this.z), new Vec2f(this.pitch, this.yaw), (ServerWorld)this.world, 0, this.getName(), this.getDisplayName(), this.world.getServer(), (Entity)(Object)this); + } + } + + @Override + public boolean sendCommandSuccess() { + return true; + } + + @Override + public boolean sendCommandFailure() { + return true; + } + + @Override + public boolean sendCommandSuccessToOps() { + return true; + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/TextMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/TextMixin.java new file mode 100644 index 00000000..642347f6 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/TextMixin.java @@ -0,0 +1,19 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.mojang.brigadier.Message; + +import net.minecraft.text.Text; + +@Mixin(Text.class) +public interface TextMixin extends Message { + + @Shadow String buildString(); + + @Override + default String getString() { + return buildString(); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/WorldMixin.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/WorldMixin.java new file mode 100644 index 00000000..725211f5 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/WorldMixin.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import net.ornithemc.osl.commands.impl.interfaces.mixin.IWorld; + +@Mixin(World.class) +public class WorldMixin implements IWorld { + + @Shadow private boolean contains(BlockPos pos) { return false; } + + @Override + public boolean osl$commands$contains(BlockPos pos) { + return contains(pos); + } + +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandManagerImpl.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandManagerImpl.java new file mode 100644 index 00000000..f9525310 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandManagerImpl.java @@ -0,0 +1,71 @@ +package net.ornithemc.osl.commands.impl.server; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.source.CommandSource; + +import net.ornithemc.osl.commands.api.BrigadierCommandSource; +import net.ornithemc.osl.commands.api.CommandEvents; +import net.ornithemc.osl.commands.api.server.CommandSourceStack; +import net.ornithemc.osl.commands.impl.BrigadierCommandManagerImpl; + +public class ServerCommandManagerImpl { + + private static final Logger LOGGER = LogManager.getLogger(); + + private static MinecraftServer server; + private static CommandDispatcher dispatcher; + + public static void setUp(MinecraftServer server) { + if (ServerCommandManagerImpl.server != null) { + throw new IllegalStateException("tried to set up server command manager while it was already set up!"); + } + + ServerCommandManagerImpl.server = server; + ServerCommandManagerImpl.dispatcher = new CommandDispatcher<>(); + + ServerCommandManagerImpl.init(); + } + + private static void init() { + CommandEvents.REGISTER_SERVER_BRIGADIER_COMMANDS.invoker().accept(dispatcher); + + dispatcher.findAmbiguities((root, node1, node2, inputs) -> LOGGER.warn("Ambiguity between arguments {} and {} with inputs: {}", dispatcher.getPath(node1), dispatcher.getPath(node2), inputs)); + dispatcher.setConsumer((ctx, success, result) -> ctx.getSource().onCommandComplete(ctx, success, result)); + } + + public static void destroy(MinecraftServer server) { + if (ServerCommandManagerImpl.server == null) { + throw new IllegalStateException("tried to destroy server command manager while it was not set up!"); + } + + ServerCommandManagerImpl.server = null; + ServerCommandManagerImpl.dispatcher = null; + } + + public static CommandDispatcher getDispatcher() { + return dispatcher; + } + + public static boolean run(CommandSource commandSource, String command) { + if (dispatcher == null || !(commandSource instanceof BrigadierCommandSource)) { + return false; + } + + BrigadierCommandSource brigadierSource = (BrigadierCommandSource)commandSource; + CommandSourceStack source = (CommandSourceStack)brigadierSource.createCommandSourceStack(); + + return BrigadierCommandManagerImpl.run(dispatcher, source, command, server.profiler, false) != null; + } + + public static int run(CommandSourceStack source, String command) { + if (dispatcher == null) { + throw new IllegalStateException("cannot run server commands because the command dispatcher is not set up!"); + } + return BrigadierCommandManagerImpl.run(dispatcher, source, command, server.profiler, true); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandsInitializer.java b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandsInitializer.java new file mode 100644 index 00000000..81173357 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/java/net/ornithemc/osl/commands/impl/server/ServerCommandsInitializer.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.commands.impl.server; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; + +public class ServerCommandsInitializer implements ModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(server -> { + ServerCommandManagerImpl.setUp(server); + }); + MinecraftServerEvents.STOP.register(server -> { + ServerCommandManagerImpl.destroy(server); + }); + } +} diff --git a/libraries/commands/commands-mc1.12-mc1.12.2/src/main/resources/osl.commands.mixins.json b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/resources/osl.commands.mixins.json new file mode 100644 index 00000000..2076cbb7 --- /dev/null +++ b/libraries/commands/commands-mc1.12-mc1.12.2/src/main/resources/osl.commands.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.commands.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.CommandManagerMixin", + "common.CommandRegistryMixin", + "common.EntityMixin", + "common.TextMixin", + "common.WorldMixin" + ], + "client": [ + "client.LocalClientPlayerEntityMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/build.gradle b/libraries/commands/commands-mc17w45a-mc1.13.2/build.gradle new file mode 100644 index 00000000..f03df10a --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/build.gradle @@ -0,0 +1,4 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.13.2', + 'networking-mc18w31a-mc1.13.2' +) diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/gradle.properties b/libraries/commands/commands-mc17w45a-mc1.13.2/gradle.properties new file mode 100644 index 00000000..f7ea2466 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/gradle.properties @@ -0,0 +1,6 @@ +environment = * +min_mc_version = 17w45a +max_mc_version = 1.13.2 +mc_version_range = >=1.13-alpha.17.45.a <=1.13.2 + +feather_build = 16 diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java new file mode 100644 index 00000000..665d6ea6 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/CommandEvents.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.commands.api; + +import java.util.function.Consumer; + +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.server.command.source.CommandSourceStack; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.core.api.events.Event; + +public class CommandEvents { + + public static final Event>> REGISTER_CLIENT_COMMANDS = Event.consumer(); + public static final Event>> REGISTER_SERVER_COMMANDS = Event.consumer(); + +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java new file mode 100644 index 00000000..7dea1a92 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandManager.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.commands.api.client; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; + +import net.ornithemc.osl.commands.impl.client.ClientCommandManagerImpl; + +public class ClientCommandManager { + + public static CommandDispatcher getDispatcher() { + return ClientCommandManagerImpl.getDispatcher(); + } + + public static LiteralArgumentBuilder literal(String name) { + return LiteralArgumentBuilder.literal(name); + } + + public static RequiredArgumentBuilder argument(String name, ArgumentType type) { + return RequiredArgumentBuilder.argument(name, type); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java new file mode 100644 index 00000000..bd1145b1 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/api/client/ClientCommandSourceStack.java @@ -0,0 +1,264 @@ +package net.ornithemc.osl.commands.api.client; + +import com.mojang.brigadier.ResultConsumer; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BinaryOperator; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.living.player.ClientPlayerEntity; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.command.SuggestionProvider; +import net.minecraft.command.argument.AnchorArgument; +import net.minecraft.command.argument.AnchorArgument.Anchor; +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.player.PlayerEntity; +import net.minecraft.resource.Identifier; +import net.minecraft.server.command.source.CommandSource; +import net.minecraft.server.command.source.CommandSourceStack; +import net.minecraft.text.Formatting; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.registry.Registry; + +import net.ornithemc.osl.commands.impl.interfaces.mixin.IAnchor; + +public class ClientCommandSourceStack implements SuggestionProvider { + + private final CommandSource source; + private final Vec3d pos; + private final ClientWorld world; + private final int permissions; + private final String name; + private final Text displayName; + private final Minecraft minecraft; + private final boolean silent; + private final Entity entity; + private final ResultConsumer callback; + private final Anchor anchor; + private final Vec2f rotation; + + public ClientCommandSourceStack(CommandSource source, Vec3d pos, Vec2f rotation, int permissions, String name, Text displayName, Entity entity) { + this(source, pos, rotation, permissions, name, displayName, entity, false, (ctx, success, result) -> { }, AnchorArgument.Anchor.FEET); + } + + protected ClientCommandSourceStack(CommandSource source, Vec3d pos, Vec2f rotation, int permissions, String name, Text displayName, Entity entity, boolean silent, ResultConsumer callback, Anchor anchor) { + Minecraft minecraft = Minecraft.getInstance(); + + this.source = source; + this.pos = pos; + this.world = minecraft.world; + this.silent = silent; + this.entity = entity; + this.permissions = permissions; + this.name = name; + this.displayName = displayName; + this.minecraft = minecraft; + this.callback = callback; + this.anchor = anchor; + this.rotation = rotation; + } + + public ClientCommandSourceStack withEntity(Entity entity) { + if (this.entity == entity) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.permissions, entity.getName().getString(), entity.getDisplayName(), entity, this.silent, this.callback, this.anchor); + } + + public ClientCommandSourceStack withPos(Vec3d pos) { + if (this.pos.equals(pos)) { + return this; + } + + return new ClientCommandSourceStack(this.source, pos, this.rotation, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + public ClientCommandSourceStack withRotation(Vec2f rotation) { + if (this.rotation.equals(rotation)) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, rotation, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + public ClientCommandSourceStack withCallback(ResultConsumer callback) { + if (this.callback.equals(callback)) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.permissions, this.name, this.displayName, this.entity, this.silent, callback, this.anchor); + } + + public ClientCommandSourceStack withCallback(ResultConsumer callback, BinaryOperator> chooser) { + return this.withCallback(chooser.apply(this.callback, callback)); + } + + public ClientCommandSourceStack silent() { + if (this.silent) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.permissions, this.name, this.displayName, this.entity, true, this.callback, this.anchor); + } + + public ClientCommandSourceStack withPermissions(int permissions) { + if (permissions == this.permissions) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, permissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + public ClientCommandSourceStack withMaxPermissions(int maxPermissions) { + if (maxPermissions <= this.permissions) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, maxPermissions, this.name, this.displayName, this.entity, this.silent, this.callback, this.anchor); + } + + public ClientCommandSourceStack withAnchor(Anchor anchor) { + if (anchor == this.anchor) { + return this; + } + + return new ClientCommandSourceStack(this.source, this.pos, this.rotation, this.permissions, this.name, this.displayName, this.entity, this.silent, this.callback, anchor); + } + + public ClientCommandSourceStack withFacing(Entity entity, Anchor anchor) throws CommandSyntaxException { + return this.withFacing(anchor.apply(entity)); + } + + public ClientCommandSourceStack withFacing(Vec3d target) throws CommandSyntaxException { + IAnchor anchor = (IAnchor)(Object)this.anchor; + Vec3d anchorPos = anchor.osl$commands$apply(this); + + double dx = target.x - anchorPos.x; + double dy = target.y - anchorPos.y; + double dz = target.z - anchorPos.z; + double squaredDistance = MathHelper.sqrt(dx * dx + dz * dz); + + float rotX = MathHelper.wrapDegrees((float)(-(MathHelper.fastAtan2(dy, squaredDistance) * 57.2957763671875))); + float rotY = MathHelper.wrapDegrees((float)(MathHelper.fastAtan2(dz, dx) * 57.2957763671875) - 90.0f); + + return this.withRotation(new Vec2f(rotX, rotY)); + } + + public Text getDisplayName() { + return this.displayName; + } + + public String getName() { + return this.name; + } + + @Override + public boolean hasPermissions(int permissions) { + return this.permissions >= permissions; + } + + public Vec3d getPos() { + return this.pos; + } + + public ClientWorld getWorld() { + return this.world; + } + + public Entity getEntity() { + return this.entity; + } + + public Entity getEntityOrThrow() throws CommandSyntaxException { + if (this.entity == null) { + throw CommandSourceStack.NOT_ENTITY_EXCEPTION.create(); + } + + return this.entity; + } + + public ClientPlayerEntity getPlayerOrThrow() throws CommandSyntaxException { + if (!(this.entity instanceof ClientPlayerEntity)) { + throw CommandSourceStack.NOT_PLAYER_EXCEPTION.create(); + } + + return (ClientPlayerEntity)this.entity; + } + + public Vec2f getRotation() { + return this.rotation; + } + + public Minecraft getMinecraft() { + return this.minecraft; + } + + public Anchor getAnchor() { + return this.anchor; + } + + public void sendSuccess(Text message) { + if (this.source.sendCommandSuccess() && !this.silent) { + this.source.sendMessage(message); + } + } + + public void sendFailure(Text message) { + if (this.source.sendCommandFailure() && !this.silent) { + this.source.sendMessage(new LiteralText("").append(message).setFormatting(Formatting.RED)); + } + } + + public void onCommandComplete(CommandContext ctx, boolean success, int result) { + if (this.callback != null) { + this.callback.onCommandComplete(ctx, success, result); + } + } + + @Override + public Collection getPlayerNames() { + List names = new ArrayList<>(); + for (PlayerEntity player : this.world.players) { + names.add(player.getGameProfile().getName()); + } + return names; + } + + @Override + public Collection getTeams() { + return this.world.getScoreboard().getTeamNames(); + } + + @Override + public Collection getAvailableSounds() { + return Registry.SOUND_EVENT.keySet(); + } + + @Override + public Collection getAvailableRecipes() { + return this.world.getCraftingManager().getLocations(); + } + + @Override + public CompletableFuture suggest(CommandContext ctx, SuggestionsBuilder builder) { + return null; + } + + @Override + public Collection getCoordinates(boolean absolute) { + return Collections.singleton(Coordinate.DEFAULT_GLOBAL); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java new file mode 100644 index 00000000..70fd88b3 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandManagerImpl.java @@ -0,0 +1,139 @@ +package net.ornithemc.osl.commands.impl.client; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.BuiltInExceptionProvider; +import com.mojang.brigadier.exceptions.CommandExceptionType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.client.Minecraft; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.Formatting; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TextUtils; +import net.minecraft.text.TranslatableText; + +import net.ornithemc.osl.commands.api.CommandEvents; +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.impl.interfaces.mixin.IEntity; + +public class ClientCommandManagerImpl { + + private static final Logger LOGGER = LogManager.getLogger(); + + private static Minecraft minecraft; + private static CommandDispatcher dispatcher; + + public static void setUp(Minecraft minecraft) { + if (ClientCommandManagerImpl.minecraft != null) { + throw new IllegalStateException("tried to set up client command manager while it was already set up!"); + } + + ClientCommandManagerImpl.minecraft = minecraft; + ClientCommandManagerImpl.dispatcher = new CommandDispatcher<>(); + + ClientCommandManagerImpl.init(); + } + + private static void init() { + CommandEvents.REGISTER_CLIENT_COMMANDS.invoker().accept(dispatcher); + + dispatcher.findAmbiguities((root, node1, node2, inputs) -> LOGGER.warn("Ambiguity between arguments {} and {} with inputs: {}", dispatcher.getPath(node1), dispatcher.getPath(node2), inputs)); + dispatcher.setConsumer((ctx, success, result) -> ctx.getSource().onCommandComplete(ctx, success, result)); + } + + public static void destroy(Minecraft minecraft) { + if (ClientCommandManagerImpl.minecraft == null) { + throw new IllegalStateException("tried to destroy client command manager while it was not set up!"); + } + + ClientCommandManagerImpl.minecraft = null; + ClientCommandManagerImpl.dispatcher = null; + } + + public static CommandDispatcher getDispatcher() { + return dispatcher; + } + + public static boolean run(String command) { + if (dispatcher == null || minecraft.player == null) { + return false; + } + + IEntity player = (IEntity)minecraft.player; + ClientCommandSourceStack source = player.osl$commands$createClientCommandSourceStack(); + + return ClientCommandManagerImpl.run(source, command, false) != null; + } + + public static int run(ClientCommandSourceStack source, String command) { + return run(source, command, true); + } + + private static Integer run(ClientCommandSourceStack source, String command, boolean force) { + if (dispatcher == null) { + throw new IllegalStateException("cannot run client commands because the command dispatcher is not set up!"); + } + StringReader reader = new StringReader(command); + if (reader.canRead() && reader.peek() == '/') { + reader.skip(); + } + minecraft.profiler.push(command); + try { + return dispatcher.execute(reader, source); + } catch (CommandSyntaxException e) { + if (!force && shouldIgnore(e.getType())) { + return null; + } + source.sendFailure(TextUtils.fromMessage(e.getRawMessage())); + if (e.getInput() != null && e.getCursor() >= 0) { + Text message = new LiteralText("") + .withStyle(style -> style + .setColor(Formatting.GRAY) + .setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command))); + int cursor = Math.min(e.getInput().length(), e.getCursor()); + if (cursor > 10) { + message.append("..."); + } + message.append(e.getInput().substring(Math.max(0, cursor - 10), cursor)); + if (cursor < e.getInput().length()) { + message.append(new LiteralText(e.getInput().substring(cursor)) + .setFormatting(Formatting.RED, Formatting.UNDERLINE)); + } + message.append(new TranslatableText("command.context.here").setFormatting(Formatting.RED, + Formatting.ITALIC)); + source.sendFailure(message); + } + return 0; + } catch (Exception e) { + LiteralText message = new LiteralText(e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + if (LOGGER.isDebugEnabled()) { + StackTraceElement[] stackTrace = e.getStackTrace(); + for (StackTraceElement element : stackTrace) { + message + .append("\n\n") + .append(element.getMethodName()) + .append("\n ") + .append(element.getFileName()) + .append(":") + .append(String.valueOf(element.getLineNumber())); + } + } + source.sendFailure(new TranslatableText("command.failed") + .withStyle(style -> style.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, message)))); + return 0; + } finally { + minecraft.profiler.pop(); + } + } + + private static boolean shouldIgnore(CommandExceptionType type) { + BuiltInExceptionProvider exceptions = CommandSyntaxException.BUILT_IN_EXCEPTIONS; + return type == exceptions.dispatcherUnknownCommand() || type == exceptions.dispatcherParseException(); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java new file mode 100644 index 00000000..f66ded9a --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ClientCommandsInitializer.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.commands.impl.client; + +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; + +public class ClientCommandsInitializer implements ClientModInitializer { + + @Override + public void initClient() { + ClientConnectionEvents.LOGIN.register(minecraft -> { + ClientCommandManagerImpl.setUp(minecraft); + }); + ClientConnectionEvents.DISCONNECT.register(minecraft -> { + ClientCommandManagerImpl.destroy(minecraft); + }); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ServerCommandsInitializer.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ServerCommandsInitializer.java new file mode 100644 index 00000000..07190522 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/client/ServerCommandsInitializer.java @@ -0,0 +1,10 @@ +package net.ornithemc.osl.commands.impl.client; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; + +public class ServerCommandsInitializer implements ModInitializer { + + @Override + public void init() { + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IAnchor.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IAnchor.java new file mode 100644 index 00000000..2d028f5d --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IAnchor.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.commands.impl.interfaces.mixin; + +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; + +public interface IAnchor { + + Vec3d osl$commands$apply(ClientCommandSourceStack source); + +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IEntity.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IEntity.java new file mode 100644 index 00000000..fd00c677 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/interfaces/mixin/IEntity.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.commands.impl.interfaces.mixin; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; + +public interface IEntity { + + ClientCommandSourceStack osl$commands$createClientCommandSourceStack(); + +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/AnchorMixin.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/AnchorMixin.java new file mode 100644 index 00000000..a46f07e3 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/AnchorMixin.java @@ -0,0 +1,29 @@ +package net.ornithemc.osl.commands.impl.mixin.client; + +import java.util.function.BiFunction; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.command.argument.AnchorArgument.Anchor; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Vec3d; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.impl.interfaces.mixin.IAnchor; + +@Mixin(Anchor.class) +public class AnchorMixin implements IAnchor { + + @Shadow @Final private BiFunction transform; + + @Override + public Vec3d osl$commands$apply(ClientCommandSourceStack source) { + Entity entity = source.getEntity(); + if (entity == null) { + return source.getPos(); + } + return this.transform.apply(source.getPos(), entity); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/EntityMixin.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/EntityMixin.java new file mode 100644 index 00000000..d45262e4 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/EntityMixin.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.commands.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.source.CommandSource; +import net.minecraft.text.Text; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import net.ornithemc.osl.commands.api.client.ClientCommandSourceStack; +import net.ornithemc.osl.commands.impl.interfaces.mixin.IEntity; + +@Mixin(Entity.class) +public abstract class EntityMixin implements CommandSource, IEntity { + + @Shadow private World world; + @Shadow private double x; + @Shadow private double y; + @Shadow private double z; + + @Shadow private Vec2f getRotation() { return null; } + + @Shadow private int getPermissions() { return 0; } + + @Shadow private Text getName() { return null; } + + @Shadow private Text getDisplayName() { return null; } + + @Override + public ClientCommandSourceStack osl$commands$createClientCommandSourceStack() { + if (!(world instanceof ClientWorld)) { + throw new IllegalStateException("cannot create a client command source stack on the server!"); + } + + return new ClientCommandSourceStack(this, new Vec3d(x, y, z), getRotation(), getPermissions(), getName().getString(), getDisplayName(), (Entity)(Object)this); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java new file mode 100644 index 00000000..f2115cea --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/client/LocalClientPlayerEntityMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.commands.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.entity.living.player.LocalClientPlayerEntity; + +import net.ornithemc.osl.commands.impl.client.ClientCommandManagerImpl; + +@Mixin(LocalClientPlayerEntity.class) +public class LocalClientPlayerEntityMixin { + + @Inject( + method = "sendChat", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$commands$runClientCommand(String message, CallbackInfo ci) { + if (ClientCommandManagerImpl.run(message)) { + ci.cancel(); + } + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java new file mode 100644 index 00000000..53c6c5cb --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/java/net/ornithemc/osl/commands/impl/mixin/common/CommandManagerMixin.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.commands.impl.mixin.common; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.server.command.handler.CommandManager; +import net.minecraft.server.command.source.CommandSourceStack; + +import net.ornithemc.osl.commands.api.CommandEvents; + +@Mixin(CommandManager.class) +public class CommandManagerMixin { + + @Shadow @Final private CommandDispatcher dispatcher; + + @Inject( + method="", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/brigadier/CommandDispatcher;findAmbiguities(Lcom/mojang/brigadier/AmbiguityConsumer;)V" + ) + ) + private void registerCommands(boolean isDedicatedServer, CallbackInfo ci) { + CommandEvents.REGISTER_SERVER_COMMANDS.invoker().accept(dispatcher); + } +} diff --git a/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/resources/osl.commands.mixins.json b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/resources/osl.commands.mixins.json new file mode 100644 index 00000000..124dfb32 --- /dev/null +++ b/libraries/commands/commands-mc17w45a-mc1.13.2/src/main/resources/osl.commands.mixins.json @@ -0,0 +1,19 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.commands.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.CommandManagerMixin" + ], + "client": [ + "client.AnchorMixin", + "client.EntityMixin", + "client.LocalClientPlayerEntityMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/commands/gradle.properties b/libraries/commands/gradle.properties new file mode 100644 index 00000000..dc89c1bb --- /dev/null +++ b/libraries/commands/gradle.properties @@ -0,0 +1,2 @@ +version = 0.1.0 +archives_base_name = commands diff --git a/libraries/commands/src/main/resources/assets/ornithe-standard-libraries/commands/icon.png b/libraries/commands/src/main/resources/assets/ornithe-standard-libraries/commands/icon.png new file mode 100644 index 00000000..ef588531 Binary files /dev/null and b/libraries/commands/src/main/resources/assets/ornithe-standard-libraries/commands/icon.png differ diff --git a/libraries/commands/src/main/resources/fabric.mod.json b/libraries/commands/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..8b8e43d4 --- /dev/null +++ b/libraries/commands/src/main/resources/fabric.mod.json @@ -0,0 +1,38 @@ +{ + "schemaVersion": 1, + "id": "osl-commands", + "version": "${version}", + "name": "Commands", + "description": "An API for creating and registering Minecraft commands.", + "authors": [ + "OrnitheMC", + "Space Walker" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0", + "icon": "assets/ornithe-standard-libraries/commands/icon.png", + "environment": "${environment}", + "entrypoints": { + "init": [ + "net.ornithemc.osl.commands.impl.server.ServerCommandsInitializer" + ], + "client-init": [ + "net.ornithemc.osl.commands.impl.client.ClientCommandsInitializer" + ] + }, + "mixins": [ + "osl.commands.mixins.json" + ], + "depends": { + "fabricloader": ">=0.14.21", + "minecraft": "${mc_version_range}", + "osl-core": ">=0.4.0", + "osl-entrypoints": ">=0.2.0", + "osl-lifecycle-events": ">=0.4.0", + "osl-networking": ">=0.4.0" + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java index 51aa26f5..89f17697 100644 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java @@ -1,7 +1,17 @@ package net.ornithemc.osl.resource.loader.api; +import net.minecraft.resource.Identifier; + public class ResourceUtils { + public static boolean isValidChar(char chr) { + return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'z') || chr == '_' || chr == ':' || chr == '/' || chr == '.' || chr == '-'; + } + + public static boolean isValidIdentifier(Identifier id) { + return isValidNamespace(id.getNamespace()) && isValidPath(id.getPath()); + } + public static boolean isValidNamespace(String namespace) { return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z')); } diff --git a/settings.gradle b/settings.gradle index ab71cb02..b9f4ce85 100644 --- a/settings.gradle +++ b/settings.gradle @@ -32,6 +32,10 @@ include ':libraries:branding:branding-mc1.7.10-pre3-mc1.7.10' include ':libraries:branding:branding-mc14w02a-mc14w29b' include ':libraries:branding:branding-mc14w30a-mc16w05a' +include ':libraries:commands' +include ':libraries:commands:commands-mc1.12-mc1.12.2' +include ':libraries:commands:commands-mc17w45a-mc1.13.2' + include ':libraries:config' include ':libraries:config:config-mc1.3-pre-07261249-mc1.5.2' include ':libraries:config:config-mc13w16a-04192037-mc1.6.4'