From f936e9128b8cf492a13fea77695c8eca87cbabde Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 1 Jun 2024 01:21:39 +0800 Subject: [PATCH 01/16] crack Villager RNG. have bugs in simulator. using DynamicProgram so need to change build.gradle --- build.gradle | 2 +- .../clientcommands/ClientCommands.java | 1 + .../command/CrackVillagerRNGCommand.java | 48 +++++++ .../features/CCrackVillager.java | 119 +++++++++++++++++ .../clientcommands/features/Measurement.java | 121 ++++++++++++++++++ .../features/VillagerRNGSim.java | 59 +++++++++ .../rngevents/ClientPacketListenerMixin.java | 12 ++ .../assets/clientcommands/lang/en_us.json | 6 + 8 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/features/Measurement.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java diff --git a/build.gradle b/build.gradle index ff2dd8d8..68fb8234 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ dependencies { includedLibrary "com.seedfinding:mc_seed:${project.seedfinding_seed_version}" includedLibrary "com.seedfinding:latticg:${project.latticg_version}:rt" - codeGenImplementation "com.seedfinding:latticg:${project.latticg_version}" + implementation "com.seedfinding:latticg:${project.latticg_version}" compileOnly 'com.demonwav.mcdev:annotations:2.0.0' diff --git a/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java b/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java index 830978ac..dae2f97c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java +++ b/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java @@ -171,6 +171,7 @@ public static void registerCommands(CommandDispatcher WeatherCommand.register(dispatcher); WhisperEncryptedCommand.register(dispatcher); WikiCommand.register(dispatcher); + CrackVillagerRNGCommand.register(dispatcher); Calendar calendar = Calendar.getInstance(); boolean registerChatCommand = calendar.get(Calendar.MONTH) == Calendar.APRIL && calendar.get(Calendar.DAY_OF_MONTH) == 1; diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java new file mode 100644 index 00000000..dcc0febc --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -0,0 +1,48 @@ +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.exceptions.CommandSyntaxException; +import net.earthcomputer.clientcommands.Configs; +import net.earthcomputer.clientcommands.features.CCrackVillager; +import net.earthcomputer.clientcommands.features.PlayerRandCracker; +import net.earthcomputer.clientcommands.features.ServerBrandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.network.chat.Component; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class CrackVillagerRNGCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(literal("ccrackvillager") + .executes(ctx -> crackVillagerRNG(ctx.getSource())) + .then(literal("cancel") + .executes(ctx -> cancel(ctx.getSource()))) + .then(literal("interval") + .then(argument("interval0", IntegerArgumentType.integer(20, 100)) + .executes(ctx -> crackWithInterval(ctx.getSource(), IntegerArgumentType.getInteger(ctx, "interval0")))))); + } + + private static int crackVillagerRNG(FabricClientCommandSource source) throws CommandSyntaxException { + ServerBrandManager.rngWarning(); + CCrackVillager.crackVillager(source.getPlayer(), seed -> { + source.sendFeedback(Component.translatable("commands.ccrackvillager.success", Long.toHexString(seed))); + PlayerRandCracker.setSeed(seed); + Configs.playerCrackState = PlayerRandCracker.CrackState.CRACKED; + }); + return Command.SINGLE_SUCCESS; + } + + private static int cancel(FabricClientCommandSource source) { + CCrackVillager.cancel(); + source.sendFeedback(Component.translatable("commands.ccrackvillager.cancel")); + return Command.SINGLE_SUCCESS; + } + + private static int crackWithInterval(FabricClientCommandSource source, int interval) throws CommandSyntaxException { + CCrackVillager.setInterval(interval); + return crackVillagerRNG(source); + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java new file mode 100644 index 00000000..0f0632f9 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -0,0 +1,119 @@ +package net.earthcomputer.clientcommands.features; + +import com.seedfinding.latticg.reversal.DynamicProgram; +import com.seedfinding.latticg.util.LCG; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.entity.ai.targeting.TargetingConditions; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.level.block.Blocks; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class CCrackVillager { + + public static WeakReference targetVillager = null; + + static Consumer onCrackFinished; + + static List measurements = new ArrayList<>(); + static boolean cracked = false; + static int validMeasures = 0; + static boolean cracking = false; + static int interval = 22; + + public static void cancel() { + targetVillager = null; + } + + public static void setInterval(int i) { + interval = i; + } + + public static void onAmethyst(ClientboundSoundPacket packet) { + Villager villager; + if(targetVillager != null && (villager = targetVillager.get()) != null) { + if(villager.distanceToSqr(packet.getX(), packet.getY(), packet.getZ()) < 1.0) { + if(cracked) { + VillagerRNGSim.onAmethyst(packet); + } else { + new Thread(() -> crack(packet)).start(); + } + } + } + } + + public static void onAmbient() { + if(!cracked && validMeasures > 0) { + measurements.add(Measurement.skip(2)); + } else if(cracked){ + VillagerRNGSim.onAmbient(); + } + } + + static void crack(ClientboundSoundPacket packet) { + var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); + var nextFloat = (packet.getPitch() - 0.5f) / lastChimeIntensity1_2; + if(validMeasures > 0) + measurements.add(Measurement.skip(interval * 2)); // 2 random call every ticks + + measurements.add(Measurement.nextFloat(nextFloat, 0.0015f)); + validMeasures++; + + if(validMeasures > 6 && !cracking) { + cracking = true; + var cachedMeasurements = new ArrayList<>(measurements); + DynamicProgram program = DynamicProgram.create(new LCG(25214903917L, 11, 1L<<48)); + for(var measurement : cachedMeasurements) + measurement.apply(program); + var seeds = program.reverse().toArray(); + if(seeds.length == 1) { + cracked = true; + reset(); + VillagerRNGSim.setSeed(seeds[0]); + for(var measurement : cachedMeasurements) { + measurement.apply(VillagerRNGSim.random); + } + onCrackFinished.accept(VillagerRNGSim.getSeed()); + } else { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.fail"), false); + reset(); + } + cracking = false; + } + } + + public static void crackVillager(LocalPlayer player, Consumer callback) { + var world = player.getCommandSenderWorld(); + var villagers = world.getNearbyEntities(Villager.class, TargetingConditions.forNonCombat().selector( + (villager -> villager.getBlockStateOn().is(Blocks.AMETHYST_BLOCK)) + ), player, player.getBoundingBox().deflate(30)); + if(!villagers.isEmpty()) { + Villager target = null; + double distance = 100; + for(var villager : villagers) { + var tmpDistance = villager.distanceToSqr(player); + if(tmpDistance < distance) { + target = villager; + distance = tmpDistance; + } + } + if(target != null) { + targetVillager = new WeakReference<>(target); + onCrackFinished = callback; + reset(); + cracked = false; + } + } + } + + static void reset() { + measurements.clear(); + validMeasures = 0; + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/features/Measurement.java b/src/main/java/net/earthcomputer/clientcommands/features/Measurement.java new file mode 100644 index 00000000..3342269d --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/features/Measurement.java @@ -0,0 +1,121 @@ +package net.earthcomputer.clientcommands.features; + +import com.seedfinding.latticg.reversal.DynamicProgram; +import com.seedfinding.latticg.reversal.calltype.CallType; +import com.seedfinding.latticg.reversal.calltype.java.JavaCalls; +import com.seedfinding.latticg.util.Range; +import net.minecraft.util.RandomSource; + + +public abstract class Measurement { + public abstract void apply(DynamicProgram program); + + public abstract void apply(RandomSource random); + + public static Measurement nextFloat(float value) { + return new FloatMeasurement(value); + } + + public static Measurement nextFloat(float value, float range) { + return new FloatRangedMeasurement(value, range); + } + + public static Measurement skip() { + return skip(1); + } + + public static Measurement skip(int count) { + return new SkipMeasurement(count); + } + + public static Measurement nextInt(int bound, int value) { + return new IntMeasurement(bound, value); + } + + static class SkipMeasurement extends Measurement { + int count; + SkipMeasurement(int count) { + this.count = count; + } + + @Override + public void apply(DynamicProgram program) { + program.skip(count); + } + + @Override + public void apply(RandomSource random) { + for(var i = 0; i < count; i++) { + random.nextFloat(); + } + } + } + + static class FloatMeasurement extends Measurement { + float value; + + static CallType> callType = JavaCalls.nextFloat().ranged(0.04f); + + FloatMeasurement(float value) { + this.value = value; + } + + CallType> getCallType() { + return callType; + } + + float getRange() { + return 0.02f; + } + + @Override + public void apply(DynamicProgram program) { + program.add(getCallType(), Range.of(value-getRange(), value+getRange())); + } + + @Override + public void apply(RandomSource random) { + random.nextFloat(); + } + } + + static class FloatRangedMeasurement extends FloatMeasurement { + float range; + + FloatRangedMeasurement(float value, float range) { + super(value); + this.range = range; + } + + @Override + CallType> getCallType() { + return JavaCalls.nextFloat().ranged(this.range * 2f); + } + + @Override + public float getRange() { + return range; + } + } + + static class IntMeasurement extends Measurement { + CallType callType; + int bound; + int value; + IntMeasurement(int bound, int value) { + this.value = value; + this.bound = bound; + callType = JavaCalls.nextInt(bound); + } + + @Override + public void apply(DynamicProgram program) { + program.add(callType, this.value); + } + + @Override + public void apply(RandomSource random) { + random.nextInt(bound); + } + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java new file mode 100644 index 00000000..d05a80fa --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -0,0 +1,59 @@ +package net.earthcomputer.clientcommands.features; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.level.levelgen.LegacyRandomSource; + +public class VillagerRNGSim { + public static LegacyRandomSource random = new LegacyRandomSource(0); + + static int errorCount = 0; + static long lastAmbient = 0; + static boolean lastAmbientCracked = false; + + public static void onAmethyst(ClientboundSoundPacket packet) { + var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); + var nextFloat = (packet.getPitch() - 0.5f) / lastChimeIntensity1_2; + for(var i = 0; i < CCrackVillager.interval; i++) { + random.nextFloat(); + random.nextFloat(); + } + var maxRetry = 100; + int i; + for(i = 0; i < maxRetry; i++) { + float predicted = random.nextFloat(); + if(Math.abs(nextFloat - predicted) < 0.0001) { + break; + } + if(i == maxRetry-1) { + errorCount++; + if(errorCount > 6) { + errorCount = 0; + CCrackVillager.cracked = false; + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintainFail"), false); + } + return; + } + } + errorCount = 0; + if(i < 2) + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintain"), false); + } + + public static void onAmbient() { + if(!lastAmbientCracked) { + lastAmbientCracked = true; + lastAmbient = -80; + } + } + + public static long getSeed() { + return random.seed.get(); + } + + public static void setSeed(long seed) { + random.setSeed(seed ^ 25214903917L); + lastAmbientCracked = false; + } +} \ No newline at end of file diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java index cd0ff704..c109d39b 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java @@ -1,8 +1,11 @@ package net.earthcomputer.clientcommands.mixin.rngevents; import com.mojang.brigadier.StringReader; +import net.earthcomputer.clientcommands.features.CCrackVillager; import net.earthcomputer.clientcommands.features.PlayerRandCracker; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.sounds.SoundEvents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -18,4 +21,13 @@ private void onSendCommand(String command, CallbackInfo ci) { PlayerRandCracker.onGiveCommand(); } } + + @Inject(method = "handleSoundEvent", at = @At("TAIL")) + private void onSoundEvent(ClientboundSoundPacket packet, CallbackInfo ci) { + if(packet.getSound().is(SoundEvents.AMETHYST_BLOCK_CHIME.getLocation())) { + CCrackVillager.onAmethyst(packet); + } else if (packet.getSound().is(SoundEvents.VILLAGER_AMBIENT.getLocation())) { + CCrackVillager.onAmbient(); + } + } } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index ec1169c1..f71e52fe 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -263,6 +263,12 @@ "commands.client.requiresRestart": "This change will take effect after you restart your client", "commands.client.tooFewArguments": "Too few arguments", + "commands.ccrackvillager.fail": "Crack Fail, retrying...", + "commands.ccrackvillager.success": "Villager RNG cracked: %d", + "commands.ccrackvillager.maintain": "Villager RNG maintain success", + "commands.ccrackvillager.cancel": "Crack RNG cancelled", + "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", + "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", "chorusManip.goalTooFar": "Goal is too far away!", From fa4692d49878c4ee07b463a2c1a7606e0882cfb2 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 1 Jun 2024 15:54:36 +0800 Subject: [PATCH 02/16] able to predict offers now --- .../command/CrackVillagerRNGCommand.java | 23 ++- .../features/CCrackVillager.java | 25 ++- .../features/VillagerRNGSim.java | 168 ++++++++++++++---- .../rngevents/ClientPacketListenerMixin.java | 24 ++- .../rngevents/MultiPlayerGameModeMixin.java | 10 ++ .../assets/clientcommands/lang/en_us.json | 1 + 6 files changed, 202 insertions(+), 49 deletions(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index dcc0febc..e5749df2 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -9,24 +9,31 @@ import net.earthcomputer.clientcommands.features.PlayerRandCracker; import net.earthcomputer.clientcommands.features.ServerBrandManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; 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 com.mojang.brigadier.arguments.IntegerArgumentType.*; public class CrackVillagerRNGCommand { public static void register(CommandDispatcher dispatcher) { dispatcher.register(literal("ccrackvillager") - .executes(ctx -> crackVillagerRNG(ctx.getSource())) .then(literal("cancel") .executes(ctx -> cancel(ctx.getSource()))) - .then(literal("interval") - .then(argument("interval0", IntegerArgumentType.integer(20, 100)) - .executes(ctx -> crackWithInterval(ctx.getSource(), IntegerArgumentType.getInteger(ctx, "interval0")))))); + .then(literal("clock") + .then(argument("clockpos", blockPos()) + .executes(ctx -> crackVillagerRNG(ctx.getSource(), getBlockPos(ctx, "clockpos"))) + .then(literal("interval") + .then(argument("ticks", integer(20, 100)) + .executes(ctx -> crackWithInterval(ctx.getSource(), getBlockPos(ctx, "clockpos"), getInteger(ctx, "ticks")))))) + )); } - private static int crackVillagerRNG(FabricClientCommandSource source) throws CommandSyntaxException { - ServerBrandManager.rngWarning(); + private static int crackVillagerRNG(FabricClientCommandSource source, BlockPos pos) throws CommandSyntaxException { + CCrackVillager.clockPos = pos; CCrackVillager.crackVillager(source.getPlayer(), seed -> { source.sendFeedback(Component.translatable("commands.ccrackvillager.success", Long.toHexString(seed))); PlayerRandCracker.setSeed(seed); @@ -41,8 +48,8 @@ private static int cancel(FabricClientCommandSource source) { return Command.SINGLE_SUCCESS; } - private static int crackWithInterval(FabricClientCommandSource source, int interval) throws CommandSyntaxException { + private static int crackWithInterval(FabricClientCommandSource source, BlockPos pos, int interval) throws CommandSyntaxException { CCrackVillager.setInterval(interval); - return crackVillagerRNG(source); + return crackVillagerRNG(source, pos); } } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index 0f0632f9..c58bcc48 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -4,6 +4,7 @@ import com.seedfinding.latticg.util.LCG; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.world.entity.ai.targeting.TargetingConditions; @@ -26,6 +27,7 @@ public class CCrackVillager { static int validMeasures = 0; static boolean cracking = false; static int interval = 22; + public static BlockPos clockPos; public static void cancel() { targetVillager = null; @@ -35,12 +37,19 @@ public static void setInterval(int i) { interval = i; } + public static void onClockUpdate() { + VillagerRNGSim.INSTANCE.onTick(); + if(!cracked && validMeasures > 0) { + measurements.add(Measurement.skip(2)); + } + } + public static void onAmethyst(ClientboundSoundPacket packet) { Villager villager; if(targetVillager != null && (villager = targetVillager.get()) != null) { if(villager.distanceToSqr(packet.getX(), packet.getY(), packet.getZ()) < 1.0) { if(cracked) { - VillagerRNGSim.onAmethyst(packet); + VillagerRNGSim.INSTANCE.onAmethyst(packet); } else { new Thread(() -> crack(packet)).start(); } @@ -49,18 +58,17 @@ public static void onAmethyst(ClientboundSoundPacket packet) { } public static void onAmbient() { + VillagerRNGSim.INSTANCE.onAmbient(); if(!cracked && validMeasures > 0) { measurements.add(Measurement.skip(2)); - } else if(cracked){ - VillagerRNGSim.onAmbient(); } } static void crack(ClientboundSoundPacket packet) { var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); var nextFloat = (packet.getPitch() - 0.5f) / lastChimeIntensity1_2; - if(validMeasures > 0) - measurements.add(Measurement.skip(interval * 2)); // 2 random call every ticks + //if(validMeasures > 0) + // measurements.add(Measurement.skip(interval * 2)); // 2 random call every ticks measurements.add(Measurement.nextFloat(nextFloat, 0.0015f)); validMeasures++; @@ -75,11 +83,11 @@ static void crack(ClientboundSoundPacket packet) { if(seeds.length == 1) { cracked = true; reset(); - VillagerRNGSim.setSeed(seeds[0]); + VillagerRNGSim.INSTANCE.setSeed(seeds[0]); for(var measurement : cachedMeasurements) { - measurement.apply(VillagerRNGSim.random); + measurement.apply(VillagerRNGSim.INSTANCE.random); } - onCrackFinished.accept(VillagerRNGSim.getSeed()); + onCrackFinished.accept(VillagerRNGSim.INSTANCE.getSeed()); } else { Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.fail"), false); reset(); @@ -108,6 +116,7 @@ public static void crackVillager(LocalPlayer player, Consumer callback) { onCrackFinished = callback; reset(); cracked = false; + VillagerRNGSim.INSTANCE.lastAmbientCracked = false; } } } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index d05a80fa..9fa0659d 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -1,59 +1,167 @@ package net.earthcomputer.clientcommands.features; +import com.google.common.collect.Lists; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.levelgen.LegacyRandomSource; public class VillagerRNGSim { - public static LegacyRandomSource random = new LegacyRandomSource(0); + public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); + + LegacyRandomSource random = new LegacyRandomSource(0); - static int errorCount = 0; - static long lastAmbient = 0; - static boolean lastAmbientCracked = false; + int errorCount = 0; + long lastAmbient = 0; + boolean lastAmbientCracked = false; + boolean justAmbient = false; + long lastAmethyst = 0; + int ticksToWait = 0; - public static void onAmethyst(ClientboundSoundPacket packet) { + + public void onAmethyst(ClientboundSoundPacket packet) { var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); var nextFloat = (packet.getPitch() - 0.5f) / lastChimeIntensity1_2; - for(var i = 0; i < CCrackVillager.interval; i++) { - random.nextFloat(); - random.nextFloat(); + + var forSync = clone(); + var ticks = 0; + var predicted = forSync.random.nextFloat(); + while(Math.abs(nextFloat - predicted) > 0.0001 && ticks++ < 30) { + predicted = forSync.random.nextFloat(); } - var maxRetry = 100; - int i; - for(i = 0; i < maxRetry; i++) { - float predicted = random.nextFloat(); - if(Math.abs(nextFloat - predicted) < 0.0001) { - break; + + if(ticks < 30) { + setSeed(forSync.getSeed()); + justAmbient = forSync.justAmbient; + lastAmbient = forSync.lastAmbient; + ticksToWait = forSync.ticksToWait; + lastAmethyst = forSync.lastAmethyst; + errorCount = 0; + if(ticks == 0) { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); + } else { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintain"), false); } - if(i == maxRetry-1) { - errorCount++; - if(errorCount > 6) { - errorCount = 0; - CCrackVillager.cracked = false; - Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintainFail"), false); - } - return; + Minecraft.getInstance().gui.overlayMessageTime = 20; + } else { + ticksToWait = 10; + errorCount++; + Minecraft.getInstance().gui.overlayMessageTime = 0; + if(errorCount > 4) { + errorCount = 0; + CCrackVillager.cracked = false; + lastAmbientCracked = false; + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintainFail"), false); } } - errorCount = 0; - if(i < 2) - Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintain"), false); + } - public static void onAmbient() { + public void onAmbient() { if(!lastAmbientCracked) { - lastAmbientCracked = true; + if(!CCrackVillager.cracked) return; + lastAmbient = -80; + random.nextFloat(); + random.nextFloat(); + justAmbient = true; + } + + if(justAmbient) return; + + var forSync = clone(); + var ticks = 0; + while(!forSync.justAmbient) { + ticks++; + forSync.onTick(); + } + + if(ticks < 30) { + setSeed(forSync.getSeed()); + justAmbient = forSync.justAmbient; + lastAmbient = forSync.lastAmbient; + ticksToWait = forSync.ticksToWait; + lastAmethyst = forSync.lastAmethyst;; + } else { + ticksToWait = 10; } } - public static long getSeed() { + public long getSeed() { return random.seed.get(); } - public static void setSeed(long seed) { + public void setSeed(long seed) { random.setSeed(seed ^ 25214903917L); - lastAmbientCracked = false; + } + + public void onTick() { + if(ticksToWait-- > 0) { + return; + } + if(random.nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { + random.nextFloat(); + random.nextFloat(); + lastAmbient = -80; + lastAmbientCracked = true; + justAmbient = true; + } else { + justAmbient = false; + } + random.nextInt(100); + } + + public void onOfferTrades() { + var chat = Minecraft.getInstance().gui.getChat(); + chat.addMessage(Component.literal("client pre-trade: " + Long.toHexString(getSeed()))); + + var villager = CCrackVillager.targetVillager.get(); + if(villager == null) return; + var map = VillagerTrades.TRADES.get(villager.getVillagerData().getProfession()); + if(map == null || map.isEmpty()) return; + var items = map.get(villager.getVillagerData().getLevel()); + if(items == null) return; + var offers = new MerchantOffers(); + var itemList = Lists.newArrayList(items); + var i = 0; + while (i < 2) { + MerchantOffer offer = itemList.remove(this.random.nextInt(itemList.size())).getOffer(villager, this.random); + if (offer == null) continue; + offers.add(offer); + ++i; + var first = offer.getCostA(); + var second = offer.getCostB(); + var result = offer.getResult(); + var offerString = "%dx %s".formatted(first.getCount(), first.getHoverName().getString()); + if(!second.isEmpty()) { + offerString += " + %dx %s".formatted(second.getCount(), second.getDisplayName().getString()); + } + offerString += " => %dx %s".formatted(result.getCount(), result.getHoverName().getString()); + if(result.is(Items.ENCHANTED_BOOK)) { + var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(result); + var enchantment = enchantments.keySet().iterator().next().value(); + offerString += " with %s".formatted(enchantment.getFullname(EnchantmentHelper.getItemEnchantmentLevel(enchantment, result))); + } + chat.addMessage(Component.literal(offerString)); + } + chat.addMessage(Component.literal("client post-trade: " + Long.toHexString(getSeed()))); + + } + + @Override + public VillagerRNGSim clone() { + var result = new VillagerRNGSim(); + result.setSeed(getSeed()); + result.lastAmbient = lastAmbient; + result.lastAmethyst = lastAmethyst; + result.lastAmbientCracked = lastAmbientCracked; + result.justAmbient = justAmbient; + + return result; } } \ No newline at end of file diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java index c109d39b..010efffc 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java @@ -4,6 +4,8 @@ import net.earthcomputer.clientcommands.features.CCrackVillager; import net.earthcomputer.clientcommands.features.PlayerRandCracker; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.sounds.SoundEvents; import org.spongepowered.asm.mixin.Mixin; @@ -24,10 +26,26 @@ private void onSendCommand(String command, CallbackInfo ci) { @Inject(method = "handleSoundEvent", at = @At("TAIL")) private void onSoundEvent(ClientboundSoundPacket packet, CallbackInfo ci) { - if(packet.getSound().is(SoundEvents.AMETHYST_BLOCK_CHIME.getLocation())) { - CCrackVillager.onAmethyst(packet); - } else if (packet.getSound().is(SoundEvents.VILLAGER_AMBIENT.getLocation())) { + if (packet.getSound().is(SoundEvents.VILLAGER_AMBIENT.getLocation())) { CCrackVillager.onAmbient(); + } else if(packet.getSound().is(SoundEvents.AMETHYST_BLOCK_CHIME.getLocation())) { + CCrackVillager.onAmethyst(packet); } } + + @Inject(method = "handleBlockUpdate", at = @At("TAIL")) + void onBlockUpdate(ClientboundBlockUpdatePacket packet, CallbackInfo ci){ + if(packet.getPos().equals(CCrackVillager.clockPos)) { + CCrackVillager.onClockUpdate(); + } + } + + @Inject(method = "handleChunkBlocksUpdate", at = @At("TAIL")) + void onBlockUpdate(ClientboundSectionBlocksUpdatePacket packet, CallbackInfo ci){ + packet.runUpdates((pos, block) -> { + if(pos.equals(CCrackVillager.clockPos)) { + CCrackVillager.onClockUpdate(); + } + }); + } } diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java index 9714046f..cb02d7be 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java @@ -1,10 +1,15 @@ package net.earthcomputer.clientcommands.mixin.rngevents; import net.earthcomputer.clientcommands.features.PlayerRandCracker; +import net.earthcomputer.clientcommands.features.VillagerRNGSim; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.MultiPlayerGameMode; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.DiggerItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -47,4 +52,9 @@ private void postStartPrediction(CallbackInfo ci) { private void startPredictionFinally(CallbackInfo ci) { PlayerRandCracker.isPredictingBlockBreaking = false; } + + @Inject(method = "interact", at = @At("TAIL")) + void onInteract(Player player, Entity target, InteractionHand hand, CallbackInfoReturnable cir) { + VillagerRNGSim.INSTANCE.clone().onOfferTrades(); + } } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index f71e52fe..b69a4fc3 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -266,6 +266,7 @@ "commands.ccrackvillager.fail": "Crack Fail, retrying...", "commands.ccrackvillager.success": "Villager RNG cracked: %d", "commands.ccrackvillager.maintain": "Villager RNG maintain success", + "commands.ccrackvillager.synced": "Villager RNG synced", "commands.ccrackvillager.cancel": "Crack RNG cancelled", "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", From 56a890d10b27b78b193d8ee24632f502a27f8ca6 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 1 Jun 2024 16:48:36 +0800 Subject: [PATCH 03/16] able to get desire trade, when there's no lag. --- .../command/CrackVillagerRNGCommand.java | 12 +++- .../ItemAndEnchantmentsPredicateArgument.java | 6 +- .../features/CCrackVillager.java | 5 ++ .../features/VillagerRNGSim.java | 56 +++++++++++++++---- .../rngevents/MultiPlayerGameModeMixin.java | 4 -- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index e5749df2..9e471512 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -12,11 +12,13 @@ import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Items; 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 com.mojang.brigadier.arguments.IntegerArgumentType.*; +import static net.earthcomputer.clientcommands.command.arguments.ItemAndEnchantmentsPredicateArgument.*; public class CrackVillagerRNGCommand { public static void register(CommandDispatcher dispatcher) { @@ -29,7 +31,14 @@ public static void register(CommandDispatcher dispatc .then(literal("interval") .then(argument("ticks", integer(20, 100)) .executes(ctx -> crackWithInterval(ctx.getSource(), getBlockPos(ctx, "clockpos"), getInteger(ctx, "ticks")))))) - )); + ) + .then(literal("enchant").then(argument("name", itemAndEnchantmentsPredicate().withItemPredicate((i) -> i.equals(Items.BOOK)).constrainMaxLevel()) + .executes(ctx -> lookingForEnchantment(ctx.getSource(), getItemAndEnchantmentsPredicate(ctx, "name")))))); + } + + private static int lookingForEnchantment(FabricClientCommandSource source, ItemAndEnchantmentsPredicate predicate) { + CCrackVillager.targetEnchantment = predicate; + return Command.SINGLE_SUCCESS; } private static int crackVillagerRNG(FabricClientCommandSource source, BlockPos pos) throws CommandSyntaxException { @@ -44,6 +53,7 @@ private static int crackVillagerRNG(FabricClientCommandSource source, BlockPos p private static int cancel(FabricClientCommandSource source) { CCrackVillager.cancel(); + CCrackVillager.targetEnchantment = null; source.sendFeedback(Component.translatable("commands.ccrackvillager.cancel")); return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java index 914aeaa4..82b7be01 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java @@ -22,6 +22,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.EnchantmentInstance; import net.minecraft.world.item.enchantment.ItemEnchantments; import org.jetbrains.annotations.Nullable; @@ -153,8 +154,9 @@ public boolean test(ItemStack stack) { if (item != stack.getItem() && (item != Items.BOOK || stack.getItem() != Items.ENCHANTED_BOOK)) { return false; } - List enchantments = stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).entrySet().stream() - .map(entry -> new EnchantmentInstance(entry.getKey().value(), entry.getIntValue())) + var enchantmentsForCrafting = EnchantmentHelper.getEnchantmentsForCrafting(stack); + var enchantments = enchantmentsForCrafting.keySet().stream() + .map(holder -> new EnchantmentInstance(holder.value(), EnchantmentHelper.getItemEnchantmentLevel(holder.value(), stack))) .toList(); return predicate.test(enchantments); } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index c58bcc48..ae7fda9b 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -2,6 +2,7 @@ import com.seedfinding.latticg.reversal.DynamicProgram; import com.seedfinding.latticg.util.LCG; +import net.earthcomputer.clientcommands.command.arguments.ItemAndEnchantmentsPredicateArgument; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -29,6 +30,10 @@ public class CCrackVillager { static int interval = 22; public static BlockPos clockPos; + public static ItemAndEnchantmentsPredicateArgument.ItemAndEnchantmentsPredicate targetEnchantment = null; + + + public static void cancel() { targetVillager = null; } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 9fa0659d..3145b04e 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.npc.VillagerTrades; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -11,6 +12,9 @@ import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.levelgen.LegacyRandomSource; +import java.util.ArrayList; +import java.util.List; + public class VillagerRNGSim { public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); @@ -78,7 +82,7 @@ public void onAmbient() { var ticks = 0; while(!forSync.justAmbient) { ticks++; - forSync.onTick(); + forSync.onTick(true); } if(ticks < 30) { @@ -101,6 +105,10 @@ public void setSeed(long seed) { } public void onTick() { + onTick(false); + } + + public void onTick(boolean sim) { if(ticksToWait-- > 0) { return; } @@ -114,26 +122,53 @@ public void onTick() { justAmbient = false; } random.nextInt(100); - } - public void onOfferTrades() { - var chat = Minecraft.getInstance().gui.getChat(); - chat.addMessage(Component.literal("client pre-trade: " + Long.toHexString(getSeed()))); + if(CCrackVillager.cracked && !sim && CCrackVillager.targetEnchantment != null) { + var player = Minecraft.getInstance().player; + var villager = CCrackVillager.targetVillager.get(); + if(player == null || player.distanceTo(villager) > 5) return; + var simulate = clone(); + //simulate.onTick(true); + var offers = simulate.predictOffers(); + if(offers == null) return; + for(var offer : offers) { + if(CCrackVillager.targetEnchantment.test(offer.getResult())) { + assert Minecraft.getInstance().gameMode != null; + Minecraft.getInstance().gameMode.interact(player, villager, InteractionHand.MAIN_HAND); + var chat = Minecraft.getInstance().gui.getChat(); + chat.addMessage(Component.literal("I found it !")); + CCrackVillager.targetEnchantment = null; + break; + } + } + } + } + public List predictOffers() { var villager = CCrackVillager.targetVillager.get(); - if(villager == null) return; + if(villager == null) return null; var map = VillagerTrades.TRADES.get(villager.getVillagerData().getProfession()); - if(map == null || map.isEmpty()) return; + if(map == null || map.isEmpty()) return null; var items = map.get(villager.getVillagerData().getLevel()); - if(items == null) return; - var offers = new MerchantOffers(); + if(items == null) return null; var itemList = Lists.newArrayList(items); + List offers = new ArrayList<>(); var i = 0; while (i < 2) { MerchantOffer offer = itemList.remove(this.random.nextInt(itemList.size())).getOffer(villager, this.random); if (offer == null) continue; offers.add(offer); ++i; + } + return offers; + } + + public void onOfferTrades() { + var chat = Minecraft.getInstance().gui.getChat(); + chat.addMessage(Component.literal("client pre-trade: " + Long.toHexString(getSeed()))); + + for(var offer : predictOffers()) { + var first = offer.getCostA(); var second = offer.getCostB(); var result = offer.getResult(); @@ -145,10 +180,11 @@ public void onOfferTrades() { if(result.is(Items.ENCHANTED_BOOK)) { var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(result); var enchantment = enchantments.keySet().iterator().next().value(); - offerString += " with %s".formatted(enchantment.getFullname(EnchantmentHelper.getItemEnchantmentLevel(enchantment, result))); + offerString += " with %s".formatted(enchantment.getFullname(EnchantmentHelper.getItemEnchantmentLevel(enchantment, result)).getString()); } chat.addMessage(Component.literal(offerString)); } + chat.addMessage(Component.literal("client post-trade: " + Long.toHexString(getSeed()))); } diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java index cb02d7be..6e1342f8 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java @@ -53,8 +53,4 @@ private void startPredictionFinally(CallbackInfo ci) { PlayerRandCracker.isPredictingBlockBreaking = false; } - @Inject(method = "interact", at = @At("TAIL")) - void onInteract(Player player, Entity target, InteractionHand hand, CallbackInfoReturnable cir) { - VillagerRNGSim.INSTANCE.clone().onOfferTrades(); - } } From ca707ecd1efb07747b85df3fa8732c0ac4fc84ed Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 1 Jun 2024 20:02:43 +0800 Subject: [PATCH 04/16] deal with latency --- .../command/CrackVillagerRNGCommand.java | 12 +- .../features/CCrackVillager.java | 2 +- .../features/VillagerRNGSim.java | 143 ++++++++++++++++-- .../mixin/debug/PlayerTabOverlayMixin.java | 33 ++++ .../assets/clientcommands/lang/en_us.json | 1 + src/main/resources/mixins.clientcommands.json | 1 + 6 files changed, 172 insertions(+), 20 deletions(-) create mode 100644 src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 9e471512..c5048df5 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -27,11 +27,11 @@ public static void register(CommandDispatcher dispatc .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", integer(20, 100)) - .executes(ctx -> crackWithInterval(ctx.getSource(), getBlockPos(ctx, "clockpos"), getInteger(ctx, "ticks")))))) + .executes(ctx -> crackVillagerRNG(ctx.getSource(), getBlockPos(ctx, "clockpos")))) ) + .then(literal("interval") + .then(argument("ticks", integer(0, 10)) + .executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks"))))) .then(literal("enchant").then(argument("name", itemAndEnchantmentsPredicate().withItemPredicate((i) -> i.equals(Items.BOOK)).constrainMaxLevel()) .executes(ctx -> lookingForEnchantment(ctx.getSource(), getItemAndEnchantmentsPredicate(ctx, "name")))))); } @@ -58,8 +58,8 @@ private static int cancel(FabricClientCommandSource source) { return Command.SINGLE_SUCCESS; } - private static int crackWithInterval(FabricClientCommandSource source, BlockPos pos, int interval) throws CommandSyntaxException { + private static int setInterval(FabricClientCommandSource source, int interval) throws CommandSyntaxException { CCrackVillager.setInterval(interval); - return crackVillagerRNG(source, pos); + return Command.SINGLE_SUCCESS; } } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index ae7fda9b..fbc5a617 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -27,7 +27,7 @@ public class CCrackVillager { static boolean cracked = false; static int validMeasures = 0; static boolean cracking = false; - static int interval = 22; + static int interval = 0; public static BlockPos clockPos; public static ItemAndEnchantmentsPredicateArgument.ItemAndEnchantmentsPredicate targetEnchantment = null; diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 3145b04e..08e850c7 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -3,20 +3,29 @@ import com.google.common.collect.Lists; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.EnchantmentInstance; import net.minecraft.world.item.trading.MerchantOffer; -import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.levelgen.LegacyRandomSource; import java.util.ArrayList; import java.util.List; public class VillagerRNGSim { - public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); + public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); + static VillagerRNGSim TenTicksBefore = new VillagerRNGSim(); + static boolean tenTicksBeforeSet = false; + static int tenTickIndex = 0; + static int[] tenTickRandomCalls = new int[10]; + static long[] tenTickSeeds = new long[10]; + static long[] tenTickLastAmbient = new long[10]; + static long[] tenTickLastAmethyst = new long[10]; LegacyRandomSource random = new LegacyRandomSource(0); @@ -25,8 +34,11 @@ public class VillagerRNGSim { boolean lastAmbientCracked = false; boolean justAmbient = false; long lastAmethyst = 0; + static long amethystInterval = 0; int ticksToWait = 0; + boolean synced = false; + long tickCounter = 0; public void onAmethyst(ClientboundSoundPacket packet) { var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); @@ -34,19 +46,28 @@ public void onAmethyst(ClientboundSoundPacket packet) { var forSync = clone(); var ticks = 0; - var predicted = forSync.random.nextFloat(); + var predicted = forSync.nextFloat(); while(Math.abs(nextFloat - predicted) > 0.0001 && ticks++ < 30) { - predicted = forSync.random.nextFloat(); + predicted = forSync.nextFloat(); } + assert Minecraft.getInstance().level != null; + amethystInterval = lastAmethyst; + lastAmethyst = tickCounter; + amethystInterval = lastAmethyst - amethystInterval; + + synced = false; if(ticks < 30) { setSeed(forSync.getSeed()); justAmbient = forSync.justAmbient; lastAmbient = forSync.lastAmbient; ticksToWait = forSync.ticksToWait; lastAmethyst = forSync.lastAmethyst; + tenTickLastAmethyst[tenTickIndex] = lastAmethyst; + errorCount = 0; if(ticks == 0) { + synced = true; Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); } else { Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintain"), false); @@ -71,8 +92,8 @@ public void onAmbient() { if(!CCrackVillager.cracked) return; lastAmbient = -80; - random.nextFloat(); - random.nextFloat(); + nextFloat(); + nextFloat(); justAmbient = true; } @@ -112,23 +133,48 @@ public void onTick(boolean sim) { if(ticksToWait-- > 0) { return; } - if(random.nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { - random.nextFloat(); - random.nextFloat(); + tickCounter++; + + if(sim && tickCounter - lastAmethyst >= amethystInterval) { + nextFloat(); + } + + if(CCrackVillager.cracked) { + tenTickIndex++; + tenTickIndex %= 10; + tenTickRandomCalls[tenTickIndex] = 0; + tenTickSeeds[tenTickIndex] = getSeed(); + } + + if(nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { + nextFloat(); + nextFloat(); lastAmbient = -80; lastAmbientCracked = true; justAmbient = true; } else { justAmbient = false; } - random.nextInt(100); + if(CCrackVillager.cracked) { + tenTickLastAmbient[tenTickIndex] = lastAmbient; + } + nextInt(100); - if(CCrackVillager.cracked && !sim && CCrackVillager.targetEnchantment != null) { + if(CCrackVillager.cracked && !sim && CCrackVillager.targetEnchantment != null && synced) { var player = Minecraft.getInstance().player; var villager = CCrackVillager.targetVillager.get(); if(player == null || player.distanceTo(villager) > 5) return; var simulate = clone(); - //simulate.onTick(true); + var connection = Minecraft.getInstance().getConnection(); + if(connection != null) { + var info = connection.getPlayerInfo(player.getScoreboardName()); + if(info != null) { + CCrackVillager.interval = info.getLatency() / 50; + } + } + for(var i = 0; i < CCrackVillager.interval; i++) { + simulate.onTick(true); + } var offers = simulate.predictOffers(); if(offers == null) return; for(var offer : offers) { @@ -144,6 +190,22 @@ public void onTick(boolean sim) { } } + void randomCalled() { + if(this == INSTANCE) { + tenTickRandomCalls[tenTickIndex]++; + } + } + + float nextFloat() { + randomCalled(); + return random.nextFloat(); + } + + int nextInt(int bound) { + randomCalled(); + return random.nextInt(bound); + } + public List predictOffers() { var villager = CCrackVillager.targetVillager.get(); if(villager == null) return null; @@ -155,7 +217,7 @@ public List predictOffers() { List offers = new ArrayList<>(); var i = 0; while (i < 2) { - MerchantOffer offer = itemList.remove(this.random.nextInt(itemList.size())).getOffer(villager, this.random); + MerchantOffer offer = itemList.remove(nextInt(itemList.size())).getOffer(villager, this.random); if (offer == null) continue; offers.add(offer); ++i; @@ -189,6 +251,61 @@ public void onOfferTrades() { } + public void syncOffers(ClientboundMerchantOffersPacket packet) { + if(CCrackVillager.cracked) { + var offers = packet.getOffers(); + var tick = 0; + while (tick < 10) { + var player = Minecraft.getInstance().player; + var villager = CCrackVillager.targetVillager.get(); + if(player == null || player.distanceTo(villager) > 5) return; + var simulate = clone(); + var index = (tenTickIndex-tick+10) % 10; + simulate.setSeed(tenTickSeeds[index]); + var predictedOffers = simulate.predictOffers(); + if(predictedOffers == null) return; + var match = true; + for(var i = 0; i < predictedOffers.size(); i++) { + if(!checkItem(offers.get(i).getCostA(), predictedOffers.get(i).getCostA())) { + match = false; + break; + } + } + if(match) { + break; + } + tick++; + } + if(tick > 0 && tick < 10) { + CCrackVillager.interval = tick; + var chat = Minecraft.getInstance().gui.getChat(); + chat.addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", tick)); + } + } + } + + EnchantmentInstance getEnchantment(ItemStack stack) { + + var enchantmentsForCrafting = EnchantmentHelper.getEnchantmentsForCrafting(stack); + if(enchantmentsForCrafting.isEmpty()) return null; + var holder = enchantmentsForCrafting.keySet().iterator().next(); + return new EnchantmentInstance(holder.value(), EnchantmentHelper.getItemEnchantmentLevel(holder.value(), stack)); + } + + boolean checkItem(ItemStack stack1, ItemStack stack2){ + if(stack1.getItem() == stack2.getItem() && stack1.getCount() == stack2.getCount()) { + var enchantment1 = getEnchantment(stack1); + var enchantment2 = getEnchantment(stack2); + if((enchantment1 == null) == (enchantment2 == null)) { + return enchantment1 == null + || (enchantment1.enchantment == enchantment2.enchantment && enchantment1.level == enchantment2.level); + } + return false; + } + return false; + + } + @Override public VillagerRNGSim clone() { var result = new VillagerRNGSim(); diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java new file mode 100644 index 00000000..02010917 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java @@ -0,0 +1,33 @@ +package net.earthcomputer.clientcommands.mixin.debug; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.PlayerTabOverlay; +import net.minecraft.client.multiplayer.PlayerInfo; +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.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(PlayerTabOverlay.class) +public class PlayerTabOverlayMixin { + @Shadow @Final private Minecraft minecraft; + + @ModifyConstant(method = "render", constant = @Constant(intValue = 13)) + int modifyWidth(int constant) { + return constant + 45; + } + + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/components/PlayerTabOverlay;renderPingIcon(Lnet/minecraft/client/gui/GuiGraphics;IIILnet/minecraft/client/multiplayer/PlayerInfo;)V")) + void onRender(PlayerTabOverlay instance, GuiGraphics guiGraphics, int width, int x, int y, PlayerInfo playerInfo) { + String ping = "%dms".formatted(playerInfo.getLatency()); + var w = minecraft.font.width(ping); + var textX = width + x - w; + guiGraphics.drawString(minecraft.font, ping, textX, y, 0xffffff, true); + RenderSystem.setShaderColor(1f,1f,1f,1f); + } +} diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index b69a4fc3..7c90bd63 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -269,6 +269,7 @@ "commands.ccrackvillager.synced": "Villager RNG synced", "commands.ccrackvillager.cancel": "Crack RNG cancelled", "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", + "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", diff --git a/src/main/resources/mixins.clientcommands.json b/src/main/resources/mixins.clientcommands.json index df7f8eb8..0faee904 100644 --- a/src/main/resources/mixins.clientcommands.json +++ b/src/main/resources/mixins.clientcommands.json @@ -71,6 +71,7 @@ "commands.findblock.ClientLevelMixin", "commands.generic.CommandSuggestionsMixin", "dataqueryhandler.ClientPacketListenerMixin", + "debug.PlayerTabOverlayMixin", "events.ClientPacketListenerMixin", "lengthextender.ChatScreenMixin", "scrambletitle.MinecraftMixin", From 9202098ed0a0f9ce3c9dec6e2ca805bfc02d4686 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 1 Jun 2024 22:28:50 +0800 Subject: [PATCH 05/16] can even works on aternos --- .../ItemAndEnchantmentsPredicateArgument.java | 2 +- .../features/VillagerRNGSim.java | 165 +++++++++--------- .../rngevents/ClientPacketListenerMixin.java | 7 + .../assets/clientcommands/lang/en_us.json | 1 + 4 files changed, 91 insertions(+), 84 deletions(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java index 82b7be01..6c4a28dd 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ItemAndEnchantmentsPredicateArgument.java @@ -156,7 +156,7 @@ public boolean test(ItemStack stack) { } var enchantmentsForCrafting = EnchantmentHelper.getEnchantmentsForCrafting(stack); var enchantments = enchantmentsForCrafting.keySet().stream() - .map(holder -> new EnchantmentInstance(holder.value(), EnchantmentHelper.getItemEnchantmentLevel(holder.value(), stack))) + .map(holder -> new EnchantmentInstance(holder.value(), enchantmentsForCrafting.getLevel(holder.value()))) .toList(); return predicate.test(enchantments); } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 08e850c7..df17ec53 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -19,16 +19,12 @@ public class VillagerRNGSim { public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); - static VillagerRNGSim TenTicksBefore = new VillagerRNGSim(); - static boolean tenTicksBeforeSet = false; - static int tenTickIndex = 0; - static int[] tenTickRandomCalls = new int[10]; - static long[] tenTickSeeds = new long[10]; - static long[] tenTickLastAmbient = new long[10]; - static long[] tenTickLastAmethyst = new long[10]; LegacyRandomSource random = new LegacyRandomSource(0); + static List nextOffers = new ArrayList<>(); + static List nextOffersWithBooks = new ArrayList<>(); + int errorCount = 0; long lastAmbient = 0; boolean lastAmbientCracked = false; @@ -63,7 +59,6 @@ public void onAmethyst(ClientboundSoundPacket packet) { lastAmbient = forSync.lastAmbient; ticksToWait = forSync.ticksToWait; lastAmethyst = forSync.lastAmethyst; - tenTickLastAmethyst[tenTickIndex] = lastAmethyst; errorCount = 0; if(ticks == 0) { @@ -77,7 +72,7 @@ public void onAmethyst(ClientboundSoundPacket packet) { ticksToWait = 10; errorCount++; Minecraft.getInstance().gui.overlayMessageTime = 0; - if(errorCount > 4) { + if(errorCount > 2) { errorCount = 0; CCrackVillager.cracked = false; lastAmbientCracked = false; @@ -139,13 +134,6 @@ public void onTick(boolean sim) { nextFloat(); } - if(CCrackVillager.cracked) { - tenTickIndex++; - tenTickIndex %= 10; - tenTickRandomCalls[tenTickIndex] = 0; - tenTickSeeds[tenTickIndex] = getSeed(); - } - if(nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { nextFloat(); nextFloat(); @@ -155,9 +143,6 @@ public void onTick(boolean sim) { } else { justAmbient = false; } - if(CCrackVillager.cracked) { - tenTickLastAmbient[tenTickIndex] = lastAmbient; - } nextInt(100); if(CCrackVillager.cracked && !sim && CCrackVillager.targetEnchantment != null && synced) { @@ -165,13 +150,6 @@ public void onTick(boolean sim) { var villager = CCrackVillager.targetVillager.get(); if(player == null || player.distanceTo(villager) > 5) return; var simulate = clone(); - var connection = Minecraft.getInstance().getConnection(); - if(connection != null) { - var info = connection.getPlayerInfo(player.getScoreboardName()); - if(info != null) { - CCrackVillager.interval = info.getLatency() / 50; - } - } for(var i = 0; i < CCrackVillager.interval; i++) { simulate.onTick(true); } @@ -180,6 +158,7 @@ public void onTick(boolean sim) { for(var offer : offers) { if(CCrackVillager.targetEnchantment.test(offer.getResult())) { assert Minecraft.getInstance().gameMode != null; + printNextTrades(); Minecraft.getInstance().gameMode.interact(player, villager, InteractionHand.MAIN_HAND); var chat = Minecraft.getInstance().gui.getChat(); chat.addMessage(Component.literal("I found it !")); @@ -191,9 +170,6 @@ public void onTick(boolean sim) { } void randomCalled() { - if(this == INSTANCE) { - tenTickRandomCalls[tenTickIndex]++; - } } float nextFloat() { @@ -225,71 +201,94 @@ public List predictOffers() { return offers; } - public void onOfferTrades() { - var chat = Minecraft.getInstance().gui.getChat(); - chat.addMessage(Component.literal("client pre-trade: " + Long.toHexString(getSeed()))); - - for(var offer : predictOffers()) { + String getOfferString(MerchantOffer offer) { + var first = offer.getCostA(); + var second = offer.getCostB(); + var result = offer.getResult(); + var offerString = "%dx %s".formatted(first.getCount(), first.getHoverName().getString()); + if(!second.isEmpty()) { + offerString += " + %dx %s".formatted(second.getCount(), second.getHoverName().getString()); + } + if(result.is(Items.ENCHANTED_BOOK)) { + var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(result); + var enchantment = enchantments.keySet().iterator().next().value(); - var first = offer.getCostA(); - var second = offer.getCostB(); - var result = offer.getResult(); - var offerString = "%dx %s".formatted(first.getCount(), first.getHoverName().getString()); - if(!second.isEmpty()) { - offerString += " + %dx %s".formatted(second.getCount(), second.getDisplayName().getString()); - } + offerString += " => %s lvl.%d".formatted(Component.translatable(enchantment.getDescriptionId()).getString(), EnchantmentHelper.getEnchantmentsForCrafting(result).getLevel(enchantment)); + } else { offerString += " => %dx %s".formatted(result.getCount(), result.getHoverName().getString()); - if(result.is(Items.ENCHANTED_BOOK)) { - var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(result); - var enchantment = enchantments.keySet().iterator().next().value(); - offerString += " with %s".formatted(enchantment.getFullname(EnchantmentHelper.getItemEnchantmentLevel(enchantment, result)).getString()); - } - chat.addMessage(Component.literal(offerString)); } - - chat.addMessage(Component.literal("client post-trade: " + Long.toHexString(getSeed()))); - + return offerString; } - public void syncOffers(ClientboundMerchantOffersPacket packet) { - if(CCrackVillager.cracked) { - var offers = packet.getOffers(); - var tick = 0; - while (tick < 10) { - var player = Minecraft.getInstance().player; - var villager = CCrackVillager.targetVillager.get(); - if(player == null || player.distanceTo(villager) > 5) return; - var simulate = clone(); - var index = (tenTickIndex-tick+10) % 10; - simulate.setSeed(tenTickSeeds[index]); - var predictedOffers = simulate.predictOffers(); - if(predictedOffers == null) return; - var match = true; - for(var i = 0; i < predictedOffers.size(); i++) { - if(!checkItem(offers.get(i).getCostA(), predictedOffers.get(i).getCostA())) { - match = false; - break; - } - } - if(match) { - break; - } - tick++; + public void printNextTrades() { + nextOffers.clear(); + nextOffersWithBooks.clear(); + var chat = Minecraft.getInstance().gui.getChat(); + for(var i = 0; i < 15; i++) { + var sim = clone(); + for(var tick = 0; tick < i; tick++) { + sim.onTick(true); } - if(tick > 0 && tick < 10) { - CCrackVillager.interval = tick; - var chat = Minecraft.getInstance().gui.getChat(); - chat.addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", tick)); + var offers = sim.predictOffers(); + var bookIndex = -1; + for(var index = 0; index < 2; index++) { + var offer = offers.get(index); + nextOffers.add(offer); + if(offer.getResult().is(Items.ENCHANTED_BOOK)) { + bookIndex = index; + var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(offer.getResult()); + var enchantment = enchantments.keySet().iterator().next().value(); + //chat.addMessage(Component.translatable("commands.ccrackvillager.showEnchOnTick", i, enchantment.getFullname(enchantments.getLevel(enchantment)))); + } } + nextOffersWithBooks.add(bookIndex); } + } EnchantmentInstance getEnchantment(ItemStack stack) { - var enchantmentsForCrafting = EnchantmentHelper.getEnchantmentsForCrafting(stack); if(enchantmentsForCrafting.isEmpty()) return null; var holder = enchantmentsForCrafting.keySet().iterator().next(); - return new EnchantmentInstance(holder.value(), EnchantmentHelper.getItemEnchantmentLevel(holder.value(), stack)); + return new EnchantmentInstance(holder.value(), EnchantmentHelper.getEnchantmentsForCrafting(stack).getLevel(holder.value())); + } + + public void syncOffer(ClientboundMerchantOffersPacket packet) { + var offers = packet.getOffers(); + var hasBook = -1; + for(var i = 0; i < 2; i++) { + if(offers.get(i).getResult().is(Items.ENCHANTED_BOOK)) hasBook = i; + } + if(hasBook != -1) { + for(var i = 0; i < nextOffers.size(); i+=2) { + var i2 = nextOffersWithBooks.get(i/2); + if(i2 != -1) { + if(i2 == hasBook && checkItem(offers.get(hasBook).getResult(), nextOffers.get(i+i2).getResult())) { + CCrackVillager.interval = i/2; + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); + return; + } + } + } + } else { + for(var i = 0; i < nextOffers.size(); i+=2) { + var same = true; + for(var j = 0; j < 2; j++) { + var offer = nextOffers.get(i+j); + var offer2 = offers.get(j); + if(checkItem(offer.getResult(), offer2.getResult()) + && checkItem(offer.getCostA(), offer2.getCostA()) + && checkItem(offer.getCostB(), offer2.getCostB())) + continue; + same = false; + } + if(same) { + CCrackVillager.interval = i/2; + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); + return; + } + } + } } boolean checkItem(ItemStack stack1, ItemStack stack2){ @@ -297,13 +296,13 @@ boolean checkItem(ItemStack stack1, ItemStack stack2){ var enchantment1 = getEnchantment(stack1); var enchantment2 = getEnchantment(stack2); if((enchantment1 == null) == (enchantment2 == null)) { - return enchantment1 == null - || (enchantment1.enchantment == enchantment2.enchantment && enchantment1.level == enchantment2.level); + if(enchantment1 == null) return true; + return enchantment1.enchantment.getDescriptionId().equals(enchantment2.enchantment.getDescriptionId()) + && enchantment1.level == enchantment2.level; } return false; } return false; - } @Override diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java index 010efffc..e9879b0f 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java @@ -3,8 +3,10 @@ import com.mojang.brigadier.StringReader; import net.earthcomputer.clientcommands.features.CCrackVillager; import net.earthcomputer.clientcommands.features.PlayerRandCracker; +import net.earthcomputer.clientcommands.features.VillagerRNGSim; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket; import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.sounds.SoundEvents; @@ -48,4 +50,9 @@ void onBlockUpdate(ClientboundSectionBlocksUpdatePacket packet, CallbackInfo ci) } }); } + + @Inject(method = "handleMerchantOffers", at = @At("TAIL")) + void onOffers(ClientboundMerchantOffersPacket packet, CallbackInfo ci) { + VillagerRNGSim.INSTANCE.syncOffer(packet); + } } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index 7c90bd63..ea869c97 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -270,6 +270,7 @@ "commands.ccrackvillager.cancel": "Crack RNG cancelled", "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", + "commands.ccrackvillager.showEnchOnTick": "tick: %d => %s", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", From 00468d36a070e430f33fca0166e451534c436196 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sun, 2 Jun 2024 00:18:21 +0800 Subject: [PATCH 06/16] fix gradle --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 68fb8234..df941a0c 100644 --- a/build.gradle +++ b/build.gradle @@ -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" - implementation "com.seedfinding:latticg:${project.latticg_version}" + includedLibrary "com.seedfinding:latticg:${project.latticg_version}" compileOnly 'com.demonwav.mcdev:annotations:2.0.0' From 178ac034b3d4ea9467cdfd291ba384fec31c3c8d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sun, 2 Jun 2024 17:50:49 +0800 Subject: [PATCH 07/16] add goals for command --- .../clientcommands/ClientCommands.java | 2 +- .../command/CrackVillagerRNGCommand.java | 176 ++++++++++++++++-- .../command/arguments/CombinedArgument.java | 71 +++++++ .../arguments/DynamicIntegerArgument.java | 75 ++++++++ .../arguments/EnchantmentArgument.java | 41 ++++ .../command/arguments/ProfessionArgument.java | 39 ++++ .../features/CCrackVillager.java | 67 ++++++- .../features/VillagerRNGSim.java | 6 +- 8 files changed, 454 insertions(+), 23 deletions(-) create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java diff --git a/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java b/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java index dae2f97c..edcaece9 100644 --- a/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java +++ b/src/main/java/net/earthcomputer/clientcommands/ClientCommands.java @@ -171,7 +171,7 @@ public static void registerCommands(CommandDispatcher WeatherCommand.register(dispatcher); WhisperEncryptedCommand.register(dispatcher); WikiCommand.register(dispatcher); - CrackVillagerRNGCommand.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; diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index c5048df5..8ad0ca0d 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -2,42 +2,89 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.earthcomputer.clientcommands.Configs; +import net.earthcomputer.clientcommands.command.arguments.ProfessionArgument; import net.earthcomputer.clientcommands.features.CCrackVillager; import net.earthcomputer.clientcommands.features.PlayerRandCracker; -import net.earthcomputer.clientcommands.features.ServerBrandManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.arguments.item.ItemArgument; +import net.minecraft.commands.arguments.item.ItemInput; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +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.earthcomputer.clientcommands.command.arguments.ProfessionArgument.profession; 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 com.mojang.brigadier.arguments.IntegerArgumentType.*; import static net.earthcomputer.clientcommands.command.arguments.ItemAndEnchantmentsPredicateArgument.*; +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.CrackVillagerRNGCommand.MyItemArgument.item; public class CrackVillagerRNGCommand { - public static void register(CommandDispatcher dispatcher) { + public static void register(CommandDispatcher dispatcher, CommandBuildContext context) { + //var professionArg = profession(); 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", integer(0, 10)) - .executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks"))))) - .then(literal("enchant").then(argument("name", itemAndEnchantmentsPredicate().withItemPredicate((i) -> i.equals(Items.BOOK)).constrainMaxLevel()) - .executes(ctx -> lookingForEnchantment(ctx.getSource(), getItemAndEnchantmentsPredicate(ctx, "name")))))); + .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, 10)) + .executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks"))))) + .then(literal("addgoal") + .then(genFirst(context)) + .then(genSecond(context)) + .then(genResult(context))) + .then(literal("listgoals") + .executes(CrackVillagerRNGCommand::listGoals)) + .then(literal("removegoal") + .then(argument("index", integer(1,CCrackVillager.goalOffers::size)) + .executes(CrackVillagerRNGCommand::removeGoal))) + .then(literal("cleargoals").executes(CrackVillagerRNGCommand::clearGoals)) + .then(literal("run").executes(CrackVillagerRNGCommand::doRun))); + } + + private static int doRun(CommandContext context) { + CCrackVillager.findingOffers = true; + return Command.SINGLE_SUCCESS; + } + + private static int clearGoals(CommandContext context) { + CCrackVillager.goalOffers.clear(); + return Command.SINGLE_SUCCESS; + } + + private static int removeGoal(CommandContext context) { + CCrackVillager.goalOffers.remove(getInteger(context, "index")-1); + return Command.SINGLE_SUCCESS; } - private static int lookingForEnchantment(FabricClientCommandSource source, ItemAndEnchantmentsPredicate predicate) { - CCrackVillager.targetEnchantment = predicate; + private static int listGoals(CommandContext context) { + for(var i = 0; i < CCrackVillager.goalOffers.size(); i++) { + var offer = CCrackVillager.goalOffers.get(i); + context.getSource().sendFeedback(Component.literal("%d. %s".formatted(i+1, offer))); + } return Command.SINGLE_SUCCESS; } @@ -53,7 +100,7 @@ private static int crackVillagerRNG(FabricClientCommandSource source, BlockPos p private static int cancel(FabricClientCommandSource source) { CCrackVillager.cancel(); - CCrackVillager.targetEnchantment = null; + CCrackVillager.findingOffers = false; source.sendFeedback(Component.translatable("commands.ccrackvillager.cancel")); return Command.SINGLE_SUCCESS; } @@ -62,4 +109,97 @@ private static int setInterval(FabricClientCommandSource source, int interval) t CCrackVillager.setInterval(interval); return Command.SINGLE_SUCCESS; } + + static class MyItemArgument extends ItemArgument { + public ItemInput lastItem; + + public MyItemArgument(CommandBuildContext context) { + super(context); + } + + public static MyItemArgument item(CommandBuildContext context) { + return new MyItemArgument(context); + } + + public static ItemInput getItem(CommandContext context, String name) { + return context.getArgument(name, ItemInput.class); + } + + @Override + public ItemInput parse(StringReader reader) throws CommandSyntaxException { + return lastItem = super.parse(reader); + } + } + + private static Combined, String> createPredicate(CommandContext context, String argName) { + try { + Result>> 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 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> 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() || result2.value().second() == level; + }, result2.string()); + } catch (IllegalArgumentException ignored) { } + + context.getSource().sendFeedback(Component.literal("add goal: " + offer)); + + CCrackVillager.goalOffers.add(offer); + + return Command.SINGLE_SUCCESS; + } + + + + static LiteralArgumentBuilder genFirst(CommandBuildContext context) { + var item = item(context); + Supplier supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize(); + return literal("first") + .then(argument("seconditem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) + .executes(CrackVillagerRNGCommand::setGoal) + .then(genSecond(context)) .then(genResult(context))); + } + + static LiteralArgumentBuilder genSecond(CommandBuildContext context) { + var item = item(context); + Supplier 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 genResult(CommandBuildContext context) { + var enchantment = enchantment(); + var item = item(context); + Supplier 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)))); + } } diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java new file mode 100644 index 00000000..7fa8da33 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java @@ -0,0 +1,71 @@ +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.commands.arguments.item.ItemInput; +import net.minecraft.network.chat.Component; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class CombinedArgument implements ArgumentType> { + ArgumentType firstArgument; + ArgumentType secondArgument; + private static final SimpleCommandExceptionType TOO_FEW_ARGUMENTS_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.client.tooFewArguments")); + + private CombinedArgument(ArgumentType first, ArgumentType second) { + firstArgument = first; + secondArgument = second; + } + + public static CombinedArgument combined(ArgumentType first, ArgumentType second) { + return new CombinedArgument<>(first, second); + } + + public static Combined getCombined(CommandContext context, String name) { + return context.getArgument(name, Combined.class); + } + + @Override + public Combined 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 CompletableFuture listSuggestions(CommandContext 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 first, B second) { + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java new file mode 100644 index 00000000..e092db56 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java @@ -0,0 +1,75 @@ +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 { + Supplier low; + Supplier high; + boolean allowAny = false; + + DynamicIntegerArgument(Supplier low, Supplier high) { + this.low = low; + this.high = high; + } + + public DynamicIntegerArgument allowAny() { + allowAny = true; + return this; + } + + public static int getInteger(CommandContext context, String name) { + return context.getArgument(name, int.class); + } + + public static DynamicIntegerArgument integer(Supplier low, Supplier high) { + return new DynamicIntegerArgument(low, high); + } + + public static DynamicIntegerArgument integer(int low, Supplier high) { + return integer(() -> low, high); + } + public static DynamicIntegerArgument integer(Supplier low, int high) { + return integer(low, () -> high); + } + + public static DynamicIntegerArgument integer(Supplier 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 CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + builder.suggest("*"); + return builder.buildFuture(); + } +} \ No newline at end of file diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java new file mode 100644 index 00000000..80d0bc3c --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java @@ -0,0 +1,41 @@ +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 net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.enchantment.Enchantment; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class EnchantmentArgument implements ArgumentType { + public Enchantment lastParsed = null; + + @Override + public Enchantment parse(StringReader reader) throws CommandSyntaxException { + return lastParsed = BuiltInRegistries.ENCHANTMENT.get(ResourceLocation.read(reader)); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + SharedSuggestionProvider.suggestResource(BuiltInRegistries.ENCHANTMENT.keySet(), builder); + + return builder.buildFuture(); + } + + public static EnchantmentArgument enchantment() { + return new EnchantmentArgument(); + } + + + public static Enchantment getEnchantment(CommandContext context, String name) { + return context.getArgument(name, Enchantment.class); + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java new file mode 100644 index 00000000..7f8268c0 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java @@ -0,0 +1,39 @@ +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 net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.npc.VillagerProfession; + +import java.util.concurrent.CompletableFuture; + +public class ProfessionArgument implements ArgumentType { + public VillagerProfession lastParsed = null; + + @Override + public VillagerProfession parse(StringReader reader) throws CommandSyntaxException { + return lastParsed = BuiltInRegistries.VILLAGER_PROFESSION.get(ResourceLocation.read(reader)); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + SharedSuggestionProvider.suggestResource(BuiltInRegistries.VILLAGER_PROFESSION.keySet(), builder); + + return builder.buildFuture(); + } + + public static ProfessionArgument profession() { + return new ProfessionArgument(); + } + + + public static VillagerProfession getProfession(CommandContext context, String name) { + return context.getArgument(name, VillagerProfession.class); + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index fbc5a617..fa1bfbb5 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -10,12 +10,16 @@ import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.world.entity.ai.targeting.TargetingConditions; import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.level.block.Blocks; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; public class CCrackVillager { @@ -30,7 +34,8 @@ public class CCrackVillager { static int interval = 0; public static BlockPos clockPos; - public static ItemAndEnchantmentsPredicateArgument.ItemAndEnchantmentsPredicate targetEnchantment = null; + public static List goalOffers = new ArrayList<>(); + public static boolean findingOffers = false; @@ -130,4 +135,64 @@ static void reset() { measurements.clear(); validMeasures = 0; } + + public static class Offer implements Predicate { + + Predicate first = null; + Predicate second = null; + Predicate result = null; + + String firstDescription = ""; + String secondDescription = ""; + String resultDescription = ""; + String enchantmentDescription = ""; + + public Offer withFirst(Predicate predicate, String description) { + first = predicate; + firstDescription = description; + return this; + } + public Offer withSecond(Predicate predicate, String description) { + second = predicate; + secondDescription = description; + return this; + } + public Offer withResult(Predicate predicate, String description) { + result = predicate; + resultDescription = description; + return this; + } + public Offer andEnchantment(Predicate predicate, String description) { + result = result.and(predicate); + enchantmentDescription = description; + return this; + } + + @Override + public boolean test(MerchantOffer offer) { + if(first != null && !first.test(offer.getItemCostA().itemStack())) return false; + if(second != null && !second.test(offer.getItemCostB().isPresent() ? offer.getItemCostB().get().itemStack() : null)) { + return false; + } + return result == null || result.test(offer.getResult()); + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(firstDescription); + if(!secondDescription.isEmpty() && !result.isEmpty()) { + result.append(" + "); + } + result.append(secondDescription); + if(!resultDescription.isEmpty() && !result.isEmpty()) { + result.append(" => "); + } + result.append(resultDescription); + if(!enchantmentDescription.isEmpty()) { + result.append(" with ").append(enchantmentDescription); + } + + return result.toString(); + } + } } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index df17ec53..546a1d37 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -145,7 +145,7 @@ public void onTick(boolean sim) { } nextInt(100); - if(CCrackVillager.cracked && !sim && CCrackVillager.targetEnchantment != null && synced) { + if(CCrackVillager.cracked && !sim && CCrackVillager.findingOffers && synced) { var player = Minecraft.getInstance().player; var villager = CCrackVillager.targetVillager.get(); if(player == null || player.distanceTo(villager) > 5) return; @@ -156,13 +156,13 @@ public void onTick(boolean sim) { var offers = simulate.predictOffers(); if(offers == null) return; for(var offer : offers) { - if(CCrackVillager.targetEnchantment.test(offer.getResult())) { + if(CCrackVillager.goalOffers.stream().anyMatch(goalOffer -> goalOffer.test(offer))) { assert Minecraft.getInstance().gameMode != null; printNextTrades(); Minecraft.getInstance().gameMode.interact(player, villager, InteractionHand.MAIN_HAND); var chat = Minecraft.getInstance().gui.getChat(); chat.addMessage(Component.literal("I found it !")); - CCrackVillager.targetEnchantment = null; + CCrackVillager.findingOffers = false; break; } } From e75b5bae41f25b99ff5d8f9571c0af02084ea496 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sun, 2 Jun 2024 17:54:24 +0800 Subject: [PATCH 08/16] remove unused argument --- .../command/CrackVillagerRNGCommand.java | 2 - .../command/arguments/ProfessionArgument.java | 39 ------------------- 2 files changed, 41 deletions(-) delete mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 8ad0ca0d..8a981005 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -9,7 +9,6 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.earthcomputer.clientcommands.Configs; -import net.earthcomputer.clientcommands.command.arguments.ProfessionArgument; import net.earthcomputer.clientcommands.features.CCrackVillager; import net.earthcomputer.clientcommands.features.PlayerRandCracker; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; @@ -28,7 +27,6 @@ import java.util.function.Supplier; import static net.earthcomputer.clientcommands.command.arguments.DynamicIntegerArgument.integer; -import static net.earthcomputer.clientcommands.command.arguments.ProfessionArgument.profession; 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.*; diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java deleted file mode 100644 index 7f8268c0..00000000 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/ProfessionArgument.java +++ /dev/null @@ -1,39 +0,0 @@ -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 net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.npc.VillagerProfession; - -import java.util.concurrent.CompletableFuture; - -public class ProfessionArgument implements ArgumentType { - public VillagerProfession lastParsed = null; - - @Override - public VillagerProfession parse(StringReader reader) throws CommandSyntaxException { - return lastParsed = BuiltInRegistries.VILLAGER_PROFESSION.get(ResourceLocation.read(reader)); - } - - @Override - public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { - SharedSuggestionProvider.suggestResource(BuiltInRegistries.VILLAGER_PROFESSION.keySet(), builder); - - return builder.buildFuture(); - } - - public static ProfessionArgument profession() { - return new ProfessionArgument(); - } - - - public static VillagerProfession getProfession(CommandContext context, String name) { - return context.getArgument(name, VillagerProfession.class); - } -} From 40dc1fe987de8c86ed27f9e1e24c4ec565bc8d04 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 3 Jun 2024 21:31:43 +0800 Subject: [PATCH 09/16] fix arguments --- .../command/CrackVillagerRNGCommand.java | 12 ++++++------ .../command/arguments/DynamicIntegerArgument.java | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 8a981005..7653c00f 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -48,7 +48,7 @@ public static void register(CommandDispatcher dispatc .then(argument("clockpos", blockPos()) .executes(ctx -> crackVillagerRNG(ctx.getSource(), getBlockPos(ctx, "clockpos"))))) .then(literal("interval") - .then(argument("ticks", IntegerArgumentType.integer(0, 10)) + .then(argument("ticks", IntegerArgumentType.integer(0, 20)) .executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks"))))) .then(literal("addgoal") .then(genFirst(context)) @@ -74,7 +74,7 @@ private static int clearGoals(CommandContext context) } private static int removeGoal(CommandContext context) { - CCrackVillager.goalOffers.remove(getInteger(context, "index")-1); + context.getSource().sendFeedback(Component.literal("remove goal: " + CCrackVillager.goalOffers.remove(getInteger(context, "index")-1))); return Command.SINGLE_SUCCESS; } @@ -137,8 +137,8 @@ private static Combined, String> createPredicate(CommandCon 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)), + && ((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; @@ -164,7 +164,7 @@ private static int setGoal(CommandContext context) { }, result2.string()); } catch (IllegalArgumentException ignored) { } - context.getSource().sendFeedback(Component.literal("add goal: " + offer)); + context.getSource().sendFeedback(Component.literal((CCrackVillager.goalOffers.size()+1) + ": " + offer)); CCrackVillager.goalOffers.add(offer); @@ -177,7 +177,7 @@ static LiteralArgumentBuilder genFirst(CommandBuildCo var item = item(context); Supplier supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize(); return literal("first") - .then(argument("seconditem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) + .then(argument("firstitem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) .executes(CrackVillagerRNGCommand::setGoal) .then(genSecond(context)) .then(genResult(context))); } diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java index e092db56..9459950c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java @@ -69,7 +69,9 @@ public Integer parse(final StringReader reader) throws CommandSyntaxException { @Override public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { - builder.suggest("*"); + if(allowAny) { + builder.suggest("*"); + } return builder.buildFuture(); } } \ No newline at end of file From da8bf4734de37c366076c71b0870892c0df4f515 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 3 Jun 2024 21:44:45 +0800 Subject: [PATCH 10/16] remove stuff --- .../command/CrackVillagerRNGCommand.java | 5 --- .../command/arguments/CombinedArgument.java | 2 -- .../arguments/EnchantmentArgument.java | 2 -- .../features/CCrackVillager.java | 4 --- .../features/VillagerRNGSim.java | 27 ++------------- .../mixin/debug/PlayerTabOverlayMixin.java | 33 ------------------- .../rngevents/MultiPlayerGameModeMixin.java | 6 ---- src/main/resources/mixins.clientcommands.json | 1 - 8 files changed, 2 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 7653c00f..05f9ed6c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -4,7 +4,6 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -17,9 +16,7 @@ import net.minecraft.commands.arguments.item.ItemInput; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.npc.VillagerTrades; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -30,7 +27,6 @@ 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.ItemAndEnchantmentsPredicateArgument.*; import static net.earthcomputer.clientcommands.command.arguments.CombinedArgument.*; import static net.earthcomputer.clientcommands.command.arguments.EnchantmentArgument.*; import static net.earthcomputer.clientcommands.command.arguments.DynamicIntegerArgument.*; @@ -40,7 +36,6 @@ public class CrackVillagerRNGCommand { public static void register(CommandDispatcher dispatcher, CommandBuildContext context) { - //var professionArg = profession(); dispatcher.register(literal("ccrackvillager") .then(literal("cancel") .executes(ctx -> cancel(ctx.getSource()))) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java index 7fa8da33..bde396fe 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CombinedArgument.java @@ -7,10 +7,8 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.commands.arguments.item.ItemInput; import net.minecraft.network.chat.Component; -import java.util.Collection; import java.util.concurrent.CompletableFuture; public class CombinedArgument implements ArgumentType> { diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java index 80d0bc3c..e7fb6c5a 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/EnchantmentArgument.java @@ -11,9 +11,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.enchantment.Enchantment; -import java.util.Collection; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; public class EnchantmentArgument implements ArgumentType { public Enchantment lastParsed = null; diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index fa1bfbb5..f0841d5c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -2,7 +2,6 @@ import com.seedfinding.latticg.reversal.DynamicProgram; import com.seedfinding.latticg.util.LCG; -import net.earthcomputer.clientcommands.command.arguments.ItemAndEnchantmentsPredicateArgument; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -18,7 +17,6 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; public class CCrackVillager { @@ -77,8 +75,6 @@ public static void onAmbient() { static void crack(ClientboundSoundPacket packet) { var lastChimeIntensity1_2 = (packet.getVolume() - 0.1f); var nextFloat = (packet.getPitch() - 0.5f) / lastChimeIntensity1_2; - //if(validMeasures > 0) - // measurements.add(Measurement.skip(interval * 2)); // 2 random call every ticks measurements.add(Measurement.nextFloat(nextFloat, 0.0015f)); validMeasures++; diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 546a1d37..e01b219c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -160,8 +160,6 @@ public void onTick(boolean sim) { assert Minecraft.getInstance().gameMode != null; printNextTrades(); Minecraft.getInstance().gameMode.interact(player, villager, InteractionHand.MAIN_HAND); - var chat = Minecraft.getInstance().gui.getChat(); - chat.addMessage(Component.literal("I found it !")); CCrackVillager.findingOffers = false; break; } @@ -201,29 +199,9 @@ public List predictOffers() { return offers; } - String getOfferString(MerchantOffer offer) { - var first = offer.getCostA(); - var second = offer.getCostB(); - var result = offer.getResult(); - var offerString = "%dx %s".formatted(first.getCount(), first.getHoverName().getString()); - if(!second.isEmpty()) { - offerString += " + %dx %s".formatted(second.getCount(), second.getHoverName().getString()); - } - if(result.is(Items.ENCHANTED_BOOK)) { - var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(result); - var enchantment = enchantments.keySet().iterator().next().value(); - - offerString += " => %s lvl.%d".formatted(Component.translatable(enchantment.getDescriptionId()).getString(), EnchantmentHelper.getEnchantmentsForCrafting(result).getLevel(enchantment)); - } else { - offerString += " => %dx %s".formatted(result.getCount(), result.getHoverName().getString()); - } - return offerString; - } - public void printNextTrades() { nextOffers.clear(); nextOffersWithBooks.clear(); - var chat = Minecraft.getInstance().gui.getChat(); for(var i = 0; i < 15; i++) { var sim = clone(); for(var tick = 0; tick < i; tick++) { @@ -236,9 +214,6 @@ public void printNextTrades() { nextOffers.add(offer); if(offer.getResult().is(Items.ENCHANTED_BOOK)) { bookIndex = index; - var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(offer.getResult()); - var enchantment = enchantments.keySet().iterator().next().value(); - //chat.addMessage(Component.translatable("commands.ccrackvillager.showEnchOnTick", i, enchantment.getFullname(enchantments.getLevel(enchantment)))); } } nextOffersWithBooks.add(bookIndex); @@ -270,6 +245,7 @@ public void syncOffer(ClientboundMerchantOffersPacket packet) { } } } + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.maintainFail")); } else { for(var i = 0; i < nextOffers.size(); i+=2) { var same = true; @@ -288,6 +264,7 @@ && checkItem(offer.getCostB(), offer2.getCostB())) return; } } + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.maintainFail")); } } diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java deleted file mode 100644 index 02010917..00000000 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/debug/PlayerTabOverlayMixin.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.earthcomputer.clientcommands.mixin.debug; - -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.PlayerTabOverlay; -import net.minecraft.client.multiplayer.PlayerInfo; -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.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(PlayerTabOverlay.class) -public class PlayerTabOverlayMixin { - @Shadow @Final private Minecraft minecraft; - - @ModifyConstant(method = "render", constant = @Constant(intValue = 13)) - int modifyWidth(int constant) { - return constant + 45; - } - - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/components/PlayerTabOverlay;renderPingIcon(Lnet/minecraft/client/gui/GuiGraphics;IIILnet/minecraft/client/multiplayer/PlayerInfo;)V")) - void onRender(PlayerTabOverlay instance, GuiGraphics guiGraphics, int width, int x, int y, PlayerInfo playerInfo) { - String ping = "%dms".formatted(playerInfo.getLatency()); - var w = minecraft.font.width(ping); - var textX = width + x - w; - guiGraphics.drawString(minecraft.font, ping, textX, y, 0xffffff, true); - RenderSystem.setShaderColor(1f,1f,1f,1f); - } -} diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java index 6e1342f8..9714046f 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/MultiPlayerGameModeMixin.java @@ -1,15 +1,10 @@ package net.earthcomputer.clientcommands.mixin.rngevents; import net.earthcomputer.clientcommands.features.PlayerRandCracker; -import net.earthcomputer.clientcommands.features.VillagerRNGSim; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.MultiPlayerGameMode; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.DiggerItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -52,5 +47,4 @@ private void postStartPrediction(CallbackInfo ci) { private void startPredictionFinally(CallbackInfo ci) { PlayerRandCracker.isPredictingBlockBreaking = false; } - } diff --git a/src/main/resources/mixins.clientcommands.json b/src/main/resources/mixins.clientcommands.json index 0faee904..df7f8eb8 100644 --- a/src/main/resources/mixins.clientcommands.json +++ b/src/main/resources/mixins.clientcommands.json @@ -71,7 +71,6 @@ "commands.findblock.ClientLevelMixin", "commands.generic.CommandSuggestionsMixin", "dataqueryhandler.ClientPacketListenerMixin", - "debug.PlayerTabOverlayMixin", "events.ClientPacketListenerMixin", "lengthextender.ChatScreenMixin", "scrambletitle.MinecraftMixin", From dbbeb36c3148a92e1d606f2615e98e9d6db092f3 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 5 Jun 2024 01:00:24 +0800 Subject: [PATCH 11/16] oops --- .../clientcommands/command/CrackVillagerRNGCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 05f9ed6c..7ca24bc9 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -155,7 +155,7 @@ private static int setGoal(CommandContext context) { offer.andEnchantment((stack) -> { var enchantments = EnchantmentHelper.getEnchantmentsForCrafting(stack); var level = enchantments.getLevel(enchantment); - return result2.value().second() > enchantment.getMaxLevel() || result2.value().second() == level; + return (result2.value().second() > enchantment.getMaxLevel() && level > 0) || result2.value().second() == level; }, result2.string()); } catch (IllegalArgumentException ignored) { } From a220fda2fa2b49aff8bfd75a7e4acfe7f28952eb Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 5 Jun 2024 22:52:58 +0800 Subject: [PATCH 12/16] add rng crack progress add predicted waiting time --- .../features/CCrackVillager.java | 3 ++ .../features/VillagerRNGSim.java | 39 ++++++++++++++++++- .../assets/clientcommands/lang/en_us.json | 3 ++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index f0841d5c..6777731c 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -6,6 +6,7 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.world.entity.ai.targeting.TargetingConditions; import net.minecraft.world.entity.npc.Villager; @@ -99,6 +100,8 @@ static void crack(ClientboundSoundPacket packet) { reset(); } cracking = false; + } else { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.progress", validMeasures), false); } } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index e01b219c..207a474d 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -34,6 +34,9 @@ public class VillagerRNGSim { int ticksToWait = 0; boolean synced = false; + static long lastBruteForce = 0; + static long bruteForceResult = 0; + long tickCounter = 0; public void onAmethyst(ClientboundSoundPacket packet) { @@ -62,6 +65,10 @@ public void onAmethyst(ClientboundSoundPacket packet) { errorCount = 0; if(ticks == 0) { + if((tickCounter - lastBruteForce > 500 || tickCounter > bruteForceResult + 10) && CCrackVillager.findingOffers) { + lastBruteForce = tickCounter; + bruteForce(); + } synced = true; Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); } else { @@ -76,10 +83,10 @@ public void onAmethyst(ClientboundSoundPacket packet) { errorCount = 0; CCrackVillager.cracked = false; lastAmbientCracked = false; + lastBruteForce = 0; Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintainFail"), false); } } - } public void onAmbient() { @@ -107,6 +114,7 @@ public void onAmbient() { lastAmbient = forSync.lastAmbient; ticksToWait = forSync.ticksToWait; lastAmethyst = forSync.lastAmethyst;; + tickCounter = forSync.tickCounter; } else { ticksToWait = 10; } @@ -167,6 +175,34 @@ public void onTick(boolean sim) { } } + void bruteForce() { + var player = Minecraft.getInstance().player; + var villager = CCrackVillager.targetVillager.get(); + if(player == null || player.distanceTo(villager) > 5) return; + var simulate = clone(); + + for(var i = 0; i < CCrackVillager.interval; i++) { + simulate.onTick(true); + } + for(var step = 0; step < 600; step++) { + simulate.onTick(true); + var sim2 = simulate.clone(); + + var offers = sim2.predictOffers(); + if(offers == null) return; + for(var offer : offers) { + for(var goal : CCrackVillager.goalOffers) { + if(goal.test(offer)) { + bruteForceResult = sim2.tickCounter; + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.match", step)); + return; + } + } + } + } + Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.noMatch")); + } + void randomCalled() { } @@ -290,6 +326,7 @@ public VillagerRNGSim clone() { result.lastAmethyst = lastAmethyst; result.lastAmbientCracked = lastAmbientCracked; result.justAmbient = justAmbient; + result.tickCounter = tickCounter; return result; } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index ea869c97..f221c3b6 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -271,6 +271,9 @@ "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", "commands.ccrackvillager.showEnchOnTick": "tick: %d => %s", + "commands.ccrackvillager.noMatch": "cannot find any trades match any goals in 30 seconds", + "commands.ccrackvillager.match": "there might have a desired trade in %d ticks later", + "commands.ccrackvillager.progress": "crack RNG progress: %d/7", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", From 329e7a161eb3a3de6e1824549d71ad8f74e4780d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 5 Jun 2024 22:55:54 +0800 Subject: [PATCH 13/16] empty goals warning --- .../clientcommands/command/CrackVillagerRNGCommand.java | 3 +++ src/main/resources/assets/clientcommands/lang/en_us.json | 1 + 2 files changed, 4 insertions(+) diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 7ca24bc9..603a19b9 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -60,6 +60,9 @@ public static void register(CommandDispatcher dispatc private static int doRun(CommandContext context) { CCrackVillager.findingOffers = true; + if(CCrackVillager.goalOffers.isEmpty()) { + context.getSource().sendFeedback(Component.translatable("commands.ccrackvillager.emptyGoals")); + } return Command.SINGLE_SUCCESS; } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index f221c3b6..f16b4699 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -274,6 +274,7 @@ "commands.ccrackvillager.noMatch": "cannot find any trades match any goals in 30 seconds", "commands.ccrackvillager.match": "there might have a desired trade in %d ticks later", "commands.ccrackvillager.progress": "crack RNG progress: %d/7", + "commands.ccrackvillager.emptyGoals": "warning: you haven't added any goals", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", From 0c58bec0ec0e0392b810d9d2fa4e121680438cec Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 6 Jun 2024 15:54:14 +0800 Subject: [PATCH 14/16] notify if doesn't cracking while it is synced --- .../clientcommands/features/VillagerRNGSim.java | 6 +++++- src/main/resources/assets/clientcommands/lang/en_us.json | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 207a474d..16a83f53 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -70,7 +70,11 @@ public void onAmethyst(ClientboundSoundPacket packet) { bruteForce(); } synced = true; - Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); + if(CCrackVillager.findingOffers) { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); + } else { + Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.syncedNotCracking"), false); + } } else { Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.maintain"), false); } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index f16b4699..53ba11d2 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -267,6 +267,7 @@ "commands.ccrackvillager.success": "Villager RNG cracked: %d", "commands.ccrackvillager.maintain": "Villager RNG maintain success", "commands.ccrackvillager.synced": "Villager RNG synced", + "commands.ccrackvillager.syncedNotCracking": "Villager RNG synced (not cracking trades)", "commands.ccrackvillager.cancel": "Crack RNG cancelled", "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", From 6a7eceaf4e30aca9d10f72e97a9bcba62fdf2948 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Fri, 7 Jun 2024 18:20:33 +0800 Subject: [PATCH 15/16] no clock notify --- .../clientcommands/features/CCrackVillager.java | 8 ++++++-- src/main/resources/assets/clientcommands/lang/en_us.json | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index 6777731c..957e8a00 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -31,7 +31,7 @@ public class CCrackVillager { static int validMeasures = 0; static boolean cracking = false; static int interval = 0; - public static BlockPos clockPos; + public static BlockPos clockPos = null; public static List goalOffers = new ArrayList<>(); public static boolean findingOffers = false; @@ -96,7 +96,11 @@ static void crack(ClientboundSoundPacket packet) { } onCrackFinished.accept(VillagerRNGSim.INSTANCE.getSeed()); } else { - Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.fail"), false); + var gui = Minecraft.getInstance().gui; + if(clockPos == null) { + gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.noClock")); + } + gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.fail"), false); reset(); } cracking = false; diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index 53ba11d2..a755d794 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -276,6 +276,7 @@ "commands.ccrackvillager.match": "there might have a desired trade in %d ticks later", "commands.ccrackvillager.progress": "crack RNG progress: %d/7", "commands.ccrackvillager.emptyGoals": "warning: you haven't added any goals", + "commands.ccrackvillager.noClock": "warning: clock position hasn't be set", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible", From 9136444d5e3dd27ed923e4e5d2ef1a1ec614d32f Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 2 Jul 2024 12:54:13 +0800 Subject: [PATCH 16/16] some suggests --- .../command/CrackVillagerRNGCommand.java | 49 ++------ .../command/arguments/CachedItemArgument.java | 31 +++++ .../arguments/DynamicIntegerArgument.java | 4 +- .../features/CCrackVillager.java | 28 +++-- .../features/VillagerRNGSim.java | 114 +++++++++--------- .../rngevents/ClientPacketListenerMixin.java | 2 +- .../assets/clientcommands/lang/en_us.json | 20 +-- 7 files changed, 132 insertions(+), 116 deletions(-) create mode 100644 src/main/java/net/earthcomputer/clientcommands/command/arguments/CachedItemArgument.java diff --git a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java index 603a19b9..29a735ce 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/CrackVillagerRNGCommand.java @@ -2,17 +2,14 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.StringReader; 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.Configs; import net.earthcomputer.clientcommands.features.CCrackVillager; -import net.earthcomputer.clientcommands.features.PlayerRandCracker; +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.ItemArgument; import net.minecraft.commands.arguments.item.ItemInput; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -32,7 +29,7 @@ import static net.earthcomputer.clientcommands.command.arguments.DynamicIntegerArgument.*; import static net.earthcomputer.clientcommands.command.arguments.WithStringArgument.*; -import static net.earthcomputer.clientcommands.command.CrackVillagerRNGCommand.MyItemArgument.item; +import static net.earthcomputer.clientcommands.command.arguments.CachedItemArgument.item; public class CrackVillagerRNGCommand { public static void register(CommandDispatcher dispatcher, CommandBuildContext context) { @@ -45,16 +42,16 @@ public static void register(CommandDispatcher dispatc .then(literal("interval") .then(argument("ticks", IntegerArgumentType.integer(0, 20)) .executes(ctx -> setInterval(ctx.getSource(), getInteger(ctx, "ticks"))))) - .then(literal("addgoal") + .then(literal("add-goal") .then(genFirst(context)) .then(genSecond(context)) .then(genResult(context))) - .then(literal("listgoals") + .then(literal("list-goals") .executes(CrackVillagerRNGCommand::listGoals)) - .then(literal("removegoal") + .then(literal("remove-goal") .then(argument("index", integer(1,CCrackVillager.goalOffers::size)) .executes(CrackVillagerRNGCommand::removeGoal))) - .then(literal("cleargoals").executes(CrackVillagerRNGCommand::clearGoals)) + .then(literal("clear-goals").executes(CrackVillagerRNGCommand::clearGoals)) .then(literal("run").executes(CrackVillagerRNGCommand::doRun))); } @@ -72,24 +69,23 @@ private static int clearGoals(CommandContext context) } private static int removeGoal(CommandContext context) { - context.getSource().sendFeedback(Component.literal("remove goal: " + CCrackVillager.goalOffers.remove(getInteger(context, "index")-1))); + context.getSource().sendFeedback(Component.translatable("commands.ccrackvillager.removeGoal", CCrackVillager.goalOffers.remove(getInteger(context, "index") - 1))); return Command.SINGLE_SUCCESS; } private static int listGoals(CommandContext context) { for(var i = 0; i < CCrackVillager.goalOffers.size(); i++) { var offer = CCrackVillager.goalOffers.get(i); - context.getSource().sendFeedback(Component.literal("%d. %s".formatted(i+1, offer))); + 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))); - PlayerRandCracker.setSeed(seed); - Configs.playerCrackState = PlayerRandCracker.CrackState.CRACKED; }); return Command.SINGLE_SUCCESS; } @@ -106,27 +102,6 @@ private static int setInterval(FabricClientCommandSource source, int interval) t return Command.SINGLE_SUCCESS; } - static class MyItemArgument extends ItemArgument { - public ItemInput lastItem; - - public MyItemArgument(CommandBuildContext context) { - super(context); - } - - public static MyItemArgument item(CommandBuildContext context) { - return new MyItemArgument(context); - } - - public static ItemInput getItem(CommandContext context, String name) { - return context.getArgument(name, ItemInput.class); - } - - @Override - public ItemInput parse(StringReader reader) throws CommandSyntaxException { - return lastItem = super.parse(reader); - } - } - private static Combined, String> createPredicate(CommandContext context, String argName) { try { Result>> result = getWithString(context, argName, null); @@ -175,7 +150,7 @@ static LiteralArgumentBuilder genFirst(CommandBuildCo var item = item(context); Supplier supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize(); return literal("first") - .then(argument("firstitem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) + .then(argument("firstitem", withString(combined(item, combined(integer(1, supplier).allowAny(), integer(1, supplier).allowAny())))) .executes(CrackVillagerRNGCommand::setGoal) .then(genSecond(context)) .then(genResult(context))); } @@ -184,7 +159,7 @@ static LiteralArgumentBuilder genSecond(CommandBuild var item = item(context); Supplier supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize(); return literal("second") - .then(argument("seconditem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) + .then(argument("seconditem", withString(combined(item, combined(integer(1, supplier).allowAny(), integer(1, supplier).allowAny())))) .executes(CrackVillagerRNGCommand::setGoal) .then(genResult(context))); } @@ -193,7 +168,7 @@ static LiteralArgumentBuilder genResult(CommandBuildC var item = item(context); Supplier supplier = () -> item.lastItem.getItem().getDefaultMaxStackSize(); return literal("result") - .then(argument("resultitem", withString(combined(item, combined(integer(1,supplier).allowAny(), integer(1,supplier).allowAny())))) + .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)))); diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/CachedItemArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CachedItemArgument.java new file mode 100644 index 00000000..1bb81303 --- /dev/null +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/CachedItemArgument.java @@ -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 ItemInput getItem(CommandContext context, String name) { + return context.getArgument(name, ItemInput.class); + } + + @Override + public ItemInput parse(StringReader reader) throws CommandSyntaxException { + return lastItem = super.parse(reader); + + } +} diff --git a/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java index 9459950c..72d1c46a 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/arguments/DynamicIntegerArgument.java @@ -47,7 +47,7 @@ public static DynamicIntegerArgument integer(Supplier limit) { @Override public Integer parse(final StringReader reader) throws CommandSyntaxException { final int start = reader.getCursor(); - if(allowAny && reader.canRead() && reader.peek() == '*') { + if (allowAny && reader.canRead() && reader.peek() == '*') { reader.read(); return Integer.MAX_VALUE; } @@ -69,7 +69,7 @@ public Integer parse(final StringReader reader) throws CommandSyntaxException { @Override public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { - if(allowAny) { + if (allowAny) { builder.suggest("*"); } return builder.buildFuture(); diff --git a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java index 957e8a00..905166c9 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/CCrackVillager.java @@ -6,7 +6,6 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.world.entity.ai.targeting.TargetingConditions; import net.minecraft.world.entity.npc.Villager; @@ -66,10 +65,15 @@ public static void onAmethyst(ClientboundSoundPacket packet) { } } - public static void onAmbient() { - VillagerRNGSim.INSTANCE.onAmbient(); - if(!cracked && validMeasures > 0) { - measurements.add(Measurement.skip(2)); + public static void onAmbient(ClientboundSoundPacket packet) { + Villager villager; + if(targetVillager != null && (villager = targetVillager.get()) != null) { + if(villager.distanceToSqr(packet.getX(), packet.getY(), packet.getZ()) < 1.0) { + VillagerRNGSim.INSTANCE.onAmbient(); + if(!cracked && validMeasures > 0) { + measurements.add(Measurement.skip(2)); + } + } } } @@ -140,7 +144,6 @@ static void reset() { } public static class Offer implements Predicate { - Predicate first = null; Predicate second = null; Predicate result = null; @@ -155,16 +158,19 @@ public Offer withFirst(Predicate predicate, String description) { firstDescription = description; return this; } + public Offer withSecond(Predicate predicate, String description) { second = predicate; secondDescription = description; return this; } + public Offer withResult(Predicate predicate, String description) { result = predicate; resultDescription = description; return this; } + public Offer andEnchantment(Predicate predicate, String description) { result = result.and(predicate); enchantmentDescription = description; @@ -173,8 +179,8 @@ public Offer andEnchantment(Predicate predicate, String description) @Override public boolean test(MerchantOffer offer) { - if(first != null && !first.test(offer.getItemCostA().itemStack())) return false; - if(second != null && !second.test(offer.getItemCostB().isPresent() ? offer.getItemCostB().get().itemStack() : null)) { + if (first != null && !first.test(offer.getItemCostA().itemStack())) return false; + if (second != null && !second.test(offer.getItemCostB().isPresent() ? offer.getItemCostB().get().itemStack() : null)) { return false; } return result == null || result.test(offer.getResult()); @@ -183,15 +189,15 @@ public boolean test(MerchantOffer offer) { @Override public String toString() { StringBuilder result = new StringBuilder(firstDescription); - if(!secondDescription.isEmpty() && !result.isEmpty()) { + if (!secondDescription.isEmpty() && !result.isEmpty()) { result.append(" + "); } result.append(secondDescription); - if(!resultDescription.isEmpty() && !result.isEmpty()) { + if (!resultDescription.isEmpty() && !result.isEmpty()) { result.append(" => "); } result.append(resultDescription); - if(!enchantmentDescription.isEmpty()) { + if (!enchantmentDescription.isEmpty()) { result.append(" with ").append(enchantmentDescription); } diff --git a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java index 16a83f53..24446241 100644 --- a/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java +++ b/src/main/java/net/earthcomputer/clientcommands/features/VillagerRNGSim.java @@ -1,6 +1,7 @@ package net.earthcomputer.clientcommands.features; import com.google.common.collect.Lists; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket; @@ -19,6 +20,7 @@ public class VillagerRNGSim { public static VillagerRNGSim INSTANCE = new VillagerRNGSim(); + public static FabricClientCommandSource commandSource = null; LegacyRandomSource random = new LegacyRandomSource(0); @@ -34,8 +36,8 @@ public class VillagerRNGSim { int ticksToWait = 0; boolean synced = false; - static long lastBruteForce = 0; - static long bruteForceResult = 0; + public static long lastBruteForce = 0; + public static long bruteForceResult = 0; long tickCounter = 0; @@ -46,7 +48,7 @@ public void onAmethyst(ClientboundSoundPacket packet) { var forSync = clone(); var ticks = 0; var predicted = forSync.nextFloat(); - while(Math.abs(nextFloat - predicted) > 0.0001 && ticks++ < 30) { + while (Math.abs(nextFloat - predicted) > 0.0001 && ticks++ < 30) { predicted = forSync.nextFloat(); } @@ -56,7 +58,7 @@ public void onAmethyst(ClientboundSoundPacket packet) { amethystInterval = lastAmethyst - amethystInterval; synced = false; - if(ticks < 30) { + if (ticks < 30) { setSeed(forSync.getSeed()); justAmbient = forSync.justAmbient; lastAmbient = forSync.lastAmbient; @@ -64,13 +66,13 @@ public void onAmethyst(ClientboundSoundPacket packet) { lastAmethyst = forSync.lastAmethyst; errorCount = 0; - if(ticks == 0) { - if((tickCounter - lastBruteForce > 500 || tickCounter > bruteForceResult + 10) && CCrackVillager.findingOffers) { + if (ticks == 0) { + if ((tickCounter - lastBruteForce > 500 || tickCounter > bruteForceResult + 10) && CCrackVillager.findingOffers) { lastBruteForce = tickCounter; bruteForce(); } synced = true; - if(CCrackVillager.findingOffers) { + if (CCrackVillager.findingOffers) { Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.synced"), false); } else { Minecraft.getInstance().gui.setOverlayMessage(Component.translatable("commands.ccrackvillager.syncedNotCracking"), false); @@ -83,7 +85,7 @@ public void onAmethyst(ClientboundSoundPacket packet) { ticksToWait = 10; errorCount++; Minecraft.getInstance().gui.overlayMessageTime = 0; - if(errorCount > 2) { + if (errorCount > 2) { errorCount = 0; CCrackVillager.cracked = false; lastAmbientCracked = false; @@ -94,8 +96,8 @@ public void onAmethyst(ClientboundSoundPacket packet) { } public void onAmbient() { - if(!lastAmbientCracked) { - if(!CCrackVillager.cracked) return; + if (!lastAmbientCracked) { + if (!CCrackVillager.cracked) return; lastAmbient = -80; nextFloat(); @@ -103,16 +105,16 @@ public void onAmbient() { justAmbient = true; } - if(justAmbient) return; + if (justAmbient) return; var forSync = clone(); var ticks = 0; - while(!forSync.justAmbient) { + while (!forSync.justAmbient) { ticks++; forSync.onTick(true); } - if(ticks < 30) { + if (ticks < 30) { setSeed(forSync.getSeed()); justAmbient = forSync.justAmbient; lastAmbient = forSync.lastAmbient; @@ -137,16 +139,16 @@ public void onTick() { } public void onTick(boolean sim) { - if(ticksToWait-- > 0) { + if (ticksToWait-- > 0) { return; } tickCounter++; - if(sim && tickCounter - lastAmethyst >= amethystInterval) { + if (sim && tickCounter - lastAmethyst >= amethystInterval) { nextFloat(); } - if(nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { + if (nextInt(1000) < lastAmbient++ && CCrackVillager.cracked) { nextFloat(); nextFloat(); lastAmbient = -80; @@ -157,18 +159,18 @@ public void onTick(boolean sim) { } nextInt(100); - if(CCrackVillager.cracked && !sim && CCrackVillager.findingOffers && synced) { + if (CCrackVillager.cracked && !sim && CCrackVillager.findingOffers && synced) { var player = Minecraft.getInstance().player; var villager = CCrackVillager.targetVillager.get(); - if(player == null || player.distanceTo(villager) > 5) return; + if (player == null || player.distanceTo(villager) > 5) return; var simulate = clone(); - for(var i = 0; i < CCrackVillager.interval; i++) { + for (var i = 0; i < CCrackVillager.interval; i++) { simulate.onTick(true); } var offers = simulate.predictOffers(); - if(offers == null) return; - for(var offer : offers) { - if(CCrackVillager.goalOffers.stream().anyMatch(goalOffer -> goalOffer.test(offer))) { + if (offers == null) return; + for (var offer : offers) { + if (CCrackVillager.goalOffers.stream().anyMatch(goalOffer -> goalOffer.test(offer))) { assert Minecraft.getInstance().gameMode != null; printNextTrades(); Minecraft.getInstance().gameMode.interact(player, villager, InteractionHand.MAIN_HAND); @@ -182,29 +184,29 @@ public void onTick(boolean sim) { void bruteForce() { var player = Minecraft.getInstance().player; var villager = CCrackVillager.targetVillager.get(); - if(player == null || player.distanceTo(villager) > 5) return; + if (player == null || player.distanceTo(villager) > 5) return; var simulate = clone(); - for(var i = 0; i < CCrackVillager.interval; i++) { + for (var i = 0; i < CCrackVillager.interval; i++) { simulate.onTick(true); } - for(var step = 0; step < 600; step++) { + for (var step = 0; step < 600; step++) { simulate.onTick(true); var sim2 = simulate.clone(); var offers = sim2.predictOffers(); - if(offers == null) return; - for(var offer : offers) { - for(var goal : CCrackVillager.goalOffers) { - if(goal.test(offer)) { + if (offers == null) return; + for (var offer : offers) { + for (var goal : CCrackVillager.goalOffers) { + if (goal.test(offer)) { bruteForceResult = sim2.tickCounter; - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.match", step)); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.match", step)); return; } } } } - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.noMatch")); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.noMatch")); } void randomCalled() { @@ -222,11 +224,11 @@ int nextInt(int bound) { public List predictOffers() { var villager = CCrackVillager.targetVillager.get(); - if(villager == null) return null; + if (villager == null) return null; var map = VillagerTrades.TRADES.get(villager.getVillagerData().getProfession()); - if(map == null || map.isEmpty()) return null; + if (map == null || map.isEmpty()) return null; var items = map.get(villager.getVillagerData().getLevel()); - if(items == null) return null; + if (items == null) return null; var itemList = Lists.newArrayList(items); List offers = new ArrayList<>(); var i = 0; @@ -242,17 +244,17 @@ public List predictOffers() { public void printNextTrades() { nextOffers.clear(); nextOffersWithBooks.clear(); - for(var i = 0; i < 15; i++) { + for (var i = 0; i < 15; i++) { var sim = clone(); - for(var tick = 0; tick < i; tick++) { + for (var tick = 0; tick < i; tick++) { sim.onTick(true); } var offers = sim.predictOffers(); var bookIndex = -1; - for(var index = 0; index < 2; index++) { + for (var index = 0; index < 2; index++) { var offer = offers.get(index); nextOffers.add(offer); - if(offer.getResult().is(Items.ENCHANTED_BOOK)) { + if (offer.getResult().is(Items.ENCHANTED_BOOK)) { bookIndex = index; } } @@ -263,7 +265,7 @@ public void printNextTrades() { EnchantmentInstance getEnchantment(ItemStack stack) { var enchantmentsForCrafting = EnchantmentHelper.getEnchantmentsForCrafting(stack); - if(enchantmentsForCrafting.isEmpty()) return null; + if (enchantmentsForCrafting.isEmpty()) return null; var holder = enchantmentsForCrafting.keySet().iterator().next(); return new EnchantmentInstance(holder.value(), EnchantmentHelper.getEnchantmentsForCrafting(stack).getLevel(holder.value())); } @@ -271,49 +273,49 @@ EnchantmentInstance getEnchantment(ItemStack stack) { public void syncOffer(ClientboundMerchantOffersPacket packet) { var offers = packet.getOffers(); var hasBook = -1; - for(var i = 0; i < 2; i++) { - if(offers.get(i).getResult().is(Items.ENCHANTED_BOOK)) hasBook = i; + for (var i = 0; i < 2; i++) { + if (offers.get(i).getResult().is(Items.ENCHANTED_BOOK)) hasBook = i; } - if(hasBook != -1) { - for(var i = 0; i < nextOffers.size(); i+=2) { + if (hasBook != -1) { + for (var i = 0; i < nextOffers.size(); i+=2) { var i2 = nextOffersWithBooks.get(i/2); - if(i2 != -1) { - if(i2 == hasBook && checkItem(offers.get(hasBook).getResult(), nextOffers.get(i+i2).getResult())) { + if (i2 != -1) { + if (i2 == hasBook && checkItem(offers.get(hasBook).getResult(), nextOffers.get(i+i2).getResult())) { CCrackVillager.interval = i/2; - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); return; } } } - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.maintainFail")); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.maintainFail")); } else { - for(var i = 0; i < nextOffers.size(); i+=2) { + for (var i = 0; i < nextOffers.size(); i+=2) { var same = true; - for(var j = 0; j < 2; j++) { + for (var j = 0; j < 2; j++) { var offer = nextOffers.get(i+j); var offer2 = offers.get(j); - if(checkItem(offer.getResult(), offer2.getResult()) + if (checkItem(offer.getResult(), offer2.getResult()) && checkItem(offer.getCostA(), offer2.getCostA()) && checkItem(offer.getCostB(), offer2.getCostB())) continue; same = false; } - if(same) { + if (same) { CCrackVillager.interval = i/2; - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.syncWithLag", CCrackVillager.interval)); return; } } - Minecraft.getInstance().gui.getChat().addMessage(Component.translatable("commands.ccrackvillager.maintainFail")); + commandSource.sendFeedback(Component.translatable("commands.ccrackvillager.maintainFail")); } } boolean checkItem(ItemStack stack1, ItemStack stack2){ - if(stack1.getItem() == stack2.getItem() && stack1.getCount() == stack2.getCount()) { + if (stack1.getItem() == stack2.getItem() && stack1.getCount() == stack2.getCount()) { var enchantment1 = getEnchantment(stack1); var enchantment2 = getEnchantment(stack2); - if((enchantment1 == null) == (enchantment2 == null)) { - if(enchantment1 == null) return true; + if ((enchantment1 == null) == (enchantment2 == null)) { + if (enchantment1 == null) return true; return enchantment1.enchantment.getDescriptionId().equals(enchantment2.enchantment.getDescriptionId()) && enchantment1.level == enchantment2.level; } diff --git a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java index e9879b0f..8a078f5b 100644 --- a/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java +++ b/src/main/java/net/earthcomputer/clientcommands/mixin/rngevents/ClientPacketListenerMixin.java @@ -29,7 +29,7 @@ private void onSendCommand(String command, CallbackInfo ci) { @Inject(method = "handleSoundEvent", at = @At("TAIL")) private void onSoundEvent(ClientboundSoundPacket packet, CallbackInfo ci) { if (packet.getSound().is(SoundEvents.VILLAGER_AMBIENT.getLocation())) { - CCrackVillager.onAmbient(); + CCrackVillager.onAmbient(packet); } else if(packet.getSound().is(SoundEvents.AMETHYST_BLOCK_CHIME.getLocation())) { CCrackVillager.onAmethyst(packet); } diff --git a/src/main/resources/assets/clientcommands/lang/en_us.json b/src/main/resources/assets/clientcommands/lang/en_us.json index a755d794..1eba2f90 100644 --- a/src/main/resources/assets/clientcommands/lang/en_us.json +++ b/src/main/resources/assets/clientcommands/lang/en_us.json @@ -263,20 +263,22 @@ "commands.client.requiresRestart": "This change will take effect after you restart your client", "commands.client.tooFewArguments": "Too few arguments", + "commands.ccrackvillager.cancel": "Crack RNG cancelled", + "commands.ccrackvillager.emptyGoals": "warning: you haven't added any goals", "commands.ccrackvillager.fail": "Crack Fail, retrying...", - "commands.ccrackvillager.success": "Villager RNG cracked: %d", + "commands.ccrackvillager.listGoal": "%d: %s", "commands.ccrackvillager.maintain": "Villager RNG maintain success", - "commands.ccrackvillager.synced": "Villager RNG synced", - "commands.ccrackvillager.syncedNotCracking": "Villager RNG synced (not cracking trades)", - "commands.ccrackvillager.cancel": "Crack RNG cancelled", "commands.ccrackvillager.maintainFail": "Villager RNG maintain fail", - "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", - "commands.ccrackvillager.showEnchOnTick": "tick: %d => %s", - "commands.ccrackvillager.noMatch": "cannot find any trades match any goals in 30 seconds", "commands.ccrackvillager.match": "there might have a desired trade in %d ticks later", - "commands.ccrackvillager.progress": "crack RNG progress: %d/7", - "commands.ccrackvillager.emptyGoals": "warning: you haven't added any goals", "commands.ccrackvillager.noClock": "warning: clock position hasn't be set", + "commands.ccrackvillager.noMatch": "cannot find any trades match any goals in 30 seconds", + "commands.ccrackvillager.progress": "crack RNG progress: %d/7", + "commands.ccrackvillager.removeGoal": "remove goal: %s", + "commands.ccrackvillager.showEnchOnTick": "tick: %d => %s", + "commands.ccrackvillager.success": "Villager RNG cracked: %d", + "commands.ccrackvillager.synced": "Villager RNG synced", + "commands.ccrackvillager.syncedNotCracking": "Villager RNG synced (not cracking trades)", + "commands.ccrackvillager.syncWithLag": "set delay to %d tick(s)", "chorusManip.landing.success": "Landing on: %d, %d, %d", "chorusManip.landing.failed": "Landing manipulation not possible",