From f0508b605b46fc7fae61815b2d2f230e90646285 Mon Sep 17 00:00:00 2001 From: Haven Date: Mon, 22 Mar 2021 17:44:00 -0700 Subject: [PATCH] - Updates FibLib for HopperOptimizations compatibility, closing #14. - Adds several performance options - Adds command to control aforementioned performance options --- gradle.properties | 4 +- src/main/java/dev/hephaestus/sax/SAX.java | 81 ++++++++++++++++++- .../sax/mixin/MixinServerWorld.java | 51 ++++++++++++ ...mentOreChunk.java => MixinWorldChunk.java} | 4 +- .../server/DeObfuscateTargetedBlock.java | 34 -------- .../dev/hephaestus/sax/server/Config.java | 70 ++++++++++------ .../hephaestus/sax/server/DeObfuscator.java | 46 +++++++---- .../sax/server/DeObfuscatorProvider.java | 11 --- .../dev/hephaestus/sax/util/FastCaster.java | 10 ++- .../hephaestus/sax/util/ObfuscatedWorld.java | 5 ++ src/main/resources/sax.mixins.json | 6 +- 11 files changed, 223 insertions(+), 99 deletions(-) create mode 100644 src/main/java/dev/hephaestus/sax/mixin/MixinServerWorld.java rename src/main/java/dev/hephaestus/sax/mixin/{world/ImplementOreChunk.java => MixinWorldChunk.java} (97%) delete mode 100644 src/main/java/dev/hephaestus/sax/mixin/server/DeObfuscateTargetedBlock.java delete mode 100644 src/main/java/dev/hephaestus/sax/server/DeObfuscatorProvider.java create mode 100644 src/main/java/dev/hephaestus/sax/util/ObfuscatedWorld.java diff --git a/gradle.properties b/gradle.properties index ef6549b..b4e0ee1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,11 +7,11 @@ yarn_mappings = 1.16.5+build.4 loader_version = 0.11.1 # Mod Properties -mod_version = 1.0.1 +mod_version = 1.1.0 maven_group = dev.hephaestus archives_base_name = sax # Dependencies fabric_version = 0.30.3+1.16 -fiblib_version = 1.0.1 +fiblib_version = 1.0.2 mod_menu_version = 1.14.6+build.31 \ No newline at end of file diff --git a/src/main/java/dev/hephaestus/sax/SAX.java b/src/main/java/dev/hephaestus/sax/SAX.java index 9e3c36c..39460ad 100644 --- a/src/main/java/dev/hephaestus/sax/SAX.java +++ b/src/main/java/dev/hephaestus/sax/SAX.java @@ -1,19 +1,33 @@ package dev.hephaestus.sax; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.hephaestus.fiblib.api.BlockFib; import dev.hephaestus.fiblib.api.BlockFibRegistry; import dev.hephaestus.sax.server.Config; import dev.hephaestus.sax.util.FastCaster; +import dev.hephaestus.sax.util.ObfuscatedWorld; import dev.hephaestus.sax.util.Profiler; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.block.Block; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Map; +import java.util.concurrent.CompletableFuture; public class SAX implements ModInitializer { public static final String MODID = "sax"; @@ -36,11 +50,70 @@ public void onInitialize() { ); } - ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> { - Profiler.dump(LOG); - }); - ServerChunkEvents.CHUNK_LOAD.register(FastCaster::load); ServerChunkEvents.CHUNK_UNLOAD.register(FastCaster::unload); + + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> + dispatcher.register(CommandManager.literal("sax") + .requires(source -> source.hasPermissionLevel(4)) + .then(CommandManager.literal("lenient") + .then(RequiredArgumentBuilder.argument("lenient", BoolArgumentType.bool()) + .executes(SAX::lenient)) + .executes(SAX::getLenient) + ) + .then(CommandManager.literal("tickRate") + .then(RequiredArgumentBuilder.argument("tickRate", IntegerArgumentType.integer(1)) + .executes(SAX::tickRate)) + .executes(SAX::getTickrate) + ) + .then(CommandManager.literal("chunkRadius") + .then(RequiredArgumentBuilder.argument("chunkRadius", IntegerArgumentType.integer(1, Byte.MAX_VALUE)) + .executes(SAX::chunkRadius)) + .executes(SAX::getChunkRadius) + ) + )); + } + + private static int lenient(CommandContext context) { + Config.LENIENT = context.getArgument("lenient", Boolean.class); + Config.save(); + + return 0; + } + + private static int getLenient(CommandContext context) { + context.getSource().sendFeedback(new LiteralText("Lenient: " + Config.LENIENT), false); + + return 0; + } + + private static int tickRate(CommandContext context) { + Config.TICK_RATE = context.getArgument("tickRate", Integer.class); + Config.save(); + + return 0; + } + + private static int getTickrate(CommandContext context) { + context.getSource().sendFeedback(new LiteralText("Tick Rate: " + Config.TICK_RATE), false); + + return 0; + } + + private static int chunkRadius(CommandContext context) { + Config.CHUNK_RADIUS = (byte) (context.getArgument("chunkRadius", Integer.class) & 0xFF); + Config.save(); + + for (ServerWorld world : context.getSource().getMinecraftServer().getWorlds()) { + ((ObfuscatedWorld) world).reset(); + } + + return 0; + } + + private static int getChunkRadius(CommandContext context) { + context.getSource().sendFeedback(new LiteralText("Chunk Radius: " + Config.CHUNK_RADIUS), false); + + return 0; } } diff --git a/src/main/java/dev/hephaestus/sax/mixin/MixinServerWorld.java b/src/main/java/dev/hephaestus/sax/mixin/MixinServerWorld.java new file mode 100644 index 0000000..fcd6df0 --- /dev/null +++ b/src/main/java/dev/hephaestus/sax/mixin/MixinServerWorld.java @@ -0,0 +1,51 @@ +package dev.hephaestus.sax.mixin; + +import dev.hephaestus.sax.server.DeObfuscator; +import dev.hephaestus.sax.util.ObfuscatedWorld; +import net.minecraft.entity.Entity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Mixin(ServerWorld.class) +public class MixinServerWorld implements ObfuscatedWorld { + @Shadow @Final private List players; + @Unique private final Map deObfuscatorMap = new HashMap<>(); + + @Inject(method = "addPlayer", at = @At("TAIL")) + private void addDeobfuscator(ServerPlayerEntity player, CallbackInfo ci) { + this.deObfuscatorMap.put(player.getUuid(), new DeObfuscator(player)); + } + + @Inject(method = "removePlayer", at = @At("TAIL")) + private void removeDeobfuscator(ServerPlayerEntity player, CallbackInfo ci) { + this.deObfuscatorMap.remove(player.getUuid()).remove(); + } + + @Inject(method = "tickEntity", at = @At("TAIL")) + private void tickDeObfuscator(Entity entity, CallbackInfo ci) { + if (entity instanceof ServerPlayerEntity) { + this.deObfuscatorMap.get(entity.getUuid()).tick(); + } + } + + @Override + public void reset() { + this.deObfuscatorMap.clear(); + + for (ServerPlayerEntity player : this.players) { + this.deObfuscatorMap.put(player.getUuid(), new DeObfuscator(player)); + } + } +} diff --git a/src/main/java/dev/hephaestus/sax/mixin/world/ImplementOreChunk.java b/src/main/java/dev/hephaestus/sax/mixin/MixinWorldChunk.java similarity index 97% rename from src/main/java/dev/hephaestus/sax/mixin/world/ImplementOreChunk.java rename to src/main/java/dev/hephaestus/sax/mixin/MixinWorldChunk.java index 7494aa6..ae10d3e 100644 --- a/src/main/java/dev/hephaestus/sax/mixin/world/ImplementOreChunk.java +++ b/src/main/java/dev/hephaestus/sax/mixin/MixinWorldChunk.java @@ -1,4 +1,4 @@ -package dev.hephaestus.sax.mixin.world; +package dev.hephaestus.sax.mixin; import dev.hephaestus.sax.server.Config; import dev.hephaestus.sax.util.ListView; @@ -30,7 +30,7 @@ import java.util.function.Consumer; @Mixin(WorldChunk.class) -public abstract class ImplementOreChunk implements OreChunk { +public abstract class MixinWorldChunk implements OreChunk { @Shadow @Final private ChunkSection[] sections; @Shadow @Final private ChunkPos pos; diff --git a/src/main/java/dev/hephaestus/sax/mixin/server/DeObfuscateTargetedBlock.java b/src/main/java/dev/hephaestus/sax/mixin/server/DeObfuscateTargetedBlock.java deleted file mode 100644 index 80c6d5b..0000000 --- a/src/main/java/dev/hephaestus/sax/mixin/server/DeObfuscateTargetedBlock.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.hephaestus.sax.mixin.server; - -import com.mojang.authlib.GameProfile; -import dev.hephaestus.sax.server.DeObfuscator; -import dev.hephaestus.sax.server.DeObfuscatorProvider; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.network.ServerPlayerInteractionManager; -import net.minecraft.server.world.ServerWorld; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ServerPlayerEntity.class) -public class DeObfuscateTargetedBlock implements DeObfuscatorProvider { - @Unique private DeObfuscator deObfuscator; - - @Inject(method = "", at = @At("TAIL")) - private void initializeDeObfuscator(MinecraftServer server, ServerWorld world, GameProfile profile, ServerPlayerInteractionManager interactionManager, CallbackInfo ci) { - this.deObfuscator = new DeObfuscator((ServerPlayerEntity) (Object) this); - } - - @Inject(method = "playerTick", at = @At("TAIL")) - private void tickDeObfuscator(CallbackInfo ci) { - this.deObfuscator.tick(); - } - - @Override - public DeObfuscator get() { - return this.deObfuscator; - } -} diff --git a/src/main/java/dev/hephaestus/sax/server/Config.java b/src/main/java/dev/hephaestus/sax/server/Config.java index 4910aaa..fb3dcac 100644 --- a/src/main/java/dev/hephaestus/sax/server/Config.java +++ b/src/main/java/dev/hephaestus/sax/server/Config.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.lib.gson.JsonReader; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.util.Identifier; @@ -20,10 +21,15 @@ // Simple config for now public class Config { + private static final Path OPTIONS = FabricLoader.getInstance().getConfigDir().resolve("sax").resolve("options.json"); + private static final Path BLOCKS = FabricLoader.getInstance().getConfigDir().resolve("sax").resolve("blocks.json"); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - public static final HashMap HIDDEN = new HashMap<>(); - public static byte CHUNK_RADIUS = 8; + public static final HashMap HIDDEN = new HashMap<>(); + public static byte CHUNK_RADIUS = 4; + public static boolean LENIENT = false; + public static int TICK_RATE = 10; static { HIDDEN.put(Blocks.DIAMOND_ORE, Blocks.STONE); @@ -41,40 +47,58 @@ public class Config { } public static void load() { - Path configDir = FabricLoader.getInstance().getConfigDir().normalize().resolve("sax"); - loadOptions(configDir, configDir.resolve("options.json")); - loadBlocks(configDir, configDir.resolve("blocks.json")); + loadOptions(); + loadBlocks(); } - private static void loadOptions(Path dir, Path file) { + private static void loadOptions() { try { - if (!Files.exists(file)) { - Files.createDirectories(dir); - - JsonObject options = new JsonObject(); - - options.addProperty("chunk_radius", CHUNK_RADIUS); - - Writer writer = Files.newBufferedWriter(file); - writer.write(GSON.toJson(options)); - writer.close(); - } else { - JsonObject options = JsonHelper.deserialize(Files.newBufferedReader(file)); + if (Files.exists(Config.OPTIONS)) { + JsonObject options = JsonHelper.deserialize(Files.newBufferedReader(Config.OPTIONS)); if (options.has("chunk_radius")) { CHUNK_RADIUS = options.get("chunk_radius").getAsByte(); } + + if (options.has("lenient")) { + LENIENT = options.get("lenient").getAsBoolean(); + } + + if (options.has("tick_rate")) { + TICK_RATE = options.get("tick_rate").getAsInt(); + } } + + save(); } catch (IOException e) { e.printStackTrace(); } + } + + public static void save() { + try { + if (!Files.exists(Config.OPTIONS.getParent())) { + Files.createDirectories(Config.OPTIONS.getParent()); + } + JsonObject options = new JsonObject(); + + options.addProperty("chunk_radius", CHUNK_RADIUS); + options.addProperty("lenient", LENIENT); + options.addProperty("tick_rate", TICK_RATE); + + Writer writer = Files.newBufferedWriter(Config.OPTIONS); + writer.write(GSON.toJson(options)); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } } - private static void loadBlocks(Path dir, Path file) { + private static void loadBlocks() { try { - if (!Files.exists(file)) { - Files.createDirectories(dir); + if (!Files.exists(Config.BLOCKS)) { + Files.createDirectories(Config.BLOCKS.getParent()); JsonObject blocks = new JsonObject(); @@ -85,13 +109,13 @@ private static void loadBlocks(Path dir, Path file) { ); } - Writer writer = Files.newBufferedWriter(file); + Writer writer = Files.newBufferedWriter(Config.BLOCKS); writer.write(GSON.toJson(blocks)); writer.close(); } else { HIDDEN.clear(); - for (Map.Entry element : JsonHelper.deserialize(Files.newBufferedReader(file)).entrySet()) { + for (Map.Entry element : JsonHelper.deserialize(Files.newBufferedReader(Config.BLOCKS)).entrySet()) { HIDDEN.put( Registry.BLOCK.get(new Identifier(element.getKey())), Registry.BLOCK.get(new Identifier(element.getValue().getAsString())) diff --git a/src/main/java/dev/hephaestus/sax/server/DeObfuscator.java b/src/main/java/dev/hephaestus/sax/server/DeObfuscator.java index c138280..e5a49dd 100644 --- a/src/main/java/dev/hephaestus/sax/server/DeObfuscator.java +++ b/src/main/java/dev/hephaestus/sax/server/DeObfuscator.java @@ -61,11 +61,15 @@ public DeObfuscator(ServerPlayerEntity player) { public void tick() { if (this.player.isCreative()) { this.revealed.clear(); - } else if (this.taskQueue.isEmpty()) { + } else if (this.taskQueue.isEmpty() && this.player.world.getTime() % Config.TICK_RATE == 0) { this.action(); } } + public void remove() { + this.executor.shutdown(); + } + private void action() { set(this.player.getCameraPosVec(1F), this.startPos); @@ -96,17 +100,25 @@ private boolean traceForBlock(Vec3i target) { ServerWorld world = this.player.getServerWorld(); - // We're checking all eight corners of our block - for (byte dX = 0; dX <= 1; ++dX) { - for (byte dY = 0; dY <= 1; ++dY) { - for (byte dZ = 0; dZ <= 1; ++dZ) { - // We want to avoid creating a ton of new vectors. - pos.x = target.getX() + dX; - pos.y = target.getY() + dY; - pos.z = target.getZ() + dZ; - - if (FastCaster.fastcast(world, this.startPos, pos, target)) { - return true; + if (Config.LENIENT) { + pos.x = target.getX() + 0.5; + pos.y = target.getY() + 0.5; + pos.z = target.getZ() + 0.5; + + return FastCaster.fastcast(world, this.startPos, pos, target) < 2; + } else { + // We're checking all eight corners of our block + for (byte dX = 0; dX <= 1; ++dX) { + for (byte dY = 0; dY <= 1; ++dY) { + for (byte dZ = 0; dZ <= 1; ++dZ) { + // We want to avoid creating a ton of new vectors. + pos.x = target.getX() + dX; + pos.y = target.getY() + dY; + pos.z = target.getZ() + dZ; + + if (FastCaster.fastcast(world, this.startPos, pos, target) < 1) { + return true; + } } } } @@ -140,11 +152,13 @@ public void run() { Collection positions = oreChunk.sax_getObfuscatedBlocks(); for (BlockPos pos : positions) { - Block block = oreChunk.getBlockState(pos).getBlock(); + if (!DeObfuscator.this.revealed.containsKey(pos)) { + Block block = oreChunk.getBlockState(pos).getBlock(); - if (Config.HIDDEN.containsKey(block)) { - if (DeObfuscator.this.traceForBlock(pos)) { - DeObfuscator.this.sendBlockUpdate(pos, DeObfuscator.this.player.networkHandler.connection::send); + if (Config.HIDDEN.containsKey(block)) { + if (DeObfuscator.this.traceForBlock(pos)) { + DeObfuscator.this.sendBlockUpdate(pos, DeObfuscator.this.player.networkHandler.connection::send); + } } } } diff --git a/src/main/java/dev/hephaestus/sax/server/DeObfuscatorProvider.java b/src/main/java/dev/hephaestus/sax/server/DeObfuscatorProvider.java deleted file mode 100644 index 62eaaa5..0000000 --- a/src/main/java/dev/hephaestus/sax/server/DeObfuscatorProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.hephaestus.sax.server; - -import net.minecraft.server.network.ServerPlayerEntity; - -public interface DeObfuscatorProvider { - static DeObfuscator get(ServerPlayerEntity playerEntity) { - return ((DeObfuscatorProvider) playerEntity).get(); - } - - DeObfuscator get(); -} diff --git a/src/main/java/dev/hephaestus/sax/util/FastCaster.java b/src/main/java/dev/hephaestus/sax/util/FastCaster.java index beb199c..899c9e6 100644 --- a/src/main/java/dev/hephaestus/sax/util/FastCaster.java +++ b/src/main/java/dev/hephaestus/sax/util/FastCaster.java @@ -23,9 +23,9 @@ public class FastCaster { private FastCaster() { } - public static boolean fastcast(ServerWorld world, Vec3d startPos, Vec3d endPos, Vec3i target) { + public static double fastcast(ServerWorld world, Vec3d startPos, Vec3d endPos, Vec3i target) { if (startPos.equals(endPos)) { - return true; + return 0; } else { double startX = MathHelper.lerp(-1.0E-7D, endPos.x, startPos.x); double startY = MathHelper.lerp(-1.0E-7D, endPos.y, startPos.y); @@ -90,9 +90,11 @@ public static boolean fastcast(ServerWorld world, Vec3d startPos, Vec3d endPos, double y2 = target.getY() + 0.5; double z2 = target.getZ() + 0.5; - double distance = 1; + dX = x1 - x2; + dY = y1 - y2; + dZ = z1 - z2; - return Math.abs(x1 - x2) < distance && Math.abs(y1 - y2) < distance && Math.abs(z1 - z2) < distance; + return Math.sqrt(dX * dX + dY * dY + dZ * dZ); } } diff --git a/src/main/java/dev/hephaestus/sax/util/ObfuscatedWorld.java b/src/main/java/dev/hephaestus/sax/util/ObfuscatedWorld.java new file mode 100644 index 0000000..aa0880a --- /dev/null +++ b/src/main/java/dev/hephaestus/sax/util/ObfuscatedWorld.java @@ -0,0 +1,5 @@ +package dev.hephaestus.sax.util; + +public interface ObfuscatedWorld { + void reset(); +} diff --git a/src/main/resources/sax.mixins.json b/src/main/resources/sax.mixins.json index 8745087..a51616d 100644 --- a/src/main/resources/sax.mixins.json +++ b/src/main/resources/sax.mixins.json @@ -3,9 +3,9 @@ "package": "dev.hephaestus.sax.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "VisionAccessor", - "server.DeObfuscateTargetedBlock", - "world.ImplementOreChunk" + "MixinServerWorld", + "MixinWorldChunk", + "VisionAccessor" ], "client": [ ],