Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crack Villager RNG. #643

Draft
wants to merge 17 commits into
base: fabric
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ dependencies {
includedLibrary "com.seedfinding:mc_core:${project.seedfinding_core_version}"
includedLibrary "com.seedfinding:mc_seed:${project.seedfinding_seed_version}"

includedLibrary "com.seedfinding:latticg:${project.latticg_version}:rt"
codeGenImplementation "com.seedfinding:latticg:${project.latticg_version}"
includedLibrary "com.seedfinding:latticg:${project.latticg_version}"

compileOnly 'com.demonwav.mcdev:annotations:2.0.0'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ public static void registerCommands(CommandDispatcher<FabricClientCommandSource>
WeatherCommand.register(dispatcher);
WhisperEncryptedCommand.register(dispatcher);
WikiCommand.register(dispatcher);
CrackVillagerRNGCommand.register(dispatcher, context);

Calendar calendar = Calendar.getInstance();
boolean registerChatCommand = calendar.get(Calendar.MONTH) == Calendar.APRIL && calendar.get(Calendar.DAY_OF_MONTH) == 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package net.earthcomputer.clientcommands.command;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.earthcomputer.clientcommands.features.CCrackVillager;
import net.earthcomputer.clientcommands.features.VillagerRNGSim;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.arguments.item.ItemInput;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;

import java.util.function.Predicate;
import java.util.function.Supplier;

import static net.earthcomputer.clientcommands.command.arguments.DynamicIntegerArgument.integer;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
import static dev.xpple.clientarguments.arguments.CBlockPosArgument.*;
import static net.earthcomputer.clientcommands.command.arguments.CombinedArgument.*;
import static net.earthcomputer.clientcommands.command.arguments.EnchantmentArgument.*;
import static net.earthcomputer.clientcommands.command.arguments.DynamicIntegerArgument.*;
import static net.earthcomputer.clientcommands.command.arguments.WithStringArgument.*;

import static net.earthcomputer.clientcommands.command.arguments.CachedItemArgument.item;

public class CrackVillagerRNGCommand {
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandBuildContext context) {
dispatcher.register(literal("ccrackvillager")
.then(literal("cancel")
.executes(ctx -> cancel(ctx.getSource())))
.then(literal("clock")
.then(argument("clockpos", blockPos())
.executes(ctx -> crackVillagerRNG(ctx.getSource(), getBlockPos(ctx, "clockpos")))))
.then(literal("interval")
.then(argument("ticks", IntegerArgumentType.integer(0, 20))
.executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks")))))
.then(literal("add-goal")
.then(genFirst(context))
.then(genSecond(context))
.then(genResult(context)))
.then(literal("list-goals")
.executes(CrackVillagerRNGCommand::listGoals))
.then(literal("remove-goal")
.then(argument("index", integer(1,CCrackVillager.goalOffers::size))
.executes(CrackVillagerRNGCommand::removeGoal)))
.then(literal("clear-goals").executes(CrackVillagerRNGCommand::clearGoals))
.then(literal("run").executes(CrackVillagerRNGCommand::doRun)));
}

private static int doRun(CommandContext<FabricClientCommandSource> context) {
CCrackVillager.findingOffers = true;
if(CCrackVillager.goalOffers.isEmpty()) {
context.getSource().sendFeedback(Component.translatable("commands.ccrackvillager.emptyGoals"));
}
return Command.SINGLE_SUCCESS;
}

private static int clearGoals(CommandContext<FabricClientCommandSource> context) {
CCrackVillager.goalOffers.clear();
return Command.SINGLE_SUCCESS;
}

private static int removeGoal(CommandContext<FabricClientCommandSource> context) {
context.getSource().sendFeedback(Component.translatable("commands.ccrackvillager.removeGoal", CCrackVillager.goalOffers.remove(getInteger(context, "index") - 1)));
return Command.SINGLE_SUCCESS;
}

private static int listGoals(CommandContext<FabricClientCommandSource> context) {
for(var i = 0; i < CCrackVillager.goalOffers.size(); i++) {
var offer = CCrackVillager.goalOffers.get(i);
context.getSource().sendFeedback(Component.translatable("commands.ccrackvillager.listGoal", i + 1, offer));
}
return Command.SINGLE_SUCCESS;
}

private static int crackVillagerRNG(FabricClientCommandSource source, BlockPos pos) throws CommandSyntaxException {
CCrackVillager.clockPos = pos;
VillagerRNGSim.commandSource = source;
CCrackVillager.crackVillager(source.getPlayer(), seed -> {
source.sendFeedback(Component.translatable("commands.ccrackvillager.success", Long.toHexString(seed)));
});
return Command.SINGLE_SUCCESS;
}

private static int cancel(FabricClientCommandSource source) {
CCrackVillager.cancel();
CCrackVillager.findingOffers = false;
source.sendFeedback(Component.translatable("commands.ccrackvillager.cancel"));
return Command.SINGLE_SUCCESS;
}

private static int setInterval(FabricClientCommandSource source, int interval) throws CommandSyntaxException {
CCrackVillager.setInterval(interval);
return Command.SINGLE_SUCCESS;
}

private static Combined<Predicate<ItemStack>, String> createPredicate(CommandContext<FabricClientCommandSource> context, String argName) {
try {
Result<Combined<ItemInput, Combined<Integer, Integer>>> result = getWithString(context, argName, null);
var combined = result.value();
var item = combined.first().getItem();
var min = combined.second().first();
var max = combined.second().second();
return new Combined<>((stack) -> stack.is(item)
&& ((min > item.getDefaultMaxStackSize() || min <= stack.getCount())
&& (max > item.getDefaultMaxStackSize() || stack.getCount() <= max)),
result.string().replaceAll("\\* \\*","*").replaceAll("([\\d*]+) ([\\d*]+)$", "$1-$2"));
} catch (IllegalArgumentException ignored) { }
return null;
}

private static int setGoal(CommandContext<FabricClientCommandSource> context) {
CCrackVillager.Offer offer = new CCrackVillager.Offer();

var combined = createPredicate(context, "firstitem");
if(combined != null) offer.withFirst(combined.first(), combined.second());
combined = createPredicate(context, "seconditem");
if(combined != null) offer.withSecond(combined.first(), combined.second());
combined = createPredicate(context, "resultitem");
if(combined != null) offer.withResult(combined.first(), combined.second());

try {
Result<Combined<Enchantment, Integer>> result2 = getWithString(context, "enchantment", null);
var enchantment = result2.value().first();
offer.andEnchantment((stack) -> {
var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(stack);
var level = enchantments.getLevel(enchantment);
return (result2.value().second() > enchantment.getMaxLevel() && level > 0) || result2.value().second() == level;
}, result2.string());
} catch (IllegalArgumentException ignored) { }

context.getSource().sendFeedback(Component.literal((CCrackVillager.goalOffers.size()+1) + ": " + offer));

CCrackVillager.goalOffers.add(offer);

return Command.SINGLE_SUCCESS;
}



static LiteralArgumentBuilder<FabricClientCommandSource> genFirst(CommandBuildContext context) {
var item = item(context);
Supplier<Integer> supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize();
return literal("first")
.then(argument("firstitem", withString(combined(item, combined(integer(1, supplier).allowAny(), integer(1, supplier).allowAny()))))
.executes(CrackVillagerRNGCommand::setGoal)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, so a valid goal can be a first item with no specific result or anything else set?

.then(genSecond(context)) .then(genResult(context)));
}

static LiteralArgumentBuilder<FabricClientCommandSource> genSecond(CommandBuildContext context) {
var item = item(context);
Supplier<Integer> supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize();
return literal("second")
.then(argument("seconditem", withString(combined(item, combined(integer(1, supplier).allowAny(), integer(1, supplier).allowAny()))))
.executes(CrackVillagerRNGCommand::setGoal) .then(genResult(context)));
}

static LiteralArgumentBuilder<FabricClientCommandSource> genResult(CommandBuildContext context) {
var enchantment = enchantment();
var item = item(context);
Supplier<Integer> supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize();
return literal("result")
.then(argument("resultitem", withString(combined(item, combined(integer(1, supplier).allowAny(), integer(1, supplier).allowAny()))))
.executes(CrackVillagerRNGCommand::setGoal) .then(literal("enchant")
.then(argument("enchantment", withString(combined(enchantment, integer(() -> enchantment.lastParsed.getMaxLevel()).allowAny())))
.executes(CrackVillagerRNGCommand::setGoal))));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package net.earthcomputer.clientcommands.command.arguments;

import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.earthcomputer.clientcommands.command.CrackVillagerRNGCommand;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.arguments.item.ItemArgument;
import net.minecraft.commands.arguments.item.ItemInput;

public class CachedItemArgument extends ItemArgument {
public ItemInput lastItem;

public CachedItemArgument(CommandBuildContext context) {
super(context);
}

public static CachedItemArgument item(CommandBuildContext context) {
return new CachedItemArgument(context);
}

public static <S> ItemInput getItem(CommandContext<S> context, String name) {
return context.getArgument(name, ItemInput.class);
}

@Override
public ItemInput parse(StringReader reader) throws CommandSyntaxException {
return lastItem = super.parse(reader);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package net.earthcomputer.clientcommands.command.arguments;

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.network.chat.Component;

import java.util.concurrent.CompletableFuture;

public class CombinedArgument<A, B> implements ArgumentType<CombinedArgument.Combined<A, B>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this required?

ArgumentType<A> firstArgument;
ArgumentType<B> secondArgument;
private static final SimpleCommandExceptionType TOO_FEW_ARGUMENTS_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.client.tooFewArguments"));

private CombinedArgument(ArgumentType<A> first, ArgumentType<B> second) {
firstArgument = first;
secondArgument = second;
}

public static <A, B> CombinedArgument<A, B> combined(ArgumentType<A> first, ArgumentType<B> second) {
return new CombinedArgument<>(first, second);
}

public static <A, B, S> Combined<A, B> getCombined(CommandContext<S> context, String name) {
return context.getArgument(name, Combined.class);
}

@Override
public Combined<A, B> parse(StringReader reader) throws CommandSyntaxException {
A first = firstArgument.parse(reader);
if(!reader.canRead()) throw TOO_FEW_ARGUMENTS_EXCEPTION.create();
reader.expect(' ');
if(!reader.canRead()) throw TOO_FEW_ARGUMENTS_EXCEPTION.create();
B second = secondArgument.parse(reader);
return new Combined<>(first, second);
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
StringReader reader = new StringReader(builder.getInput());
reader.setCursor(builder.getStart());
int readAmount = 0;
int cursor = reader.getCursor();
try {
if(reader.canRead()) {
firstArgument.parse(reader);
if(reader.canRead()) {
reader.expect(' ');
readAmount++;
cursor = reader.getCursor();
secondArgument.parse(reader);
}
}
} catch (CommandSyntaxException ignored) {
}
if(readAmount == 0) {
return firstArgument.listSuggestions(context, builder.createOffset(cursor));
} else {
return secondArgument.listSuggestions(context, builder.createOffset(cursor));
}
}

public record Combined<A, B>(A first, B second) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package net.earthcomputer.clientcommands.command.arguments;

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 java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

public class DynamicIntegerArgument implements ArgumentType<Integer> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need this just use CRangeArgument and predicate if the range is valid from the stack's max size, also if you were to need it, use MinMaxBounds.Ints

Supplier<Integer> low;
Supplier<Integer> high;
boolean allowAny = false;

DynamicIntegerArgument(Supplier<Integer> low, Supplier<Integer> high) {
this.low = low;
this.high = high;
}

public DynamicIntegerArgument allowAny() {
allowAny = true;
return this;
}

public static <S> int getInteger(CommandContext<S> context, String name) {
return context.getArgument(name, int.class);
}

public static DynamicIntegerArgument integer(Supplier<Integer> low, Supplier<Integer> high) {
return new DynamicIntegerArgument(low, high);
}

public static DynamicIntegerArgument integer(int low, Supplier<Integer> high) {
return integer(() -> low, high);
}
public static DynamicIntegerArgument integer(Supplier<Integer> low, int high) {
return integer(low, () -> high);
}

public static DynamicIntegerArgument integer(Supplier<Integer> limit) {
return integer(0, limit);
}

@Override
public Integer parse(final StringReader reader) throws CommandSyntaxException {
final int start = reader.getCursor();
if (allowAny && reader.canRead() && reader.peek() == '*') {
reader.read();
return Integer.MAX_VALUE;
}
final int result = reader.readInt();

var min = low.get();
var max = high.get();

if (result < min) {
reader.setCursor(start);
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooLow().createWithContext(reader, result, min);
}
if (result > max) {
reader.setCursor(start);
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooHigh().createWithContext(reader, result, max);
}
return result;
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
if (allowAny) {
builder.suggest("*");
}
return builder.buildFuture();
}
}
Loading