diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 00000000..31245d31 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,72 @@ +name: deploy + +on: + push: + tags: + - 'v*' + +jobs: + release: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + outputs: + release_url: ${{ steps.create_release.outputs.upload_url }} + + build: + name: Build Carpetmod + runs-on: ubuntu-latest + needs: release + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-java@v2 + with: + java-version: 8 + distribution: temurin + + - name: Set output + id: vars + run: echo ::set-output name=tag::${GITHUB_REF#refs/*/v} + + - name: Cache Gradle Packages + uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + + - name: Grant execute permissions to gradlew + run: chmod +x gradlew + + - name: Build gradle + env: + VERSION: ${{ steps.vars.outputs.tag }} + SKIP_PROMPT: true + run: | + ./gradlew setupCarpetmod + ./gradlew createRelease + mv build/distributions/Carpetmod_dev.zip build/distributions/Carpet_$VERSION.zip + + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.release.outputs.release_url }} + asset_path: ./build/distributions/Carpet_${{ steps.vars.outputs.tag }}.zip + asset_name: Carpet_${{ steps.vars.outputs.tag }}.zip + asset_content_type: application/zip \ No newline at end of file diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml new file mode 100644 index 00000000..97403755 --- /dev/null +++ b/.github/workflows/pull-requests.yaml @@ -0,0 +1,34 @@ +name: Build on Pull Request + +on: + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + java-version: 8 + distribution: temurin + - name: Cache Gradle Packages + uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + - name: Grant execute permissions to gradlew + run: chmod +x gradlew + - name: Build gradle + env: + SKIP_PROMPT: true + run: | + ./gradlew setupCarpetmod + ./gradlew createRelease + + - uses: actions/upload-artifact@v2 + with: + name: carpet-dev-${{ github.event.number }} + path: build/distributions/Carpetmod_dev.zip diff --git a/build.gradle b/build.gradle index 77f56bbc..8f1858c0 100644 --- a/build.gradle +++ b/build.gradle @@ -143,6 +143,8 @@ gradle.taskGraph.whenReady void warnOverwrite() { + if (System.getenv("SKIP_PROMPT") != null) + return ant.input(message: 'WARNING: this will overwrite your working changes. Continue? (y/n)', addproperty: 'answer', defaultValue: 'y') def answer = ant.properties.answer.toLowerCase() if (answer != 'y' && answer != 'yes') diff --git a/carpetmodSrc/carpet/CarpetServer.java b/carpetmodSrc/carpet/CarpetServer.java index 11b665aa..5d88c46c 100644 --- a/carpetmodSrc/carpet/CarpetServer.java +++ b/carpetmodSrc/carpet/CarpetServer.java @@ -23,6 +23,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.Tuple; import net.minecraft.world.WorldServer; +import org.apache.logging.log4j.LogManager; +import redstone.multimeter.server.MultimeterServer; public class CarpetServer // static for now - easier to handle all around the code, its one anyways { @@ -32,15 +34,24 @@ public class CarpetServer // static for now - easier to handle all around the co public static MinecraftServer minecraft_server; public static PluginChannelManager pluginChannels; - public static RSMMServer rsmmServer; - public static ToggleableChannelHandler rsmmChannel; + public static RSMMServer legacyRsmmServer; + public static MultimeterServer rsmmServer; + public static ToggleableChannelHandler legacyRsmmChannel; public static ToggleableChannelHandler wecuiChannel; public static boolean playerInventoryStacking = false; + public static int limitITTCounter; private static CarpetClientServer CCServer; public static void init(MinecraftServer server) //aka constructor of this static singleton class { + if (JavaVersionUtil.JAVA_VERSION != 8) + { + LogManager.getLogger().warn("!!!!!!!!!!"); + LogManager.getLogger().warn("1.12 TECH SERVERS SHOULD BE RUN USING JAVA 8, DETECTED JAVA " + JavaVersionUtil.JAVA_VERSION); + LogManager.getLogger().warn("!!!!!!!!!!"); + } + minecraft_server = server; pluginChannels = new PluginChannelManager(server); pluginChannels.register(PUBSUB_MESSENGER); @@ -48,8 +59,9 @@ public static void init(MinecraftServer server) //aka constructor of this static CCServer = new CarpetClientServer(server); pluginChannels.register(CCServer); - rsmmServer = new RSMMServer(server); - rsmmChannel = new ToggleableChannelHandler(pluginChannels, rsmmServer.createChannelHandler(), false); + rsmmServer = new MultimeterServer(server); + legacyRsmmServer = new RSMMServer(server); + legacyRsmmChannel = new ToggleableChannelHandler(pluginChannels, legacyRsmmServer.createChannelHandler(), false); wecuiChannel = new ToggleableChannelHandler(pluginChannels, WorldEditBridge.createChannelHandler(), false); } public static void onServerLoaded(MinecraftServer server) @@ -110,7 +122,7 @@ public static void onWorldsSaved(MinecraftServer server) public static void tick(MinecraftServer server) { TickSpeed.tick(server); - if (CarpetSettings.redstoneMultimeter) + if (CarpetSettings.redstoneMultimeterLegacy) { TickStartEventDispatcher.dispatchEvent(server.getTickCounter()); } diff --git a/carpetmodSrc/carpet/CarpetSettings.java b/carpetmodSrc/carpet/CarpetSettings.java index 8850252c..f26a591f 100644 --- a/carpetmodSrc/carpet/CarpetSettings.java +++ b/carpetmodSrc/carpet/CarpetSettings.java @@ -25,6 +25,7 @@ import carpet.utils.TickingArea; import carpet.worldedit.WorldEditBridge; import net.minecraft.block.BlockFalling; +import net.minecraft.command.NumberInvalidException; import net.minecraft.init.Blocks; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.util.math.AxisAlignedBB; @@ -44,7 +45,7 @@ public class CarpetSettings public static boolean locked = false; // TODO: replace these constants at build time - public static final String carpetVersion = "v21_07_16"; + public static final String carpetVersion = "v22_03_22"; public static final String minecraftVersion = "1.12.2"; public static final String mcpMappings = "39-1.12"; @@ -87,10 +88,15 @@ public class CarpetSettings }) public static boolean commandBlockInfo = true; - @Rule(desc = "Enables /loadchunk command", category = COMMANDS, extra = { - "Loads a chunk remotely" + @Rule(desc = "Enables /chunk command", category = COMMANDS, extra = { + "chunk info command" }) - public static boolean commandLoadChunk = true; + public static boolean commandChunk = true; + + @Rule(desc = "Enables /loadedChunks command", category = COMMANDS, extra = { + "Get information of the loaded chunks hashmap" + }) + public static boolean commandLoadedChunks = true; @Rule(desc = "Enables /entityinfo command", category = COMMANDS, extra = { "Also enables yellow carpet placement action if 'carpets' rule is turned on as well" @@ -225,6 +231,9 @@ private static boolean validateInstantScheduling(boolean value) { @Rule(desc = "Enables controlable TNT jump angle RNG for debuging.", category = TNT) public static boolean TNTAdjustableRandomAngle; + @Rule(desc = "/tp will teleport the players across dimensions", category = CREATIVE) + public static boolean tpAcrossDimensions = true; + @Rule(desc = "Allows to place blocks in different orientations. Requires Carpet Client", category = CREATIVE, extra = { "Also prevents rotations upon placement of dispensers and furnaces", "when placed into a world by commands" @@ -290,13 +299,18 @@ public static enum HopperCounters @SurvivalDefault public static boolean cactusCounter = false; - @Rule(desc = "Enables integration with redstone multimeter mod", category = {CREATIVE, SURVIVAL}, validator = "validateRedstoneMultimeter", extra = { + @Rule(desc = "Enables integration with NarcolepticFrog's Redstone Multimeter mod", category = {CREATIVE, SURVIVAL}, validator = "validateRedstoneMultimeterLegacy", extra = { "Required clients with RSMM Mod by Narcoleptic Frog. Enables multiplayer experience with RSMM Mod" }) + public static boolean redstoneMultimeterLegacy = false; + + @Rule(desc = "Enables integration with the new Redstone Multimeter mod", category = {CREATIVE, SURVIVAL, COMMANDS}, extra = { + "To use, the new Redstone Multimeter mod must be installed client-side as well" + }) public static boolean redstoneMultimeter = false; - private static boolean validateRedstoneMultimeter(boolean value) { - CarpetServer.rsmmChannel.setEnabled(value); + private static boolean validateRedstoneMultimeterLegacy(boolean value) { + CarpetServer.legacyRsmmChannel.setEnabled(value); return true; } @@ -478,6 +492,12 @@ public static enum WhereToChunkSavestate { * Rules in this category should end with the "Fix" suffix */ + @Rule(desc = "A limiter for updates happening on the main thread to prevent crashes on instant tile tick.", category = FIX, options = {"0", "1000000", "10000000"}) + public static int limitITTupdates = 0; + + @Rule(desc = "Fixes the async packet bugs related to asynch observer updates.", category = FIX) + public static boolean asyncPacketUpdatesFix; + @Rule(desc = "Fixes the pearl bugs removing them when players relog, similar fix to mc1.15.", category = FIX) public static boolean fixedPearlBugs; @@ -627,9 +647,6 @@ public static enum RedstoneDustAlgorithm { }) public static boolean boundingBoxFix = false; - @Rule(desc = "Blocks inherit the original light opacity and light values while being pushed with a piston", category = OPTIMIZATIONS) - public static boolean movingBlockLightOptimization = false; - @Rule(desc = "Chunk saving issues that causes entites and blocks to duplicate or disappear", category = FIX, extra = "By Theosib") @BugFixDefault public static boolean entityDuplicationFix = false; @@ -775,6 +792,9 @@ private static boolean validateRandomTickOptimization(boolean value) { @Rule(desc = "Sends invisible duplicate UUID entities to clients", category = FIX) public static boolean sendDuplicateEntitiesToClients = false; + @Rule(desc = "Enables best-effort saving of savestated chunks", category = FIX) + public static boolean saveSavestates = false; + // ===== FEATURES ===== // @Rule(desc = "Enables skyblock on 1.12, all blocks but end portal frames will be removed in newly generated chunks.", category = FEATURE, extra = "WARNING! Don't turn on if not planning to play skyblock.") @@ -975,6 +995,10 @@ private static boolean validateTileTickLimit(int value) { @Rule(desc = "Changes default tnt fuse.", category = CREATIVE, validator = "validatePositive", options = {"70", "80", "100"}) public static int tntFuseLength = 80; + + @Rule(desc = "Removes tnt applying velocity to other entities.", category = CREATIVE) + public static boolean removeTNTVelocity = false; + // ===== API ===== // /** diff --git a/carpetmodSrc/carpet/commands/CarpetCommands.java b/carpetmodSrc/carpet/commands/CarpetCommands.java index edc73117..142de5dc 100644 --- a/carpetmodSrc/carpet/commands/CarpetCommands.java +++ b/carpetmodSrc/carpet/commands/CarpetCommands.java @@ -3,18 +3,24 @@ import carpet.CarpetServer; import narcolepticfrog.rsmm.MeterCommand; import net.minecraft.command.CommandHandler; +import redstone.multimeter.command.MeterGroupCommand; public class CarpetCommands { public static void register(CommandHandler handler) { // Sorted alphabetically to make merge conflicts less likely + // For Xcom: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + handler.registerCommand(new CommandAutosave()); handler.registerCommand(new CommandBlockInfo()); handler.registerCommand(new CommandCarpet()); + handler.registerCommand(new CommandChunk()); + handler.registerCommand(new CommandColon()); handler.registerCommand(new CommandCounter()); handler.registerCommand(new CommandDebugCarpet()); handler.registerCommand(new CommandDebuglogger()); handler.registerCommand(new CommandDistance()); handler.registerCommand(new CommandEntityInfo()); + handler.registerCommand(new CommandFeel()); handler.registerCommand(new CommandFillBiome()); handler.registerCommand(new CommandGMC()); handler.registerCommand(new CommandGMS()); @@ -22,8 +28,9 @@ public static void register(CommandHandler handler) { handler.registerCommand(new CommandLagSpike()); handler.registerCommand(new CommandLazyChunkBehavior()); handler.registerCommand(new CommandLight()); - handler.registerCommand(new CommandLoadChunk()); + handler.registerCommand(new CommandLoadedChunks()); handler.registerCommand(new CommandLog()); + handler.registerCommand(new CommandPalette()); handler.registerCommand(new CommandPerimeter()); handler.registerCommand(new CommandPing()); handler.registerCommand(new CommandPlayer()); @@ -42,9 +49,12 @@ public static void register(CommandHandler handler) { handler.registerCommand(new CommandUnload13()); handler.registerCommand(new CommandUpdateCarpet()); handler.registerCommand(new CommandWaypoint()); + handler.registerCommand(new CommandZetBlock()); // ----- RSMM Start ----- // - handler.registerCommand(new MeterCommand(CarpetServer.rsmmServer)); + handler.registerCommand(new MeterCommand(CarpetServer.legacyRsmmServer)); // ----- RSMM End ----- // + + handler.registerCommand(new MeterGroupCommand(CarpetServer.rsmmServer)); } } diff --git a/carpetmodSrc/carpet/commands/CommandCarpetBase.java b/carpetmodSrc/carpet/commands/CommandCarpetBase.java index 1feceef7..f024c888 100644 --- a/carpetmodSrc/carpet/commands/CommandCarpetBase.java +++ b/carpetmodSrc/carpet/commands/CommandCarpetBase.java @@ -4,6 +4,7 @@ import carpet.utils.Messenger; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; +import net.minecraft.command.NumberInvalidException; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.server.MinecraftServer; import net.minecraft.util.text.ITextComponent; @@ -56,5 +57,8 @@ public boolean command_enabled(String command_name, ICommandSender sender) return true; } + protected int parseChunkPosition(String arg, int base) throws NumberInvalidException { + return arg.equals("~") ? base >> 4 : parseInt(arg); + } } diff --git a/carpetmodSrc/carpet/commands/CommandChunk.java b/carpetmodSrc/carpet/commands/CommandChunk.java new file mode 100644 index 00000000..b72c2475 --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandChunk.java @@ -0,0 +1,182 @@ +package carpet.commands; + +import it.unimi.dsi.fastutil.HashCommon; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.management.PlayerChunkMapEntry; +import net.minecraft.util.HttpUtil; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.ChunkProviderServer; +import net.minecraft.world.gen.IChunkGenerator; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +public class CommandChunk extends CommandCarpetBase +{ + /** + * Gets the name of the command + */ + + public String getUsage(ICommandSender sender) + { + return "Usage: chunk "; + } + + public String getName() + { + return "chunk"; + } + + protected World world; + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (!command_enabled("commandChunk", sender)) return; + + if (args.length != 3) { + throw new WrongUsageException(getUsage(sender)); + } + + world = sender.getEntityWorld(); + try { + int chunkX = parseChunkPosition(args[1], sender.getPosition().getX()); + int chunkZ = parseChunkPosition(args[2], sender.getPosition().getZ()); + + switch (args[0]){ + case "load": + world.getChunk(chunkX, chunkZ); + sender.sendMessage(new TextComponentString("Chunk " + chunkX + ", " + chunkZ + " loaded")); + return; + case "unload": + unload(sender, chunkX, chunkZ); + return; + case "regen": + regen(sender, chunkX, chunkZ); + return; + case "repop": + repop(sender, chunkX, chunkZ); + return; + case "asyncrepop": + asyncrepop(sender, chunkX, chunkZ); + return; + case "info": + default: + info(sender, chunkX, chunkZ); + + } + }catch (Exception e){ + throw new WrongUsageException(getUsage(sender)); + } + } + + private boolean checkRepopLoaded(int x, int z){ + return world.isChunkLoaded(x, z, false) + && world.isChunkLoaded(x+1, z, false) + && world.isChunkLoaded(x, z+1, false) + && world.isChunkLoaded(x+1, z+1, false); + } + + private void regen(ICommandSender sender, int x, int z) { + if(!checkRepopLoaded(x, z)) { + sender.sendMessage(new TextComponentString(("Area not loaded for re-population"))); + } + + ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider(); + long i = ChunkPos.asLong(x, z); + chunkProvider.loadedChunks.remove(i); + Chunk chunk = chunkProvider.chunkGenerator.generateChunk(x, z); + chunkProvider.loadedChunks.put(i, chunk); + chunk.onLoad(); + chunk.setTerrainPopulated(true); + chunk.onTick(false); + PlayerChunkMapEntry entry = ((WorldServer)world).playerChunkMap.getEntry(x, z); + if (entry != null && entry.chunk != null) { + entry.chunk = chunk; + entry.sentToPlayers = false; + entry.sendToPlayers(); + } + } + + private void repop(ICommandSender sender, int x, int z) { + if(!checkRepopLoaded(x, z)) { + sender.sendMessage(new TextComponentString(("Area not loaded for re-population"))); + } + + ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider(); + IChunkGenerator chunkGenerator = chunkProvider.chunkGenerator; + Chunk chunk = chunkProvider.loadChunk(x, z); + chunk.setUnpopulated(); + chunk.populate(chunkProvider, chunkGenerator); + } + + private void asyncrepop(ICommandSender sender, int x, int z) { + if(!checkRepopLoaded(x, z)) { + sender.sendMessage(new TextComponentString(("Area not loaded for re-population"))); + } + + HttpUtil.DOWNLOADER_EXECUTOR.submit(() -> { + try { + ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider(); + IChunkGenerator chunkGenerator = chunkProvider.chunkGenerator; + Chunk chunk = chunkProvider.loadChunk(x, z); + chunk.setUnpopulated(); + chunk.populate(chunkProvider, chunkGenerator); + System.out.println("Chunk async repop end."); + } catch(Throwable e) { + e.printStackTrace(); + } + }); + } + + protected void info(ICommandSender sender, int x, int z) throws NoSuchFieldException, IllegalAccessException { + if(!world.isChunkLoaded(x, z, false)) { + sender.sendMessage(new TextComponentString(("Chunk is not loaded"))); + } + + long i = ChunkPos.asLong(x, z); + ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider(); + int mask = CommandLoadedChunks.getMask((Long2ObjectOpenHashMap) provider.loadedChunks); + long key = HashCommon.mix(i) & mask; + sender.sendMessage(new TextComponentString(("Chunk ideal key is " + key))); + if (world.isSpawnChunk(x, z)) + sender.sendMessage(new TextComponentString(("Spawn Chunk"))); + } + + protected void unload(ICommandSender sender, int x, int z){ + if(!world.isChunkLoaded(x, z, false)) { + sender.sendMessage(new TextComponentString(("Chunk is not loaded"))); + return; + } + Chunk chunk = world.getChunk(x, z); + ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider(); + provider.queueUnload(chunk); + sender.sendMessage(new TextComponentString(("Chunk is queue to unload"))); + } + + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { + int chunkX = sender.getPosition().getX() >> 4; + int chunkZ = sender.getPosition().getZ() >> 4; + + if (args.length == 1) { + return getListOfStringsMatchingLastWord(args, "info", "load", "unload", "regen", "repop", "asyncrepop"); + } else if (args.length == 2) { + return getListOfStringsMatchingLastWord(args, Integer.toString(chunkX), "~"); + } else if (args.length == 3) { + return getListOfStringsMatchingLastWord(args, Integer.toString(chunkZ), "~"); + } else { + return Collections.emptyList(); + } + } +} diff --git a/carpetmodSrc/carpet/commands/CommandColon.java b/carpetmodSrc/carpet/commands/CommandColon.java new file mode 100644 index 00000000..b88a29bb --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandColon.java @@ -0,0 +1,318 @@ +package carpet.commands; + +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import javax.annotation.Nullable; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandClone; +import net.minecraft.command.CommandException; +import net.minecraft.command.CommandResultStats; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.NextTickListEntry; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.StructureBoundingBox; + +import carpet.CarpetSettings; +import carpet.worldedit.WorldEditBridge; +import net.minecraft.entity.player.EntityPlayerMP; + +public class CommandColon extends CommandBase +{ + /** + * Gets the name of the command + */ + public String getName() + { + return "colon"; + } + + /** + * Return the required permission level for this command. + */ + public int getRequiredPermissionLevel() + { + return 2; + } + + /** + * Gets the usage string for the command. + */ + public String getUsage(ICommandSender sender) + { + return "commands.clone.usage"; + } + + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (args.length < 9) + { + throw new WrongUsageException("commands.clone.usage", new Object[0]); + } + else + { + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, 0); + BlockPos blockpos = parseBlockPos(sender, args, 0, false); + BlockPos blockpos1 = parseBlockPos(sender, args, 3, false); + BlockPos blockpos2 = parseBlockPos(sender, args, 6, false); + StructureBoundingBox structureboundingbox = new StructureBoundingBox(blockpos, blockpos1); + StructureBoundingBox structureboundingbox1 = new StructureBoundingBox(blockpos2, blockpos2.add(structureboundingbox.getLength())); + + boolean flag = false; + Block block = null; + Predicate predicate = null; + + if ((args.length < 11 || !"force".equals(args[10]) && !"move".equals(args[10]) && !"force_noupdate".equals(args[10]) && !"move_noupdate".equals(args[10])) && structureboundingbox.intersectsWith(structureboundingbox1)) + { + throw new CommandException("commands.clone.noOverlap", new Object[0]); + } + else + { + if (args.length >= 11 && ("move".equals(args[10]) || "move_noupdate".equals(args[10]))) + { + flag = true; + } + + boolean update = true; + if (args.length >= 11 && ("noupdate".equals(args[10]) || "force_noupdate".equals(args[10]) || "move_noupdate".equals(args[10]))) + { + update = false; + } + + if (structureboundingbox.minY >= 0 && structureboundingbox.maxY < 256 && structureboundingbox1.minY >= 0 && structureboundingbox1.maxY < 256) + { + World world = sender.getEntityWorld(); + + boolean flag1 = false; + + if (args.length >= 10) + { + if ("masked".equals(args[9])) + { + flag1 = true; + } + else if ("filtered".equals(args[9])) + { + if (args.length < 12) + { + throw new WrongUsageException("commands.clone.usage", new Object[0]); + } + + block = getBlockByText(sender, args[11]); + + if (args.length >= 13) + { + predicate = convertArgToBlockStatePredicate(block, args[12]); + } + } + } + + List list = Lists.newArrayList(); + List list1 = Lists.newArrayList(); + List list2 = Lists.newArrayList(); + Deque deque = Lists.newLinkedList(); + BlockPos blockpos3 = new BlockPos(structureboundingbox1.minX - structureboundingbox.minX, structureboundingbox1.minY - structureboundingbox.minY, structureboundingbox1.minZ - structureboundingbox.minZ); + + for (int j = structureboundingbox.minZ; j <= structureboundingbox.maxZ; ++j) + { + for (int k = structureboundingbox.minY; k <= structureboundingbox.maxY; ++k) + { + for (int l = structureboundingbox.minX; l <= structureboundingbox.maxX; ++l) + { + BlockPos blockpos4 = new BlockPos(l, k, j); + BlockPos blockpos5 = blockpos4.add(blockpos3); + IBlockState iblockstate = world.getBlockState(blockpos4); + + if ((!flag1 || iblockstate.getBlock() != Blocks.AIR) && (block == null || iblockstate.getBlock() == block && (predicate == null || predicate.apply(iblockstate)))) + { + TileEntity tileentity = world.getTileEntity(blockpos4); + + if (tileentity != null) + { + NBTTagCompound nbttagcompound = tileentity.writeToNBT(new NBTTagCompound()); + list1.add(new StaticCloneData(blockpos5, iblockstate, nbttagcompound)); + deque.addLast(blockpos4); + } + else if (!iblockstate.isFullBlock() && !iblockstate.isFullCube()) + { + list2.add(new StaticCloneData(blockpos5, iblockstate, (NBTTagCompound)null)); + deque.addFirst(blockpos4); + } + else + { + list.add(new StaticCloneData(blockpos5, iblockstate, (NBTTagCompound)null)); + deque.addLast(blockpos4); + } + } + } + } + } + + EntityPlayerMP worldEditPlayer = sender instanceof EntityPlayerMP ? (EntityPlayerMP) sender : null; + + if (flag) + { + for (BlockPos blockpos6 : deque) + { + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos6, Blocks.AIR.getDefaultState(), null); + TileEntity tileentity1 = world.getTileEntity(blockpos6); + + if (tileentity1 instanceof IInventory) + { + ((IInventory)tileentity1).clear(); + } + + world.setBlockState(blockpos6, Blocks.BARRIER.getDefaultState(), 2 | (update?0:128)); //carpet + } + + for (BlockPos blockpos7 : deque) + { + world.setBlockState(blockpos7, Blocks.AIR.getDefaultState(), (update?3:131)); //carpet + } + } + + List list3 = Lists.newArrayList(); + list3.addAll(list); + list3.addAll(list1); + list3.addAll(list2); + List list4 = Lists.reverse(list3); + + for (StaticCloneData commandclone$staticclonedata : list4) + { + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, commandclone$staticclonedata.pos, commandclone$staticclonedata.blockState, commandclone$staticclonedata.nbt); + TileEntity tileentity2 = world.getTileEntity(commandclone$staticclonedata.pos); + + if (tileentity2 instanceof IInventory) + { + ((IInventory)tileentity2).clear(); + } + + world.setBlockState(commandclone$staticclonedata.pos, Blocks.BARRIER.getDefaultState(), 2 | (update?0:128)); //carpet + } + + int i = 0; + + for (StaticCloneData commandclone$staticclonedata1 : list3) + { + if (world.setBlockState(commandclone$staticclonedata1.pos, commandclone$staticclonedata1.blockState, 2 | (update?0:128))) //carpet + { + ++i; + } + } + for (StaticCloneData commandclone$staticclonedata2 : list1) + { + TileEntity tileentity3 = world.getTileEntity(commandclone$staticclonedata2.pos); + + if (commandclone$staticclonedata2.nbt != null && tileentity3 != null) + { + commandclone$staticclonedata2.nbt.setInteger("x", commandclone$staticclonedata2.pos.getX()); + commandclone$staticclonedata2.nbt.setInteger("y", commandclone$staticclonedata2.pos.getY()); + commandclone$staticclonedata2.nbt.setInteger("z", commandclone$staticclonedata2.pos.getZ()); + tileentity3.readFromNBT(commandclone$staticclonedata2.nbt); + tileentity3.markDirty(); + } + + world.setBlockState(commandclone$staticclonedata2.pos, commandclone$staticclonedata2.blockState, 2); + } + + /*carpet mod */ + if (update) + { + /*carpet mod end EXTRA INDENTATION START*/ + for (StaticCloneData commandclone$staticclonedata3 : list4) + { + world.notifyNeighborsRespectDebug(commandclone$staticclonedata3.pos, commandclone$staticclonedata3.blockState.getBlock(), false); + } + + List list5 = world.getPendingBlockUpdates(structureboundingbox, false); + + if (list5 != null) + { + for (NextTickListEntry nextticklistentry : list5) + { + if (structureboundingbox.isVecInside(nextticklistentry.position)) + { + BlockPos blockpos8 = nextticklistentry.position.add(blockpos3); + world.scheduleBlockUpdate(blockpos8, nextticklistentry.getBlock(), (int)(nextticklistentry.scheduledTime - world.getWorldInfo().getWorldTotalTime()), nextticklistentry.priority); + } + } + } + } //carpet mod back extra indentation + + if (i <= 0) + { + throw new CommandException("commands.clone.failed", new Object[0]); + } + else + { + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, i); + notifyCommandListener(sender, this, "commands.clone.success", new Object[] {i}); + } + } + else + { + throw new CommandException("commands.clone.outOfWorld", new Object[0]); + } + } + } + } + + /** + * Get a list of options for when the user presses the TAB key + */ + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) + { + if (args.length > 0 && args.length <= 3) + { + return getTabCompletionCoordinate(args, 0, targetPos); + } + else if (args.length > 3 && args.length <= 6) + { + return getTabCompletionCoordinate(args, 3, targetPos); + } + else if (args.length > 6 && args.length <= 9) + { + return getTabCompletionCoordinate(args, 6, targetPos); + } + else if (args.length == 10) + { + return getListOfStringsMatchingLastWord(args, new String[] {"replace", "masked", "filtered"}); + } + else if (args.length == 11) + { + return getListOfStringsMatchingLastWord(args, new String[] {"normal", "force", "move", "noupdate", "force_noupdate", "move_noupdate"}); + } + else + { + return args.length == 12 && "filtered".equals(args[9]) ? getListOfStringsMatchingLastWord(args, Block.REGISTRY.getKeys()) : Collections.emptyList(); + } + } + + static class StaticCloneData + { + public final BlockPos pos; + public final IBlockState blockState; + public final NBTTagCompound nbt; + + public StaticCloneData(BlockPos posIn, IBlockState stateIn, NBTTagCompound compoundIn) + { + this.pos = posIn; + this.blockState = stateIn; + this.nbt = compoundIn; + } + } +} diff --git a/carpetmodSrc/carpet/commands/CommandFeel.java b/carpetmodSrc/carpet/commands/CommandFeel.java new file mode 100644 index 00000000..e3e87d93 --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandFeel.java @@ -0,0 +1,270 @@ +package carpet.commands; + +import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.function.Predicate; +import javax.annotation.Nullable; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.CommandResultStats; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.nbt.NBTException; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import carpet.CarpetSettings; +import carpet.helpers.CapturedDrops; +import carpet.worldedit.WorldEditBridge; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayerMP; + +public class CommandFeel extends CommandBase +{ + /** + * Gets the name of the command + */ + public String getName() + { + return "feel"; + } + + /** + * Return the required permission level for this command. + */ + public int getRequiredPermissionLevel() + { + return 2; + } + + /** + * Gets the usage string for the command. + */ + public String getUsage(ICommandSender sender) + { + return "commands.fill.usage"; + } + + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (args.length < 7) + { + throw new WrongUsageException("commands.fill.usage", new Object[0]); + } + else + { + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, 0); + BlockPos blockpos = parseBlockPos(sender, args, 0, false); + BlockPos blockpos1 = parseBlockPos(sender, args, 3, false); + Block block = CommandBase.getBlockByText(sender, args[6]); + IBlockState iblockstate; + + if (args.length >= 8) + { + iblockstate = convertArgToBlockState(block, args[7]); + } + else + { + iblockstate = block.getDefaultState(); + } + + BlockPos blockpos2 = new BlockPos(Math.min(blockpos.getX(), blockpos1.getX()), Math.min(blockpos.getY(), blockpos1.getY()), Math.min(blockpos.getZ(), blockpos1.getZ())); + BlockPos blockpos3 = new BlockPos(Math.max(blockpos.getX(), blockpos1.getX()), Math.max(blockpos.getY(), blockpos1.getY()), Math.max(blockpos.getZ(), blockpos1.getZ())); + int i = (blockpos3.getX() - blockpos2.getX() + 1) * (blockpos3.getY() - blockpos2.getY() + 1) * (blockpos3.getZ() - blockpos2.getZ() + 1); + + if (blockpos2.getY() >= 0 && blockpos3.getY() < 256) + { + World world = sender.getEntityWorld(); + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + boolean flag = false; + + if (args.length >= 10 && block.hasTileEntity()) + { + String s = buildString(args, 9); + + try + { + nbttagcompound = JsonToNBT.getTagFromJson(s); + flag = true; + } + catch (NBTException nbtexception) + { + throw new CommandException("commands.fill.tagError", new Object[] {nbtexception.getMessage()}); + } + } + + FillType mode; + try { + mode = args.length <= 8 ? FillType.REPLACE : FillType.valueOf(args[8].toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + mode = FillType.REPLACE; + } + Block toReplace = null; + Predicate toReplacePredicate = state -> true; + if ((mode == FillType.REPLACE || mode == FillType.NOUPDATE) && args.length > 9) { + toReplace = CommandBase.getBlockByText(sender, args[9]); + if (args.length > 10 && !args[10].equals("-1") && !args[10].equals("*")) { + toReplacePredicate = CommandBase.convertArgToBlockStatePredicate(toReplace, args[10]); + } + } + + EntityPlayerMP worldEditPlayer = sender instanceof EntityPlayerMP ? (EntityPlayerMP) sender : null; + NBTTagCompound worldEditTag = flag ? nbttagcompound : null; + + List list = Lists.newArrayList(); + i = 0; + + for (int l = blockpos2.getZ(); l <= blockpos3.getZ(); ++l) + { + for (int i1 = blockpos2.getY(); i1 <= blockpos3.getY(); ++i1) + { + for (int j1 = blockpos2.getX(); j1 <= blockpos3.getX(); ++j1) + { + BlockPos blockpos4 = new BlockPos(j1, i1, l); + + if (args.length >= 9) + { + if (mode != FillType.OUTLINE && mode != FillType.HOLLOW) + { + if (mode == FillType.DESTROY) + { + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos4, Blocks.AIR.getDefaultState(), worldEditTag); + CapturedDrops.setCapturingDrops(true); + world.destroyBlock(blockpos4, true); + CapturedDrops.setCapturingDrops(false); + for (EntityItem drop : CapturedDrops.getCapturedDrops()) + WorldEditBridge.recordEntityCreation(worldEditPlayer, world, drop); + CapturedDrops.clearCapturedDrops(); + } + else if (mode == FillType.KEEP) + { + if (!world.isAirBlock(blockpos4)) + { + continue; + } + } + else if ((mode == FillType.REPLACE || mode == FillType.NOUPDATE) && !block.hasTileEntity() && args.length > 9) + { + IBlockState state = world.getBlockState(blockpos4); + if (state.getBlock() != toReplace || !toReplacePredicate.test(state)) + { + continue; + } + } + } + else if (j1 != blockpos2.getX() && j1 != blockpos3.getX() && i1 != blockpos2.getY() && i1 != blockpos3.getY() && l != blockpos2.getZ() && l != blockpos3.getZ()) + { + if (mode == FillType.HOLLOW) + { + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos4, Blocks.AIR.getDefaultState(), worldEditTag); + world.setBlockState(blockpos4, Blocks.AIR.getDefaultState(), 2); + list.add(blockpos4); + } + + continue; + } + } + + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos4, iblockstate, worldEditTag); + TileEntity tileentity1 = world.getTileEntity(blockpos4); + + if (tileentity1 != null && tileentity1 instanceof IInventory) + { + ((IInventory)tileentity1).clear(); + } + + if (world.setBlockState(blockpos4, iblockstate, 2 | (mode != FillType.NOUPDATE?0:128) )) //CM + { + list.add(blockpos4); + ++i; + + if (flag) + { + TileEntity tileentity = world.getTileEntity(blockpos4); + + if (tileentity != null) + { + nbttagcompound.setInteger("x", blockpos4.getX()); + nbttagcompound.setInteger("y", blockpos4.getY()); + nbttagcompound.setInteger("z", blockpos4.getZ()); + tileentity.readFromNBT(nbttagcompound); + } + } + } + } + } + } + + /*carpet mod */ + if (mode != FillType.NOUPDATE) + { + /*carpet mod end EXTRA INDENT*/ + for (BlockPos blockpos5 : list) + { + Block block2 = world.getBlockState(blockpos5).getBlock(); + world.notifyNeighborsRespectDebug(blockpos5, block2, false); + } + } //carpet mod back extra indentation + + if (i <= 0) + { + throw new CommandException("commands.fill.failed", new Object[0]); + } + else + { + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, i); + notifyCommandListener(sender, this, "commands.fill.success", new Object[] {i}); + } + } + else + { + throw new CommandException("commands.fill.outOfWorld", new Object[0]); + } + } + } + + /** + * Get a list of options for when the user presses the TAB key + */ + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) + { + if (args.length > 0 && args.length <= 3) + { + return getTabCompletionCoordinate(args, 0, targetPos); + } + else if (args.length > 3 && args.length <= 6) + { + return getTabCompletionCoordinate(args, 3, targetPos); + } + else if (args.length == 7) + { + return getListOfStringsMatchingLastWord(args, Block.REGISTRY.getKeys()); + } + else if (args.length == 9) + { + return getListOfStringsMatchingLastWord(args, new String[] {"replace", "destroy", "keep", "hollow", "outline", "noupdate", "replace_noupdate"}); + } + else + { + return args.length == 10 && ("replace".equalsIgnoreCase(args[8]) || "noupdate".equalsIgnoreCase(args[8])) ? getListOfStringsMatchingLastWord(args, Block.REGISTRY.getKeys()) : Collections.emptyList(); + } + } + + enum FillType { + REPLACE, DESTROY, KEEP, HOLLOW, OUTLINE, NOUPDATE; + } +} diff --git a/carpetmodSrc/carpet/commands/CommandLoadChunk.java b/carpetmodSrc/carpet/commands/CommandLoadChunk.java deleted file mode 100644 index 89a2f563..00000000 --- a/carpetmodSrc/carpet/commands/CommandLoadChunk.java +++ /dev/null @@ -1,65 +0,0 @@ -package carpet.commands; - -import carpet.CarpetSettings; -import carpet.utils.BlockInfo; -import carpet.utils.Messenger; -import com.google.common.collect.Lists; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.WrongUsageException; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.world.World; - -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.List; - -public class CommandLoadChunk extends CommandCarpetBase -{ - /** - * Gets the name of the command - */ - - public String getUsage(ICommandSender sender) - { - return "Usage: loadchunk "; - } - - public String getName() - { - return "loadchunk"; - } - - /** - * Callback for when the command is executed - */ - public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException - { - if (!command_enabled("commandLoadChunk", sender)) return; - - if (args.length != 2) - { - throw new WrongUsageException(getUsage(sender), new Object[0]); - } - int chunkX = parseInt(args[0]); - int chunkZ = parseInt(args[1]); - World world = sender.getEntityWorld(); - world.getChunk(chunkX, chunkZ); - sender.sendMessage(new TextComponentString("Chunk" + chunkX + ", " + chunkZ + " loaded")); - } - - public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { - int chunkX = sender.getPosition().getX() >> 4; - int chunkZ = sender.getPosition().getZ() >> 4; - - if (args.length == 1) { - return getListOfStringsMatchingLastWord(args, Integer.toString(chunkX)); - } else if (args.length == 2) { - return getListOfStringsMatchingLastWord(args, Integer.toString(chunkZ)); - } else { - return Collections.emptyList(); - } - } -} diff --git a/carpetmodSrc/carpet/commands/CommandLoadedChunks.java b/carpetmodSrc/carpet/commands/CommandLoadedChunks.java new file mode 100644 index 00000000..a0a0cb92 --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandLoadedChunks.java @@ -0,0 +1,334 @@ +package carpet.commands; + + +import carpet.CarpetSettings; +import it.unimi.dsi.fastutil.HashCommon; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.ChunkProviderServer; + +import javax.annotation.Nullable; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class CommandLoadedChunks extends CommandCarpetBase +{ + /** + * Gets the name of the command + */ + protected World world; + public String getUsage(ICommandSender sender) + { + return "Usage: loadedChunks "; + } + + public String getName() + { + return "loadedChunks"; + } + + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (!command_enabled("commandLoadedChunks", sender)) return; + if (args.length == 0) throw new WrongUsageException(getUsage(sender)); + + world = sender.getEntityWorld(); + + try { + switch (args[0]){ + case "size": + size(server, sender, args); + break; + case "search": + if (args.length != 3) throw new WrongUsageException(getUsage(sender)); + search(sender, parseChunkPosition(args[1], sender.getPosition().getX()), parseChunkPosition(args[2], sender.getPosition().getZ())); + break; + case "remove": + if (args.length != 3) throw new WrongUsageException(getUsage(sender)); + remove(sender, parseChunkPosition(args[1], sender.getPosition().getX()), parseChunkPosition(args[2], sender.getPosition().getZ())); + break; + case "add": + if (args.length != 3) throw new WrongUsageException(getUsage(sender)); + add(sender, parseChunkPosition(args[1], sender.getPosition().getX()), parseChunkPosition(args[2], sender.getPosition().getZ())); + break; + case "inspect": + inspect(server, sender, args); + break; + case "dump": + String fileName = "loadedchunks-" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSSS").format(new Date()) + ".csv"; + try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fileName)))) { + pw.println("index,key,x,z,hash"); + long[] keys = (long[]) getPrivateMethods(world, "key"); + Object[] values = (Object[]) getPrivateMethods(world, "value"); + int getHashSize = (int) getPrivateMethods(world, "n"); + for (int i = 0, n = getHashSize; i <= n; i++) { + long key = keys[i]; + Chunk val = (Chunk) values[i]; + if (val == null) { + pw.println(i + ",,,,"); + } else { + pw.printf("%d,%d,%d,%d,%d\n", i, key, val.x, val.z, HashCommon.mix(key) & (n - 1)); + } + } + pw.flush(); + } + notifyCommandListener(sender, this, "Written to %s", fileName); + break; + default: + throw new WrongUsageException(getUsage(sender)); + } + }catch (Exception exception){ + exception.printStackTrace(); + throw new CommandException(exception.getMessage()); + } + + } + + private Object getPrivateMethods(World world, String name){ + ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider(); + Long2ObjectOpenHashMap loadedChunks = (Long2ObjectOpenHashMap) provider.loadedChunks; + try { + Field f = loadedChunks.getClass().getDeclaredField(name); + f.setAccessible(true); + return f.get(loadedChunks); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + protected Long2ObjectOpenHashMap getLoadedChunks (ICommandSender sender){ + world = sender.getEntityWorld(); + ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider(); + return (Long2ObjectOpenHashMap) provider.loadedChunks; + } + + protected void size(MinecraftServer server, ICommandSender sender, String[] args) + throws CommandException, NoSuchFieldException, IllegalAccessException { + Long2ObjectOpenHashMap loadedChunks = this.getLoadedChunks(sender); + sender.sendMessage(new TextComponentString(String.format("Hashmap size is %d, %.2f", loadedChunks.size(), getFillLevel(loadedChunks)))); + } + + protected void inspect(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException, NoSuchFieldException, IllegalAccessException { + Long2ObjectOpenHashMap loadedChunks = this.getLoadedChunks(sender); + Object[] chunks = getValues(loadedChunks); + int mask = getMask(loadedChunks); + Integer start = 0, end = chunks.length; + Optional keyClass = Optional.empty(); + for (int i = 1; i < args.length; i++){ + switch (args[i]){ + case "from": + start = Integer.valueOf(args[++i]); + break; + case "to": + end = Integer.valueOf(args[++i]);; + break; + case "class": + keyClass = Optional.of(Long.valueOf(args[++i])); + break; + default: + throw new WrongUsageException(getUsage(sender)); + } + } + ArrayList inspections = new ArrayList<>(); + String last = ""; + int lastN = 0; + for (int i = start; (i & mask) != (end & mask); i++) { + Chunk chunk = (Chunk) chunks[i & mask]; + if(keyClass.isPresent()){ + if(chunk == null){ + if(!last.equals("null")){ + if(lastN > 0) + inspections.add(String.format("... %d %s", lastN, last)); + last = "null"; + lastN = 0; + } + lastN++; + continue; + } + if(getKeyClass(chunk, mask) != keyClass.get()){ + if(last != "chunks"){ + if(lastN > 0) + inspections.add(String.format("... %d %s", lastN, last)); + last = "chunks"; + lastN = 0; + } + lastN++; + continue; + } + } + if(last != ""){ + if(lastN > 0) + inspections.add(String.format("... %d %s", lastN, last)); + last = ""; + lastN = 0; + } + String formatted = formatChunk(chunk, i & mask, mask); + inspections.add(formatted); + + } + String result = inspections.stream().collect(Collectors.joining(", ", "[", "]")); + sender.sendMessage(new TextComponentString(result)); + } + + protected void search(ICommandSender sender, int chunkX, int chunkZ) throws NoSuchFieldException, IllegalAccessException { + Long2ObjectOpenHashMap loadedChunks = (Long2ObjectOpenHashMap) ((ChunkProviderServer) world.getChunkProvider()).loadedChunks; + Object[] chunks = getValues(loadedChunks); + int mask = getMask(loadedChunks); + for (int i = 0; i < chunks.length; i++) { + Chunk chunk = (Chunk) chunks[i]; + if(chunk == null) + continue; + if (chunk.x != chunkX || chunk.z != chunkZ) + continue; + sender.sendMessage(new TextComponentString(formatChunk(chunk,i, mask))); + break; + } + } + + protected static HashMap tempChunks = new HashMap<>(); + + protected void add(ICommandSender sender, int x, int z) { + long hash = ChunkPos.asLong(x, z); + if(!tempChunks.containsKey(hash)){ + sender.sendMessage(new TextComponentString(String.format("Chunk (%d, %d) couldn't been found", x, z))); + return; + } + Chunk chunk = tempChunks.get(hash); + Long2ObjectOpenHashMap loadedChunks = getLoadedChunks(); + loadedChunks.put(hash, chunk); + sender.sendMessage(new TextComponentString(String.format("Chunk (%d, %d) has been added back", x, z))); + } + + protected void remove(ICommandSender sender, int x, int z) { + long hash = ChunkPos.asLong(x, z); + + Long2ObjectOpenHashMap loadedChunks = getLoadedChunks(); + if(!loadedChunks.containsKey(hash)){ + sender.sendMessage(new TextComponentString(String.format("Chunk (%d, %d) is not in loaded list", x, z))); + } + Chunk chunk = loadedChunks.remove(hash); + tempChunks.put(hash, chunk); + sender.sendMessage(new TextComponentString(String.format("Chunk (%d, %d) has been removed", x, z))); + } + + protected Long2ObjectOpenHashMap getLoadedChunks(){ + ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider(); + return (Long2ObjectOpenHashMap) provider.loadedChunks; + } + + public String formatChunk(Chunk chunk, int pos, int mask){ + if (chunk == null) { + return String.format("%d: null", pos); + + } + + return String.format("%d: %s(%d, %d) %d", + pos, getChunkDescriber(chunk), chunk.x, chunk.z, + getKeyClass(chunk, mask)); + } + + public String getChunkDescriber(Chunk chunk){ + int x = chunk.x, z = chunk.z; + long hash = ChunkPos.asLong(x, z); + String describer = ""; + if(world.isSpawnChunk(x, z)){ + describer +="S "; + } + if(((hash ^ (hash >>> 16)) & 0xFFFF) == 0){ + describer +="0 "; + } + return describer; + } + + public static long getKeyClass(Chunk chunk, int mask){ + return HashCommon.mix(ChunkPos.asLong(chunk.x, chunk.z)) & mask; + } + + public static int getMaxField(Long2ObjectOpenHashMap hashMap) throws NoSuchFieldException, IllegalAccessException { + Field maxFill = Long2ObjectOpenHashMap.class.getDeclaredField("maxFill"); + maxFill.setAccessible(true); + return (int) maxFill.get(hashMap); + } + + public static int getMask(Long2ObjectOpenHashMap hashMap) throws NoSuchFieldException, IllegalAccessException { + Field mask = Long2ObjectOpenHashMap.class.getDeclaredField("mask"); + mask.setAccessible(true); + return (int) mask.get(hashMap); + } + + public static float getFillLevel(Long2ObjectOpenHashMap hashMap) throws NoSuchFieldException, IllegalAccessException { + return (float) hashMap.size() / getMaxField(hashMap); + } + + public static Object[] getValues(Long2ObjectOpenHashMap hashMap) throws NoSuchFieldException, IllegalAccessException { + Field value = Long2ObjectOpenHashMap.class.getDeclaredField("value"); + value.setAccessible(true); + return (Object[]) value.get(hashMap); + } + + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { + + if (!CarpetSettings.commandLoadedChunks) + { + return Collections.emptyList(); + } + + if (args.length == 1) + { + return getListOfStringsMatchingLastWord(args, + "size", "inspect", "search", "remove", "add", "dump"); + } + + switch (args[0]){ + case "inspect": + switch (args[args.length - 1]){ + case "class": + case "from": + case "to": + return Collections.emptyList(); + } + return getListOfStringsMatchingLastWord(args, + "class", "from", "to"); + case "search": + case "remove": + case "add": + if (args.length > 3) + return Collections.emptyList(); + return getChunkCompletitions(sender, args, 2); + } + + return Collections.emptyList(); + } + + + public List getChunkCompletitions(ICommandSender sender, String[] args, int index) { + int chunkX = sender.getPosition().getX() >> 4; + int chunkZ = sender.getPosition().getZ() >> 4; + + if (args.length == index) { + return getListOfStringsMatchingLastWord(args, Integer.toString(chunkX), "~"); + } else if (args.length == index + 1) { + return getListOfStringsMatchingLastWord(args, Integer.toString(chunkZ), "~"); + } else { + return Collections.emptyList(); + } + } +} diff --git a/carpetmodSrc/carpet/commands/CommandPalette.java b/carpetmodSrc/carpet/commands/CommandPalette.java new file mode 100644 index 00000000..42e30a61 --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandPalette.java @@ -0,0 +1,300 @@ +package carpet.commands; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockColored; +import net.minecraft.block.state.IBlockState; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BitArray; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.World; +import net.minecraft.world.chunk.*; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + +import javax.annotation.Nullable; +import java.util.*; + +public class CommandPalette extends CommandCarpetBase { + /** + * Gets the name of the command + */ + + public String getUsage(ICommandSender sender) { + return "Usage: palette <4-8 | 13>"; + } + + public String getName() { + return "palette"; + } + + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { + if (!command_enabled("commandChunk", sender)) return; + + try { + BlockPos pos = new BlockPos(sender.getPosition().getX(), sender.getPosition().getY(), sender.getPosition().getZ()); + if (args.length < 4 && args[0].equals("posInfo")) { + throw new WrongUsageException(getUsage(sender)); + } else if (args.length >= 4) { + pos = parseBlockPos(sender, args, 1, false); + } + World world = sender.getEntityWorld(); + Chunk chunk = world.getChunk(pos); + ExtendedBlockStorage[] list = chunk.getBlockStorageArray(); + int h = pos.getY() >> 4; + if (h < 0) h = 0; + if (h > 15) h = 15; + ExtendedBlockStorage ebs = list[h]; + BlockStateContainer bsc = ebs.getBlockStateContainer(); + int bits = bsc.getBits(); + + switch (args[0]) { + case "bits": + sender.sendMessage(new TextComponentString("Palette bit size: " + bits)); + return; + case "size": + getSize(sender, bsc); + return; + case "posInfo": + boolean isFull = false; + if (args.length >= 5) isFull = args[4].equals("full"); + Block block = null; + if (args.length >= 6) block = CommandBase.getBlockByText(sender, args[5]); + IBlockState iblockstate = null; + if (args.length >= 7 && block != null) { + iblockstate = convertArgToBlockState(block, args[6]); + } else if (block != null) { + iblockstate = block.getDefaultState(); + } + infoPalette(sender, bsc, pos, isFull, iblockstate); + return; + case "fill": + int bitSize = -1; + int type = 1; + if (args.length >= 5) type = args[4].equals("full") ? 2 : 1; + if (args.length >= 6) bitSize = parseInt(args[5]); + fill(sender, bsc, pos, type, bitSize); + return; + default: + throw new WrongUsageException(getUsage(sender)); + + } + } catch (Exception e) { + e.printStackTrace(); + throw new WrongUsageException(getUsage(sender)); + } + } + + private static IBlockState[] backup = null; + private static HashMap tileEntityList = new HashMap<>(); + + private static void fill(ICommandSender sender, BlockStateContainer bsc, BlockPos pos, int type, int bitSize) { + if (type != 3 && backup != null) type = 3; + + if (bitSize < 1 || bitSize > 64) bitSize = bsc.getStorage().getBitsPerEntry(); + + BlockPos basePos = new BlockPos(pos.getX() >>> 4 << 4, pos.getY() >>> 4 << 4, pos.getZ() >>> 4 << 4); + int color = -1; + int storeJ = -1; + if (type != 3) { + backup = new IBlockState[4096]; + } + HashSet backupSet = new HashSet<>(); + for (int i = 0; i < 4096; i++) { + BlockPos set = getBlockIndex(i, basePos); + if (type == 1) { + int j = i * bitSize / 64; + int k = ((i + 1) * bitSize - 1) / 64; + + if (j != k) { + backup[i] = sender.getEntityWorld().getBlockState(set); + TileEntity te = sender.getEntityWorld().getTileEntity(set); + if (te != null) { + tileEntityList.put(set, te); + sender.getEntityWorld().removeTileEntity(set); + } + sender.getEntityWorld().setBlockState(set, Blocks.GLASS.getDefaultState(), 128); + } + } else if (type == 2) { + backup[i] = sender.getEntityWorld().getBlockState(set); + TileEntity te = sender.getEntityWorld().getTileEntity(set); + if (te != null) { + tileEntityList.put(set, te); + sender.getEntityWorld().removeTileEntity(set); + } + set = getBlockIndex(i, basePos); + int j = i * bitSize / 64; + int k = ((i + 1) * bitSize - 1) / 64; + + if (j != storeJ) { + storeJ = j; + color = (color + 1) & 15; + } + + if (j != k) { + sender.getEntityWorld().setBlockState(set, Blocks.GLASS.getDefaultState(), 128); + } else { + sender.getEntityWorld().setBlockState(set, Blocks.STAINED_GLASS.getDefaultState().withProperty(BlockColored.COLOR, EnumDyeColor.byMetadata(color)), 128); + } + } else if (type == 3) { + if (backup[i] != null && !backupSet.contains(set)) { + backupSet.add(set); + sender.getEntityWorld().setBlockState(set, backup[i], 128); + TileEntity te = tileEntityList.get(set); + if (te != null) { + sender.getEntityWorld().removeTileEntity(set); + te.validate(); + sender.getEntityWorld().setTileEntity(set, te); + } + } + } + } + if (type == 3) { + backup = null; + tileEntityList.clear(); + } + } + + private void infoPalette(ICommandSender sender, BlockStateContainer bsc, BlockPos pos, boolean full, IBlockState blockState) { + BitArray bArray = bsc.getStorage(); + int bits = bArray.getBitsPerEntry(); + int index = getIndex(pos); + int i = index * bits; + int j = i / 64; + int k = ((index + 1) * bits - 1) / 64; + int l = i % 64; + long[] longArray = bArray.getBackingLongArray(); + + if (j == k) { + displayJKBits(sender, longArray[j], l, l + bits - 1, ""); + if (full) { + for (BlockPos bp : getArrayFromJK(j, k, bits, pos)) { + sender.sendMessage(new TextComponentString(bp.toString())); + } + } + } else { + displayJKBits(sender, longArray[j], l, 64, "1"); + displayJKBits(sender, longArray[k], 0, (l + bits - 1) % 64, "2"); + if (full) { + for (BlockPos bp : getArrayFromJK(j, k, bits, pos)) { + sender.sendMessage(new TextComponentString(bp.toString())); + } + } + } + if (blockState != null && bsc.getPalette() instanceof BlockStatePaletteRegistry && j != k) { + int blockStateBits = Block.BLOCK_STATE_IDS.get(blockState); + int leftBits = 64 - l; + int rightBits = bits - leftBits; + int leftMask = (1 << leftBits) - 1; + int rightMask = ((1 << rightBits) - 1) << leftBits; + int blockStateMaskL = blockStateBits & leftMask; + int blockStateMaskR = blockStateBits & rightMask; + sender.sendMessage(new TextComponentString("Left bit match:")); + for (int itr = 0; itr < Block.BLOCK_STATE_IDS.size(); itr++) { + IBlockState ibs = Block.BLOCK_STATE_IDS.getByValue(itr); + if (ibs != null) { + int left = itr & leftMask; + if (left == blockStateMaskL) { + String s = String.format("%" + bits + "s", Integer.toBinaryString(itr)).replace(' ', '0') + " " + ibs.toString().replace("minecraft:", ""); + sender.sendMessage(new TextComponentString(s)); + } + } + } + sender.sendMessage(new TextComponentString("Right bit match:")); + for (int itr = 0; itr < Block.BLOCK_STATE_IDS.size(); itr++) { + IBlockState ibs = Block.BLOCK_STATE_IDS.getByValue(itr); + if (ibs != null) { + int right = itr & rightMask; + if (right == blockStateMaskR) { + String s = String.format("%" + bits + "s", Integer.toBinaryString(itr)).replace(' ', '0') + " " + ibs.toString().replace("minecraft:", ""); + sender.sendMessage(new TextComponentString(s)); + } + } + } + } else if (blockState != null && j != k) { + sender.sendMessage(new TextComponentString("This location doesn't share two bit arrays.")); + } else if (blockState != null && bsc.getPalette() instanceof BlockStatePaletteRegistry) { + sender.sendMessage(new TextComponentString("This subchunk doesn't have enough palettes, add more palettes.")); + } + } + + private static void displayJKBits(ICommandSender sender, long longString, long l1, long l2, String append) { + StringBuilder sb = new StringBuilder(); + + String add = "§f"; + for (int bitNum = 0; bitNum < 64; bitNum++) { + char s = (longString & 1) == 1 ? '1' : '0'; + longString = longString >> 1; + if (bitNum == l1) add = "§c"; + sb.append(add + s); + if (bitNum == l2) add = "§f"; + } + sender.sendMessage(new TextComponentString("§8L" + append + ":" + sb)); + } + + private static BlockPos[] getArrayFromJK(int j, int k, int bits, BlockPos pos) { + BlockPos basePos = new BlockPos(pos.getX() >>> 4 << 4, pos.getY() >>> 4 << 4, pos.getZ() >>> 4 << 4); + ArrayList list = new ArrayList<>(); + for (int index = 0; index < 4096; index++) { + int i = index * bits; + int jj = i / 64; + int kk = ((index + 1) * bits - 1) / 64; + if (jj == j || kk == k || jj == k || kk == j) { + list.add(getBlockIndex(index, basePos)); + } + } + return list.toArray(new BlockPos[0]); + } + + private static int getIndex(BlockPos pos) { + int x = pos.getX() & 15; + int y = pos.getY() & 15; + int z = pos.getZ() & 15; + + return y << 8 | z << 4 | x; + } + + private static BlockPos getBlockIndex(int index, BlockPos pos) { + int x = (pos.getX() & ~0xF) | (index & 0xF); + int y = (pos.getY() & ~0xF) | ((index >>> 8) & 0xF); + int z = (pos.getZ() & ~0xF) | ((index >>> 4) & 0xF); + + return new BlockPos(x, y, z); + } + + private void getSize(ICommandSender sender, BlockStateContainer bsc) { + IBlockStatePalette ibsp = bsc.getPalette(); + if (ibsp instanceof BlockStatePaletteLinear) { + sender.sendMessage(new TextComponentString("Palette size: " + ((BlockStatePaletteLinear) ibsp).paletteSize())); + } else if (ibsp instanceof BlockStatePaletteHashMap) { + sender.sendMessage(new TextComponentString("Palette size: " + ((BlockStatePaletteHashMap) ibsp).paletteSize())); + } else if (ibsp instanceof BlockStatePaletteRegistry) { + sender.sendMessage(new TextComponentString("Palette size MAX aka " + Block.BLOCK_STATE_IDS.size())); + } + } + + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) { + if (args.length == 1) { + return getListOfStringsMatchingLastWord(args, "bits", "size", "posInfo", "fill"); + } else if (args.length >= 2 && args.length <= 4) { + return getTabCompletionCoordinate(args, 1, targetPos); + } else if (args.length == 5 && (args[0].equals("posInfo") || args[0].equals("fill"))) { + return getListOfStringsMatchingLastWord(args, "full", "normal"); + } else if (args.length == 6 && args[0].equals("fill")) { + return getListOfStringsMatchingLastWord(args, "4", "5", "6", "7", "8", "13"); + } else if (args.length == 6 && args[0].equals("posInfo")) { + return getListOfStringsMatchingLastWord(args, Block.REGISTRY.getKeys()); + } else { + return Collections.emptyList(); + } + } +} \ No newline at end of file diff --git a/carpetmodSrc/carpet/commands/CommandZetBlock.java b/carpetmodSrc/carpet/commands/CommandZetBlock.java new file mode 100644 index 00000000..7faf103f --- /dev/null +++ b/carpetmodSrc/carpet/commands/CommandZetBlock.java @@ -0,0 +1,185 @@ +package carpet.commands; + +import carpet.CarpetSettings; +import carpet.helpers.CapturedDrops; +import carpet.worldedit.WorldEditBridge; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.command.*; +import net.minecraft.command.server.CommandSetBlock; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.nbt.NBTException; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +public class CommandZetBlock extends CommandSetBlock { + /** + * Gets the name of the command + */ + public String getName() + { + return "zetblock"; + } + + /** + * Return the required permission level for this command. + */ + public int getRequiredPermissionLevel() + { + return 2; + } + + /** + * Gets the usage string for the command. + */ + public String getUsage(ICommandSender sender) + { + return "commands.setblock.usage"; + } + + /** + * Callback for when the command is executed + */ + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if (args.length < 4) + { + throw new WrongUsageException("commands.setblock.usage", new Object[0]); + } + else + { + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, 0); + BlockPos blockpos = parseBlockPos(sender, args, 0, false); + Block block = CommandBase.getBlockByText(sender, args[3]); + IBlockState iblockstate; + + if (args.length >= 5) + { + iblockstate = convertArgToBlockState(block, args[4]); + } + else + { + iblockstate = block.getDefaultState(); + } + + World world = sender.getEntityWorld(); + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + boolean flag = false; + + if (args.length >= 7 && block.hasTileEntity()) + { + String s = buildString(args, 6); + + try + { + nbttagcompound = JsonToNBT.getTagFromJson(s); + flag = true; + } + catch (NBTException nbtexception) + { + throw new CommandException("commands.setblock.tagError", new Object[] {nbtexception.getMessage()}); + } + } + + EntityPlayerMP worldEditPlayer = sender instanceof EntityPlayerMP ? (EntityPlayerMP) sender : null; + NBTTagCompound worldEditTag = flag ? nbttagcompound : null; + + boolean updates = true; + + if (args.length >= 6) + { + if ("destroy".equals(args[5])) + { + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos, Blocks.AIR.getDefaultState(), worldEditTag); + CapturedDrops.setCapturingDrops(true); + world.destroyBlock(blockpos, true); + CapturedDrops.setCapturingDrops(false); + for (EntityItem drop : CapturedDrops.getCapturedDrops()) + WorldEditBridge.recordEntityCreation(worldEditPlayer, world, drop); + CapturedDrops.clearCapturedDrops(); + + if (block == Blocks.AIR) + { + notifyCommandListener(sender, this, "commands.setblock.success", new Object[0]); + return; + } + } + else if ("keep".equals(args[5]) && !world.isAirBlock(blockpos)) + { + throw new CommandException("commands.setblock.noChange", new Object[0]); + } + else if ("noupdate".equals(args[5])) + { + updates = false; + } + } + + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos, iblockstate, worldEditTag); + + TileEntity tileentity1 = world.getTileEntity(blockpos); + + if (tileentity1 != null && tileentity1 instanceof IInventory) + { + ((IInventory)tileentity1).clear(); + } + + if (!world.setBlockState(blockpos, iblockstate, 2 | (updates ? 0 : 128))) + { + throw new CommandException("commands.setblock.noChange", new Object[0]); + } + else + { + if (flag) + { + TileEntity tileentity = world.getTileEntity(blockpos); + + if (tileentity != null) + { + nbttagcompound.setInteger("x", blockpos.getX()); + nbttagcompound.setInteger("y", blockpos.getY()); + nbttagcompound.setInteger("z", blockpos.getZ()); + tileentity.readFromNBT(nbttagcompound); + } + } + + if (updates) + { + world.notifyNeighborsRespectDebug(blockpos, iblockstate.getBlock(), false); + } + sender.setCommandStat(CommandResultStats.Type.AFFECTED_BLOCKS, 1); + notifyCommandListener(sender, this, "commands.setblock.success", new Object[0]); + } + } + } + + /** + * Get a list of options for when the user presses the TAB key + */ + public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos) + { + if (args.length > 0 && args.length <= 3) + { + return getTabCompletionCoordinate(args, 0, targetPos); + } + else if (args.length == 4) + { + return getListOfStringsMatchingLastWord(args, Block.REGISTRY.getKeys()); + } + else + { + return args.length == 6 ? getListOfStringsMatchingLastWord(args, new String[] {"replace", "destroy", "keep", "noupdate"}) : Collections.emptyList(); + } + } +} diff --git a/carpetmodSrc/carpet/helpers/OptimizedTNT.java b/carpetmodSrc/carpet/helpers/OptimizedTNT.java index 22064f18..68b1fa46 100644 --- a/carpetmodSrc/carpet/helpers/OptimizedTNT.java +++ b/carpetmodSrc/carpet/helpers/OptimizedTNT.java @@ -96,6 +96,11 @@ public static void doExplosionA(Explosion e) { explosionSound++; + // CARPET-SYLKOS + // TNT shouldn't apply velocity to entities + // This also yeets all the calculations tnt does for applying velocity and damage to entities + if(CarpetSettings.removeTNTVelocity) return; + for (int k2 = 0; k2 < entitylist.size(); ++k2) { Entity entity = entitylist.get(k2); @@ -249,6 +254,10 @@ public static void doExplosionB(Explosion e, boolean spawnParticles) } } } + + if(LoggerRegistry.__explosions) { + e.logHelper.onExplosionDone(e.world.getWorldTime()); + } } private static void removeFast(List lst, int index) { diff --git a/carpetmodSrc/carpet/helpers/SaveSavestatesHelper.java b/carpetmodSrc/carpet/helpers/SaveSavestatesHelper.java new file mode 100644 index 00000000..1109b026 --- /dev/null +++ b/carpetmodSrc/carpet/helpers/SaveSavestatesHelper.java @@ -0,0 +1,63 @@ +package carpet.helpers; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.NonNullList; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public class SaveSavestatesHelper { + public static void trySaveItemsCompressed(NBTTagCompound destTag, NonNullList items, boolean saveEmpty) { + List> itemsAndSlots = new ArrayList<>(items.size()); + for (int i = 0; i < items.size(); i++) { + itemsAndSlots.add(Pair.of(i, items.get(i))); + } + + itemsAndSlots.sort((a, b) -> compareItems(a.getRight(), b.getRight())); + + NBTTagList itemsTag = new NBTTagList(); + for (Pair itemAndSlot : itemsAndSlots) { + int slot = itemAndSlot.getLeft(); + ItemStack item = itemAndSlot.getRight(); + if (!item.isEmpty()) { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setByte("Slot", (byte) slot); + item.writeToNBT(itemTag); + itemsTag.appendTag(itemTag); + } + } + + if (!itemsTag.isEmpty() || saveEmpty) { + destTag.setTag("Items", itemsTag); + } + } + + private static int compareItems(ItemStack a, ItemStack b) { + int idA = Item.getIdFromItem(a.getItem()); + int idB = Item.getIdFromItem(b.getItem()); + if (idA != idB) { + return Integer.compare(idA, idB); + } + + NBTTagCompound tagA = a.getTagCompound(); + NBTTagCompound tagB = b.getTagCompound(); + if (tagA != null && tagB != null) { + NBTTagList pagesA = tagA.getTagList("pages", 8); + NBTTagList pagesB = tagB.getTagList("pages", 8); + for (int page = 0; page < Math.min(pagesA.tagCount(), pagesB.tagCount()); page++) { + String pageA = pagesA.getStringTagAt(page); + String pageB = pagesB.getStringTagAt(page); + int cmp = pageA.compareTo(pageB); + if (cmp != 0) { + return cmp; + } + } + } + + return 0; + } +} diff --git a/carpetmodSrc/carpet/helpers/TeleportHelper.java b/carpetmodSrc/carpet/helpers/TeleportHelper.java new file mode 100644 index 00000000..f1ac2775 --- /dev/null +++ b/carpetmodSrc/carpet/helpers/TeleportHelper.java @@ -0,0 +1,41 @@ +package carpet.helpers; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.play.server.SPacketRespawn; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.WorldServer; + +public class TeleportHelper { + + public static void changeDimensions(EntityPlayerMP player, EntityPlayerMP target){ + // Adapted from spectator teleport code (NetHandlerPlayServer::handleSpectate) + double x = target.posX; + double y = target.posY; + double z = target.posZ; + MinecraftServer server = player.getServer(); + assert server != null; + + WorldServer worldFrom = (WorldServer) player.world; + WorldServer worldTo = (WorldServer) target.world; + int dimension = worldTo.provider.getDimensionType().getId(); + player.dimension = dimension; + + player.connection.sendPacket(new SPacketRespawn(dimension, worldFrom.getDifficulty(), worldFrom.getWorldInfo().getTerrainType(), player.interactionManager.getGameType())); + server.getPlayerList().updatePermissionLevel(player); + worldFrom.removeEntityDangerously(player); + player.isDead = false; + player.setLocationAndAngles(x, y, z, (float) target.rotationYaw, (float) target.rotationPitch); + + worldFrom.updateEntityWithOptionalForce(player, false); + worldTo.spawnEntity(player); + worldTo.updateEntityWithOptionalForce(player, false); + + player.setWorld(worldTo); + server.getPlayerList().preparePlayer(player, worldFrom); + + player.setPositionAndUpdate(x, y, z); + player.interactionManager.setWorld(worldTo); + server.getPlayerList().updateTimeAndWeatherForPlayer(player, worldTo); + server.getPlayerList().syncPlayerInventory(player); + } +} diff --git a/carpetmodSrc/carpet/logging/LoggerRegistry.java b/carpetmodSrc/carpet/logging/LoggerRegistry.java index 4aee0dd1..3d4b3237 100644 --- a/carpetmodSrc/carpet/logging/LoggerRegistry.java +++ b/carpetmodSrc/carpet/logging/LoggerRegistry.java @@ -47,6 +47,7 @@ public class LoggerRegistry public static boolean __instantComparators; public static boolean __items; public static boolean __rng; + public static boolean __explosions; public static boolean __recipes; public static boolean __damageDebug; public static boolean __invisDebug; @@ -66,6 +67,7 @@ public static void initLoggers(MinecraftServer server) registerLogger("instantComparators", new Logger(server, "instantComparators", "all", new String[]{"all", "tileTick", "buggy"}, LogHandler.CHAT)); registerLogger("items",new Logger(server, "items", "brief", new String[]{"brief", "full"}, LogHandler.CHAT)); registerLogger("rng", new Logger(server, "rng", null, null, LogHandler.CHAT)); + registerLogger("explosions", new Logger(server, "explosions", "compact", new String[]{"brief", "full", "compact"}, LogHandler.CHAT)); registerLogger("autosave", new Logger(server, "autosave", null, null, LogHandler.HUD)); registerLogger("tps", new Logger(server, "tps", null, null, LogHandler.HUD)); diff --git a/carpetmodSrc/carpet/logging/logHelpers/ExplosionLogHelper.java b/carpetmodSrc/carpet/logging/logHelpers/ExplosionLogHelper.java new file mode 100644 index 00000000..204d6702 --- /dev/null +++ b/carpetmodSrc/carpet/logging/logHelpers/ExplosionLogHelper.java @@ -0,0 +1,104 @@ +package carpet.logging.logHelpers; + +import carpet.logging.LoggerRegistry; +import carpet.utils.Messenger; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.ITextComponent; + +public class ExplosionLogHelper { + + // CARPET-SYLKOS + // Some code yeeted from lntricarpet and gnembon 1.16+ fabric carpet + + public final Vec3d pos; + public final Entity entity; + private static boolean affectBlocks = false; // will be used later when I add in the full explosion logger + private static long lastGametime = 0; + private static long explosionCountInCurrentGT = 0; + private static long explosionCountInCurrentPos = 0; + public static Vec3d previousPosition = null; + public static long startTime = 0; + + public static boolean tickHasCompact = false; + + public ExplosionLogHelper(Entity entity, double x, double y, double z, float power, boolean createFire) { // blocks removed + this.entity = entity; + this.pos = new Vec3d(x, y, z); + } + + public void onExplosionDone(long gametime) { + if(lastGametime != gametime) { + explosionCountInCurrentGT = 1; + explosionCountInCurrentPos = 0; + previousPosition = pos; + lastGametime = gametime; + startTime = System.currentTimeMillis(); + LoggerRegistry.getLogger("explosions").log((option) -> { + return new ITextComponent[]{Messenger.m(null, "wb tick : ", "d " + gametime)}; + }); + } + + LoggerRegistry.getLogger("explosions").log((option) -> { + ITextComponent[] msg = null; + switch (option) { + case "brief": + msg = new ITextComponent[]{Messenger.m(null, + "d #" + explosionCountInCurrentGT, + "gb ->", + Messenger.dblt("l", pos.x, pos.y, pos.z), + (affectBlocks)?"m (affects blocks)":"m (doesn't affect blocks)" + )}; + explosionCountInCurrentGT++; + break; + + // temporarily removed "full" because its not really needed for my use case. may implement later - Sylkos + + case "compact": + tickHasCompact = true; + if(previousPosition != null && !pos.equals(previousPosition)) { + msg = new ITextComponent[]{Messenger.m(null, + "d #" + explosionCountInCurrentGT, + "gb ->", + "d " + explosionCountInCurrentPos + "x ", + Messenger.dblt("l", previousPosition.x, previousPosition.y, previousPosition.z), + (affectBlocks)?"m (affects blocks)":"m (doesn't affect blocks)", + "g (", "d " + (System.currentTimeMillis()-startTime), "g ms)" + )}; + explosionCountInCurrentGT += explosionCountInCurrentPos; + explosionCountInCurrentPos = 0; + previousPosition = pos; + startTime = System.currentTimeMillis(); + } + explosionCountInCurrentPos++; + break; + } + return msg; + }); + } + + public static void logLastExplosion() { + if(LoggerRegistry.__explosions) { + if (tickHasCompact) { + tickHasCompact = false; + LoggerRegistry.getLogger("explosions").log((option) -> { + ITextComponent[] msg = null; + if ("compact".equals(option)) { + if (previousPosition != null) { + msg = new ITextComponent[]{Messenger.m(null, + "d #" + (explosionCountInCurrentGT), + "gb ->", + "d " + explosionCountInCurrentPos + "x ", + Messenger.dblt("l", previousPosition.x, previousPosition.y, previousPosition.z), + (affectBlocks) ? "m (affects blocks)" : "m (doesn't affect blocks)", + "g (", "d " + (System.currentTimeMillis()-startTime), "g ms)" + )}; + } + startTime = 0; + } + return msg; + }); + } + } + } +} diff --git a/carpetmodSrc/carpet/utils/JavaVersionUtil.java b/carpetmodSrc/carpet/utils/JavaVersionUtil.java new file mode 100644 index 00000000..1a18e604 --- /dev/null +++ b/carpetmodSrc/carpet/utils/JavaVersionUtil.java @@ -0,0 +1,118 @@ +package carpet.utils; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public final class JavaVersionUtil { + public static final int JAVA_VERSION = getJavaVersion(); + + private JavaVersionUtil() {} + + private static int getJavaVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + // old format (Java 8 and below) + return version.charAt(2) - '0'; + } else { + // new format (Java 9 and above) + int dotIndex = version.indexOf('.'); + if (dotIndex == -1) { + return Integer.parseInt(version); + } else { + return Integer.parseInt(version.substring(0, dotIndex)); + } + } + } + + public static FieldAccessor objectFieldAccessor(Class ownerClass, String name, Class fieldType) { + Field field; + try { + field = ownerClass.getDeclaredField(name); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Could not find field", e); + } + if (field.getType() != fieldType) { + throw new RuntimeException("Field has wrong type, expected \"" + fieldType.getName() + "\", got \"" + field.getType().getName() + "\""); + } + if (fieldType.isPrimitive()) { + throw new RuntimeException("objectFieldAccessor does not work for primitive field types"); + } + + try { + field.setAccessible(true); + } catch (RuntimeException e) { // InaccessibleObjectException + if (JAVA_VERSION <= 8) { + throw e; + } + long fieldOffset = UnsafeFieldAccessor.unsafe.objectFieldOffset(field); + return new UnsafeFieldAccessor<>(ownerClass, fieldOffset); + } + + try { + return new MethodHandleFieldAccessor<>(MethodHandles.lookup().unreflectGetter(field)); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public interface FieldAccessor { + T get(Object instance); + } + + private static class MethodHandleFieldAccessor implements FieldAccessor { + private final MethodHandle getter; + + private MethodHandleFieldAccessor(MethodHandle getter) { + this.getter = getter; + } + + @SuppressWarnings("unchecked") + @Override + public T get(Object instance) { + try { + return (T) getter.invoke(instance); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + + private static class UnsafeFieldAccessor implements FieldAccessor { + private static final sun.misc.Unsafe unsafe = getUnsafe(); + + private final Class ownerClass; + private final long fieldOffset; + + private UnsafeFieldAccessor(Class ownerClass, long fieldOffset) { + this.ownerClass = ownerClass; + this.fieldOffset = fieldOffset; + } + + @SuppressWarnings("unchecked") + @Override + public T get(Object instance) { + return (T) unsafe.getObject(ownerClass.cast(instance), fieldOffset); + } + + private static sun.misc.Unsafe getUnsafe() { + try { + Field field = null; + for (Field f : sun.misc.Unsafe.class.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers()) && f.getType() == sun.misc.Unsafe.class) { + field = f; + break; + } + } + if (field == null) { + throw new RuntimeException("Unable to get Unsafe instance"); + } + field.setAccessible(true); + return (sun.misc.Unsafe) field.get(null); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Unable to get Unsafe instance", e); + } + } + } +} diff --git a/carpetmodSrc/carpet/worldedit/CarpetWorld.java b/carpetmodSrc/carpet/worldedit/CarpetWorld.java index afe82abe..2938aeaa 100644 --- a/carpetmodSrc/carpet/worldedit/CarpetWorld.java +++ b/carpetmodSrc/carpet/worldedit/CarpetWorld.java @@ -123,7 +123,7 @@ public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight } IBlockState newState = Block.getBlockById(block.getId()).getStateFromMeta(block.getData()); - boolean successful = chunk.setBlockState(new BlockPos(x & 15, y, z & 15), newState) != null; + boolean successful = chunk.setBlockState(new BlockPos(x, y, z), newState) != null; // Create the TileEntity if (successful) { @@ -432,4 +432,4 @@ private WorldReferenceLostException(String message) { } } -} \ No newline at end of file +} diff --git a/carpetmodSrc/narcolepticfrog/rsmm/server/RSMMServer.java b/carpetmodSrc/narcolepticfrog/rsmm/server/RSMMServer.java index e015ef21..b463ee7f 100644 --- a/carpetmodSrc/narcolepticfrog/rsmm/server/RSMMServer.java +++ b/carpetmodSrc/narcolepticfrog/rsmm/server/RSMMServer.java @@ -218,7 +218,7 @@ public void onPlayerDisconnect(EntityPlayerMP player) { @Override public void onCustomPayload(EntityPlayerMP sender, String channel, PacketBuffer data) { - if (CarpetSettings.redstoneMultimeter && "RSMM".equals(channel)) { + if (CarpetSettings.redstoneMultimeterLegacy && "RSMM".equals(channel)) { RSMMSPacket packet = RSMMSPacket.fromBuffer(data); if (packet == null) return; packet.process(getOrCreateMeterGroup(sender)); diff --git a/carpetmodSrc/redstone/multimeter/RedstoneMultimeter.java b/carpetmodSrc/redstone/multimeter/RedstoneMultimeter.java new file mode 100644 index 00000000..2af088dc --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/RedstoneMultimeter.java @@ -0,0 +1,14 @@ +package redstone.multimeter; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class RedstoneMultimeter { + + public static final String MOD_NAME = "Redstone Multimeter"; + public static final String MOD_VERSION = "1.14.0"; + public static final String NAMESPACE = "redstone_multimeter"; + public static final String CONFIG_PATH = "config/" + NAMESPACE; + public static final Logger LOGGER = LogManager.getLogger(MOD_NAME); + +} diff --git a/carpetmodSrc/redstone/multimeter/block/Meterable.java b/carpetmodSrc/redstone/multimeter/block/Meterable.java new file mode 100644 index 00000000..18135d7c --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/block/Meterable.java @@ -0,0 +1,18 @@ +package redstone.multimeter.block; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.interfaces.IBlock; + +public interface Meterable extends IBlock { + + @Override + default boolean rsmm$isMeterable() { + return true; + } + + public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state); + +} diff --git a/carpetmodSrc/redstone/multimeter/block/MeterableBlock.java b/carpetmodSrc/redstone/multimeter/block/MeterableBlock.java new file mode 100644 index 00000000..ffb91cb7 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/block/MeterableBlock.java @@ -0,0 +1,24 @@ +package redstone.multimeter.block; + +import carpet.CarpetSettings; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.helper.WorldHelper; + +public interface MeterableBlock extends Meterable { + + default void rsmm$logPowered(World world, BlockPos pos, boolean powered) { + if (CarpetSettings.redstoneMultimeter && !world.isRemote) { + WorldHelper.getMultimeter().logPowered(world, pos, powered); + } + } + + default void rsmm$logPowered(World world, BlockPos pos, IBlockState state) { + if (CarpetSettings.redstoneMultimeter && !world.isRemote) { + WorldHelper.getMultimeter().logPowered(world, pos, state); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/block/PowerSource.java b/carpetmodSrc/redstone/multimeter/block/PowerSource.java new file mode 100644 index 00000000..888a1176 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/block/PowerSource.java @@ -0,0 +1,24 @@ +package redstone.multimeter.block; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import redstone.multimeter.interfaces.IBlock; + +public interface PowerSource extends IBlock { + + public static final int MIN_POWER = 0; + public static final int MAX_POWER = 15; + + @Override + default boolean rsmm$isPowerSource() { + return true; + } + + default boolean rsmm$logPowerChangeOnStateChange() { + return true; + } + + public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state); + +} diff --git a/carpetmodSrc/redstone/multimeter/command/MeterGroupCommand.java b/carpetmodSrc/redstone/multimeter/command/MeterGroupCommand.java new file mode 100644 index 00000000..5b7ad410 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/command/MeterGroupCommand.java @@ -0,0 +1,466 @@ +package redstone.multimeter.command; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.function.Function; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.CommandNotFoundException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentString; + +import redstone.multimeter.RedstoneMultimeter; +import redstone.multimeter.common.meter.MeterGroup; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.MultimeterServer; +import redstone.multimeter.server.meter.ServerMeterGroup; + +public class MeterGroupCommand extends CommandBase { + + private static final String COMMAND_NAME = "metergroup"; + + private static final String USAGE_LIST = singleUsage("list"); + + private static final String USAGE_SUBSCRIBE_DEFAULT = singleUsage("subscribe"); + private static final String USAGE_SUBSCRIBE_NAME = singleUsage("subscribe "); + private static final String USAGE_SUBSCRIBE = buildUsage(USAGE_SUBSCRIBE_DEFAULT, USAGE_SUBSCRIBE_NAME); + + private static final String USAGE_UNSUBSCRIBE = singleUsage("unsubscribe"); + + private static final String USAGE_PRIVATE_QUERY = singleUsage("private"); + private static final String USAGE_PRIVATE_SET = singleUsage("private "); + private static final String USAGE_PRIVATE = buildUsage(USAGE_PRIVATE_QUERY, USAGE_PRIVATE_SET); + + private static final String USAGE_MEMBERS_LIST = singleUsage("members list"); + private static final String USAGE_MEMBERS_ADD = singleUsage("members add "); + private static final String USAGE_MEMBERS_REMOVE = singleUsage("members remove "); + private static final String USAGE_MEMBERS_CLEAR = singleUsage("members clear"); + private static final String USAGE_MEMBERS = buildUsage(USAGE_MEMBERS_LIST, USAGE_MEMBERS_ADD, USAGE_MEMBERS_REMOVE, USAGE_MEMBERS_CLEAR); + + private static final String USAGE_CLEAR = singleUsage("clear"); + + private static final String TOTAL_USAGE_MEMBER = buildUsage(USAGE_LIST, USAGE_SUBSCRIBE, USAGE_UNSUBSCRIBE, USAGE_CLEAR); + private static final String TOTAL_USAGE_OWNER = buildUsage(USAGE_LIST, USAGE_SUBSCRIBE, USAGE_UNSUBSCRIBE, USAGE_PRIVATE, USAGE_MEMBERS, USAGE_CLEAR); + + private static String singleUsage(String usage) { + return String.format("/%s %s", COMMAND_NAME, usage); + } + + private static String buildUsage(String... usages) { + return String.join(" OR ", usages); + } + + private final MultimeterServer server; + private final Multimeter multimeter; + + public MeterGroupCommand(MultimeterServer server) { + this.server = server; + this.multimeter = this.server.getMultimeter(); + } + + @Override + public String getName() { + return COMMAND_NAME; + } + + @Override + public String getUsage(ICommandSender source) { + return isOwnerOfSubscription(source) ? TOTAL_USAGE_OWNER : TOTAL_USAGE_MEMBER; + } + + @Override + public List getTabCompletions(MinecraftServer server, ICommandSender source, String[] args, BlockPos pos) { + boolean isOwner = isOwnerOfSubscription(source); + + switch (args.length) { + case 1: + if (isOwner) { + return getListOfStringsMatchingLastWord(args, "clear", "subscribe", "unsubscribe", "private", "members", "list"); + } else { + return getListOfStringsMatchingLastWord(args, "clear", "subscribe", "unsubscribe", "list"); + } + case 2: + switch (args[0]) { + case "subscribe": + return getListOfStringsMatchingLastWord(args, listMeterGroups(source)); + case "private": + if (isOwner) { + return getListOfStringsMatchingLastWord(args, "true", "false"); + } + + break; + case "members": + if (isOwner) { + return getListOfStringsMatchingLastWord(args, "clear", "add", "remove", "list"); + } + + break; + } + + break; + case 3: + if (isOwner && args[0].equals("members")) { + switch (args[1]) { + case "add": + return getListOfStringsMatchingLastWord(args, server.getOnlinePlayerNames()); + case "remove": + return getListOfStringsMatchingLastWord(args, listMembers(source).keySet()); + } + } + + break; + } + + return Collections.emptyList(); + } + + @Override + public void execute(MinecraftServer server, ICommandSender source, String[] args) throws CommandException { + if (!isMultimeterClient(source)) { + throw new CommandNotFoundException(); + } + + if (args.length > 0) { + switch (args[0]) { + case "list": + if (args.length == 1) { + list(source); + return; + } + + throw new WrongUsageException(USAGE_LIST); + case "subscribe": + if (args.length == 1) { + subscribe(source, null); + return; + } + + String name = ""; + + for (int index = 1; index < args.length; index++) { + name += args[index] + " "; + } + + subscribe(source, name); + return; + case "unsubscribe": + if (args.length == 1) { + unsubscribe(source); + return; + } + + throw new WrongUsageException(USAGE_UNSUBSCRIBE); + case "private": + if (!isOwnerOfSubscription(source)) { + break; + } + + switch (args.length) { + case 1: + queryPrivate(source); + return; + case 2: + switch (args[1]) { + case "true": + setPrivate(source, true); + return; + case "false": + setPrivate(source, false); + return; + } + + throw new WrongUsageException(USAGE_PRIVATE_SET); + } + + throw new WrongUsageException(USAGE_PRIVATE); + case "members": + if (!isOwnerOfSubscription(source)) { + break; + } + + if (args.length > 1) { + switch (args[1]) { + case "list": + if (args.length == 2) { + membersList(source); + return; + } + + throw new WrongUsageException(USAGE_MEMBERS_LIST); + case "add": + if (args.length == 3) { + membersAdd(source, getPlayers(server, source, args[2])); + return; + } + + throw new WrongUsageException(USAGE_MEMBERS_ADD); + case "remove": + if (args.length == 3) { + membersRemovePlayer(source, args[2]); + return; + } + + throw new WrongUsageException(USAGE_MEMBERS_REMOVE); + case "clear": + if (args.length == 2) { + membersClear(source); + return; + } + + throw new WrongUsageException(USAGE_MEMBERS_CLEAR); + } + } + + throw new WrongUsageException(USAGE_MEMBERS); + case "clear": + if (args.length == 1) { + clear(source); + return; + } + + throw new WrongUsageException(USAGE_CLEAR); + } + } + + throw new WrongUsageException(getUsage(source)); + } + + private boolean isMultimeterClient(ICommandSender source) { + return run(source, player -> server.isMultimeterClient(player)); + } + + private boolean isOwnerOfSubscription(ICommandSender source) { + return run(source, player -> multimeter.isOwnerOfSubscription(player)); + } + + private Collection listMeterGroups(ICommandSender source) { + List names = new ArrayList<>(); + + command(source, player -> { + for (ServerMeterGroup meterGroup : multimeter.getMeterGroups()) { + if (!meterGroup.isPrivate() || meterGroup.hasMember(player) || meterGroup.isOwnedBy(player)) { + names.add(meterGroup.getName()); + } + } + }); + + return names; + } + + private Map listMembers(ICommandSender source) { + Map names = new HashMap<>(); + + command(source, player -> { + ServerMeterGroup meterGroup = multimeter.getSubscription(player); + + if (meterGroup != null && meterGroup.isOwnedBy(player)) { + for (UUID playerUUID : meterGroup.getMembers()) { + String playerName = multimeter.getServer().getPlayerList().getName(playerUUID); + + if (playerName != null) { + names.put(playerName, playerUUID); + } + } + } + }); + + return names; + } + + private void list(ICommandSender source) { + Collection names = listMeterGroups(source); + + if (names.isEmpty()) { + source.sendMessage(new TextComponentString("There are no meter groups yet!")); + } else { + String message = "Meter groups:\n " + String.join("\n ", names); + source.sendMessage(new TextComponentString(message)); + } + } + + private void subscribe(ICommandSender source, String name) { + command(source, player -> { + if (name == null) { + multimeter.subscribeToDefaultMeterGroup(player); + source.sendMessage(new TextComponentString("Subscribed to default meter group")); + } else if (multimeter.hasMeterGroup(name)) { + ServerMeterGroup meterGroup = multimeter.getMeterGroup(name); + + if (!meterGroup.isPrivate() || meterGroup.hasMember(player) || meterGroup.isOwnedBy(player)) { + multimeter.subscribeToMeterGroup(meterGroup, player); + source.sendMessage(new TextComponentString(String.format("Subscribed to meter group \'%s\'", name))); + } else { + source.sendMessage(new TextComponentString("That meter group is private!")); + } + } else { + if (MeterGroup.isValidName(name)) { + multimeter.createMeterGroup(player, name); + source.sendMessage(new TextComponentString(String.format("Created meter group \'%s\'", name))); + } else { + source.sendMessage(new TextComponentString(String.format("\'%s\' is not a valid meter group name!", name))); + } + } + }); + } + + private void unsubscribe(ICommandSender source) { + command(source, (meterGroup, player) -> { + multimeter.unsubscribeFromMeterGroup(meterGroup, player); + source.sendMessage(new TextComponentString(String.format("Unsubscribed from meter group \'%s\'", meterGroup.getName()))); + }); + } + + private void queryPrivate(ICommandSender source) { + command(source, (meterGroup, player) -> { + String status = meterGroup.isPrivate() ? "private" : "public"; + source.sendMessage(new TextComponentString(String.format("Meter group \'%s\' is %s", meterGroup.getName(), status))); + }); + } + + private void setPrivate(ICommandSender source, boolean isPrivate) { + command(source, (meterGroup, player) -> { + if (meterGroup.isOwnedBy(player)) { + meterGroup.setPrivate(isPrivate); + source.sendMessage(new TextComponentString(String.format("Meter group \'%s\' is now %s", meterGroup.getName(), (isPrivate ? "private" : "public")))); + } else { + source.sendMessage(new TextComponentString("Only the owner of a meter group can change its privacy!")); + } + }); + } + + private void membersList(ICommandSender source) { + Map members = listMembers(source); + + commandMembers(source, (meterGroup, owner) -> { + if (members.isEmpty()) { + source.sendMessage(new TextComponentString(String.format("Meter group \'%s\' has no members yet!", meterGroup.getName()))); + } else { + String message = String.format("Members of meter group \'%s\':\n ", meterGroup.getName()) + String.join("\n ", members.keySet()); + source.sendMessage(new TextComponentString(message)); + } + }); + } + + private void membersAdd(ICommandSender source, Collection players) { + commandMembers(source, (meterGroup, owner) -> { + for (EntityPlayerMP player : players) { + if (player == owner) { + source.sendMessage(new TextComponentString("You cannot add yourself as a member!")); + } else if (meterGroup.hasMember(player)) { + source.sendMessage(new TextComponentString(String.format("Player \'%s\' is already a member of meter group \'%s\'!", player.getName(), meterGroup.getName()))); + } else if (!multimeter.getServer().isMultimeterClient(player)) { + source.sendMessage(new TextComponentString(String.format("You cannot add player \'%s\' as a member; they do not have %s installed!", player.getName(), RedstoneMultimeter.MOD_NAME))); + } else { + multimeter.addMemberToMeterGroup(meterGroup, player.getUniqueID()); + source.sendMessage(new TextComponentString(String.format("Player \'%s\' is now a member of meter group \'%s\'", player.getName(), meterGroup.getName()))); + } + } + }); + } + + private void membersRemovePlayer(ICommandSender source, String playerName) { + commandMembers(source, (meterGroup, owner) -> { + Entry member = findMember(listMembers(source), playerName); + + if (member == null) { + EntityPlayerMP player = multimeter.getServer().getPlayerList().get(playerName); + + if (player == owner) { + source.sendMessage(new TextComponentString("You cannot remove yourself as a member!")); + } else { + source.sendMessage(new TextComponentString(String.format("Meter group \'%s\' has no member with the name \'%s\'!", meterGroup.getName(), playerName))); + } + } else { + multimeter.removeMemberFromMeterGroup(meterGroup, member.getValue()); + source.sendMessage(new TextComponentString(String.format("Player \'%s\' is no longer a member of meter group \'%s\'", member.getKey(), meterGroup.getName()))); + } + }); + } + + private Entry findMember(Map members, String playerName) { + String key = playerName.toLowerCase(); + + for (Entry member : members.entrySet()) { + if (member.getKey().toLowerCase().equals(key)) { + return member; + } + } + + return null; + } + + private void membersClear(ICommandSender source) { + commandMembers(source, (meterGroup, owner) -> { + multimeter.clearMembersOfMeterGroup(meterGroup); + source.sendMessage(new TextComponentString(String.format("Removed all members from meter group \'%s\'", meterGroup.getName()))); + }); + } + + private void commandMembers(ICommandSender source, MeterGroupCommandExecutor command) { + command(source, (meterGroup, player) -> { + if (meterGroup.isOwnedBy(player)) { + command.run(meterGroup, player); + + if (!meterGroup.isPrivate()) { + source.sendMessage(new TextComponentString("NOTE: this meter group is public; adding/removing members will not have any effect until you make it private!")); + } + } + }); + } + + private void clear(ICommandSender source) { + command(source, (meterGroup, player) -> { + multimeter.clearMeterGroup(meterGroup); + source.sendMessage(new TextComponentString(String.format("Removed all meters in meter group \'%s\'", meterGroup.getName()))); + }); + } + + private void command(ICommandSender source, MeterGroupCommandExecutor command) { + command(source, player -> { + ServerMeterGroup meterGroup = multimeter.getSubscription(player); + + if (meterGroup == null) { + source.sendMessage(new TextComponentString("Please subscribe to a meter group first!")); + } else { + command.run(meterGroup, player); + } + }); + } + + private void command(ICommandSender source, MultimeterCommandExecutor command) { + run(source, p -> { command.run(p); return true; }); + } + + private boolean run(ICommandSender source, Function command) { + try { + return command.apply(getCommandSenderAsPlayer(source)); + } catch (CommandException e) { + return false; + } + } + + @FunctionalInterface + private static interface MultimeterCommandExecutor { + + public void run(EntityPlayerMP player); + + } + + @FunctionalInterface + private static interface MeterGroupCommandExecutor { + + public void run(ServerMeterGroup meterGroup, EntityPlayerMP player); + + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/DimPos.java b/carpetmodSrc/redstone/multimeter/common/DimPos.java new file mode 100644 index 00000000..bec47255 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/DimPos.java @@ -0,0 +1,114 @@ +package redstone.multimeter.common; + +import com.google.common.base.Objects; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumFacing.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.util.AxisUtils; + +public class DimPos { + + private final String dimension; + private final BlockPos pos; + + public DimPos(String dimension, BlockPos pos) { + this.dimension = dimension; + this.pos = pos.toImmutable(); + } + + public DimPos(String dimension, int x, int y, int z) { + this(dimension, new BlockPos(x, y, z)); + } + + public DimPos(World world, BlockPos pos) { + this(world.provider.getDimensionType().getName(), pos); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DimPos) { + DimPos other = (DimPos)obj; + return other.dimension.equals(dimension) && other.pos.equals(pos); + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(dimension, pos); + } + + @Override + public String toString() { + return String.format("%s[%d, %d, %d]", dimension.toString(), pos.getX(), pos.getY(), pos.getZ()); + } + + public String getDimension() { + return dimension; + } + + public boolean is(World world) { + return world.provider.getDimensionType().getName().equals(dimension); + } + + public DimPos offset(String dimension) { + return new DimPos(dimension, pos); + } + + public BlockPos getBlockPos() { + return pos; + } + + public boolean is(BlockPos pos) { + return pos.equals(this.pos); + } + + public DimPos offset(EnumFacing dir) { + return offset(dir, 1); + } + + public DimPos offset(EnumFacing dir, int distance) { + return new DimPos(dimension, pos.offset(dir, distance)); + } + + public DimPos offset(Axis axis) { + return offset(axis, 1); + } + + public DimPos offset(Axis axis, int distance) { + int dx = AxisUtils.choose(axis, distance, 0, 0); + int dy = AxisUtils.choose(axis, 0, distance, 0); + int dz = AxisUtils.choose(axis, 0, 0, distance); + + return new DimPos(dimension, pos.add(dx, dy, dz)); + } + + public DimPos offset(int dx, int dy, int dz) { + return new DimPos(dimension, pos.add(dx, dy, dz)); + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setString("dim", dimension); + nbt.setInteger("x", pos.getX()); + nbt.setInteger("y", pos.getY()); + nbt.setInteger("z", pos.getZ()); + + return nbt; + } + + public static DimPos fromNbt(NBTTagCompound nbt) { + String dimension = nbt.getString("dim"); + int x = nbt.getInteger("x"); + int y = nbt.getInteger("y"); + int z = nbt.getInteger("z"); + + return new DimPos(dimension, x, y, z); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/PruneType.java b/carpetmodSrc/redstone/multimeter/common/PruneType.java new file mode 100644 index 00000000..b2a048bd --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/PruneType.java @@ -0,0 +1,19 @@ +package redstone.multimeter.common; + +public enum PruneType { + + NONE (0), + BRANCH (1), + SIBLING(2), + TREE (3); + + private final int level; + + private PruneType(int level) { + this.level = level; + } + + public boolean is(PruneType type) { + return level >= type.level; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/TickPhase.java b/carpetmodSrc/redstone/multimeter/common/TickPhase.java new file mode 100644 index 00000000..3414d08b --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/TickPhase.java @@ -0,0 +1,117 @@ +package redstone.multimeter.common; + +import java.util.Arrays; + +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagByteArray; + +import redstone.multimeter.util.NbtUtils; + +public class TickPhase { + + public static final TickPhase UNKNOWN = new TickPhase(TickTask.UNKNOWN); + + private final TickTask[] tasks; + + public TickPhase(TickTask... tasks) { + this.tasks = tasks; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof TickPhase)) { + return false; + } + + return Arrays.equals(tasks, ((TickPhase)obj).tasks); + } + + @Override + public String toString() { + String string = tasks[0].getName(); + + for (int index = 1; index < tasks.length; index++) { + string += " > " + tasks[index].getName(); + } + + return string; + } + + public TickPhase startTask(TickTask task) { + if (this == UNKNOWN || tasks.length == 0) { + return new TickPhase(task); + } + + TickTask[] array = new TickTask[tasks.length + 1]; + + for (int index = 0; index < tasks.length; index++) { + array[index] = tasks[index]; + } + array[tasks.length] = task; + + return new TickPhase(array); + } + + public TickPhase endTask() { + if (this == UNKNOWN || tasks.length == 1) { + return UNKNOWN; + } + + TickTask[] array = new TickTask[tasks.length - 1]; + + for (int index = 0; index < array.length; index++) { + array[index] = tasks[index]; + } + + return new TickPhase(array); + } + + public TickPhase swapTask(TickTask task) { + if (this == UNKNOWN || tasks.length == 1) { + return new TickPhase(new TickTask[] { task }); + } + + TickTask[] array = new TickTask[tasks.length]; + + for (int index = 0; index < tasks.length; index++) { + array[index] = tasks[index]; + } + array[array.length - 1] = task; + + return new TickPhase(array); + } + + public TickTask peekTask() { + return tasks.length == 0 ? TickTask.UNKNOWN : tasks[tasks.length - 1]; + } + + public NBTBase toNbt() { + if (this == UNKNOWN) { + return NbtUtils.NULL; + } + + byte[] array = new byte[tasks.length]; + + for (int index = 0; index < array.length; index++) { + array[index] = (byte)tasks[index].getIndex(); + } + + return new NBTTagByteArray(array); + } + + public static TickPhase fromNbt(NBTBase nbt) { + if (nbt.getId() != NbtUtils.TYPE_BYTE_ARRAY) { + return UNKNOWN; + } + + NBTTagByteArray nbtArray = (NBTTagByteArray)nbt; + byte[] array = nbtArray.getByteArray(); + TickTask[] tasks = new TickTask[array.length]; + + for (int index = 0; index < tasks.length; index++) { + tasks[index] = TickTask.byIndex(array[index]); + } + + return new TickPhase(tasks); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/TickPhaseTree.java b/carpetmodSrc/redstone/multimeter/common/TickPhaseTree.java new file mode 100644 index 00000000..8267acf2 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/TickPhaseTree.java @@ -0,0 +1,255 @@ +package redstone.multimeter.common; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.Stack; + +import net.minecraft.nbt.NBTTagByteArray; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; + +import redstone.multimeter.RedstoneMultimeter; +import redstone.multimeter.util.NbtUtils; + +public class TickPhaseTree { + + public final Node root; + + private Node current; + private boolean building; + private boolean complete; + + public TickPhaseTree() { + this.root = new Node(null, TickTask.UNKNOWN); + + this.current = root; + this.building = false; + this.complete = false; + } + + public boolean isComplete() { + return complete; + } + + public boolean isBuilding() { + return building; + } + + public void reset() { + if (building) { + RedstoneMultimeter.LOGGER.warn("Cannot reset tick phase tree: currently building!"); + } else { + root.children.clear(); + current = root; + building = false; + complete = false; + } + } + + public void start() { + if (building) { + RedstoneMultimeter.LOGGER.warn("Cannot start building tick phase tree: already building!"); + } else { + root.children.clear(); + current = root; + building = true; + complete = false; + } + } + + public void end() { + if (building) { + building = false; + complete = true; + + prune(); + } else { + RedstoneMultimeter.LOGGER.warn("Cannot complete tick phase tree: not building!"); + } + } + + private void prune() { + new Pruner().run(); + } + + public void startTask(TickTask task, String... args) { + if (building) { + current = new Node(current, task, args); + current.parent.children.add(current); + } + } + + public void endTask() { + if (building) { + current = current.parent; + + if (current == null) { + current = root; // we should never get here + } + } + } + + public void swapTask(TickTask task, String... args) { + if (building) { + endTask(); + startTask(task, args); + } + } + + public NBTTagCompound toNbt() { + NBTTagList tasks = new NBTTagList(); + NBTTagList args = new NBTTagList(); + + addNode(tasks, args, root, 0); + + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setTag("tasks", tasks); + nbt.setTag("args", args); + + return nbt; + } + + private void addNode(NBTTagList tasks, NBTTagList args, Node node, int depth) { + if (depth > 0) { // depth 0 is root + byte[] array = new byte[3]; + array[0] = (byte)depth; + array[1] = (byte)node.task.getIndex(); + array[2] = (byte)node.args.length; + NBTTagByteArray taskNbt = new NBTTagByteArray(array); + + tasks.appendTag(taskNbt); + + for (int index = 0; index < node.args.length; index++) { + String arg = node.args[index]; + NBTTagString argNbt = new NBTTagString(arg); + + args.appendTag(argNbt); + } + } + + depth++; + + for (int index = 0; index < node.children.size(); index++) { + addNode(tasks, args, node.children.get(index), depth); + } + } + + public void fromNbt(NBTTagCompound nbt) { + NBTTagList tasks = nbt.getTagList("tasks", NbtUtils.TYPE_BYTE_ARRAY); + NBTTagList args = nbt.getTagList("args", NbtUtils.TYPE_STRING); + + if (!tasks.isEmpty()) { + start(); + addNode(tasks, args, 0, 0, 0); + end(); + } + } + + private void addNode(NBTTagList tasks, NBTTagList args, int taskIndex, int argIndex, int lastDepth) { + NBTTagByteArray taskNbt = (NBTTagByteArray)tasks.get(taskIndex); + byte[] array = taskNbt.getByteArray(); + int depth = array[0]; + TickTask task = TickTask.byIndex(array[1]); + int argsLength = array[2]; + + String[] taskArgs; + + if (argsLength > 0) { + taskArgs = new String[argsLength]; + + for (int i = 0; i < argsLength && argIndex < args.tagCount();) { + taskArgs[i++] = args.getStringTagAt(argIndex++); + } + } else { + taskArgs = new String[0]; + } + + int endedTasks = lastDepth - depth; + + while (endedTasks-- > 0) { + endTask(); + } + if (depth > lastDepth) { + startTask(task, taskArgs); + } else { + swapTask(task, taskArgs); + } + + if (++taskIndex < tasks.tagCount()) { + addNode(tasks, args, taskIndex, argIndex, depth); + } + } + + public class Node { + + public final Node parent; + public final List children; + public final TickTask task; + public final String[] args; + + public Node(Node parent, TickTask task, String... args) { + this.parent = parent; + this.children = new ArrayList<>(); + this.task = task; + this.args = args; + } + } + + private class Pruner { + + private final Set tasks = EnumSet.noneOf(TickTask.class); + private final Stack> layers = new Stack<>(); + private final Stack phase = new Stack<>(); + + private void run() { + tasks.clear(); + layers.clear(); + phase.clear(); + + layers.push(EnumSet.noneOf(TickTask.class)); + + prune(root); + } + + private boolean prune(Node node) { + TickTask task = node.task; + PruneType type = task.getPruneType(); + + if (type.is(PruneType.TREE) && tasks.contains(task)) { + return true; + } + + Set layer = layers.peek(); + + if (type.is(PruneType.SIBLING) && layer.contains(task)) { + return true; + } + if (type.is(PruneType.BRANCH) && phase.contains(task)) { + return true; + } + + tasks.add(task); + layer.add(task); + + phase.push(task); + layers.push(EnumSet.noneOf(TickTask.class)); + + for (Iterator it = node.children.iterator(); it.hasNext(); ) { + Node child = it.next(); + + if (prune(child)) { + it.remove(); + } + } + + phase.pop(); + layers.pop(); + + return false; + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/TickTask.java b/carpetmodSrc/redstone/multimeter/common/TickTask.java new file mode 100644 index 00000000..efdb11ab --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/TickTask.java @@ -0,0 +1,86 @@ +package redstone.multimeter.common; + +public enum TickTask { + + UNKNOWN ( 0, "unknown" , PruneType.NONE), + TICK ( 1, "tick" , PruneType.TREE), + COMMAND_FUNCTIONS ( 2, "command functions" , PruneType.TREE), + LEVELS ( 3, "levels" , PruneType.TREE), + TICK_LEVEL ( 4, "tick level" , PruneType.BRANCH), + WORLD_BORDER ( 5, "world border" , PruneType.BRANCH), + WEATHER ( 6, "weather" , PruneType.BRANCH), + WAKE_SLEEPING_PLAYERS( 7, "wake sleeping players", PruneType.BRANCH), + CHUNK_SOURCE ( 8, "chunk source" , PruneType.BRANCH), + PURGE_UNLOADED_CHUNKS( 9, "purge unloaded chunks", PruneType.BRANCH), + TICK_CHUNKS (10, "tick chunks" , PruneType.BRANCH), + MOB_SPAWNING (11, "mob spawning" , PruneType.SIBLING), + TICK_CHUNK (12, "tick chunk" , PruneType.SIBLING), + THUNDER (13, "thunder" , PruneType.SIBLING), + PRECIPITATION (14, "precipitation" , PruneType.SIBLING), + RANDOM_TICKS (15, "random ticks" , PruneType.SIBLING), + CUSTOM_MOB_SPAWNING (16, "custom mob spawning" , PruneType.BRANCH), + BROADCAST_CHUNKS (17, "broadcast chunks" , PruneType.SIBLING), + UNLOAD_CHUNKS (18, "unload chunks" , PruneType.BRANCH), + CHUNK_MAP (19, "chunk map" , PruneType.BRANCH), + TICK_TIME (20, "tick time" , PruneType.BRANCH), + SCHEDULED_TICKS (21, "scheduled ticks" , PruneType.BRANCH), + BLOCK_TICKS (22, "block ticks" , PruneType.BRANCH), + FLUID_TICKS (23, "fluid ticks" , PruneType.BRANCH), + VILLAGES (24, "villages" , PruneType.BRANCH), + RAIDS (25, "raids" , PruneType.BRANCH), + PORTALS (26, "portals" , PruneType.BRANCH), + BLOCK_EVENTS (27, "block events" , PruneType.BRANCH), + ENTITIES (28, "entities" , PruneType.BRANCH), + REGULAR_ENTITIES (29, "regular entities" , PruneType.BRANCH), + GLOBAL_ENTITIES (30, "global entities" , PruneType.BRANCH), + PLAYERS (31, "players" , PruneType.BRANCH), + DRAGON_FIGHT (32, "dragon fight" , PruneType.BRANCH), + BLOCK_ENTITIES (33, "block entities" , PruneType.BRANCH), + ENTITY_MANAGEMENT (34, "entity management" , PruneType.BRANCH), + CONNECTIONS (35, "connections" , PruneType.TREE), + PLAYER_PING (36, "player ping" , PruneType.TREE), + SERVER_GUI (37, "server gui" , PruneType.TREE), + AUTOSAVE (38, "autosave" , PruneType.TREE), + PACKETS (39, "packets" , PruneType.TREE); + + public static final TickTask[] ALL; + + static { + + ALL = new TickTask[values().length]; + + for (TickTask task : values()) { + ALL[task.index] = task; + } + } + + private final int index; + private final String name; + private final PruneType pruneType; + + private TickTask(int index, String name, PruneType pruneType) { + this.index = index; + this.name = name; + this.pruneType = pruneType; + } + + public int getIndex() { + return index; + } + + public static TickTask byIndex(int index) { + if (index > 0 && index < ALL.length) { + return ALL[index]; + } + + return UNKNOWN; + } + + public String getName() { + return name; + } + + public PruneType getPruneType() { + return pruneType; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/ColorPicker.java b/carpetmodSrc/redstone/multimeter/common/meter/ColorPicker.java new file mode 100644 index 00000000..883a529f --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/ColorPicker.java @@ -0,0 +1,36 @@ +package redstone.multimeter.common.meter; + +import java.awt.Color; + +import redstone.multimeter.util.ColorUtils; + +public enum ColorPicker { + + RANDOM { + + private int index; + + @Override + public int next() { + float hue = ((index * 11) % 8 + (index / 8) / 2.0F) / 8.0F; + index = (index + 1) % 16; + + return ColorUtils.setAlpha(Color.HSBtoRGB(hue, 0.7F, 1.0F), 0xFF); + } + }, + RAINBOW { + + private int index; + + @Override + public int next() { + float hue = index / 32.0F; + index = (index + 1) % 32; + + return ColorUtils.setAlpha(Color.HSBtoRGB(hue, 0.7F, 1.0F), 0xFF); + } + }; + + public abstract int next(); + +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/Meter.java b/carpetmodSrc/redstone/multimeter/common/meter/Meter.java new file mode 100644 index 00000000..bad78607 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/Meter.java @@ -0,0 +1,151 @@ +package redstone.multimeter.common.meter; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.MeterProperties.MutableMeterProperties; +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.common.meter.log.MeterLogs; + +public class Meter { + + private static final AtomicLong ID_COUNTER = new AtomicLong(0); + + private final long id; + private final MutableMeterProperties properties; + private final MeterLogs logs; + + /** true if the block at this position is receiving power */ + private boolean powered; + /** true if the block at this position is emitting power or active in another way */ + private boolean active; + + /** this property is used on the client to hide a meter in the HUD */ + private boolean hidden; + + public Meter(long id, MutableMeterProperties properties) { + this.id = id; + this.properties = properties.mutable(); + this.logs = new MeterLogs(); + } + + public Meter(MutableMeterProperties properties) { + this(ID_COUNTER.getAndIncrement(), properties); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Meter) { + Meter meter = (Meter)obj; + return meter.id == id; + } + + return false; + } + + public long getId() { + return id; + } + + public MeterProperties getProperties() { + return properties.immutable(); + } + + public MeterLogs getLogs() { + return logs; + } + + public void applyUpdate(Consumer update) { + update.accept(properties); + } + + public DimPos getPos() { + return properties.getPos(); + } + + public boolean isIn(World world) { + return properties.getPos().is(world); + } + + public String getName() { + return properties.getName(); + } + + public int getColor() { + return properties.getColor(); + } + + public boolean isMovable() { + return properties.getMovable(); + } + + public int getEventTypes() { + return properties.getEventTypes(); + } + + public boolean isMetering(EventType type) { + return properties.hasEventType(type); + } + + public boolean isPowered() { + return powered; + } + + public boolean isActive() { + return active; + } + + public boolean setPowered(boolean powered) { + boolean wasPowered = this.powered; + this.powered = powered; + + return wasPowered != powered; + } + + public boolean setActive(boolean active) { + boolean wasActive = this.active; + this.active = active; + + return wasActive != active; + } + + public boolean isHidden() { + return hidden; + } + + public void toggleHidden() { + setHidden(!hidden); + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setLong("id", id); + nbt.setTag("properties", properties.toNbt()); + nbt.setBoolean("powered", powered); + nbt.setBoolean("active", active); + + return nbt; + } + + public static Meter fromNbt(NBTTagCompound nbt) { + long id = nbt.getLong("id"); + MeterProperties properties = MeterProperties.fromNbt(nbt.getCompoundTag("properties")); + boolean powered = nbt.getBoolean("powered"); + boolean active = nbt.getBoolean("active"); + + Meter meter = new Meter(id, properties.mutable()); + meter.setPowered(powered); + meter.setActive(active); + + return meter; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/MeterGroup.java b/carpetmodSrc/redstone/multimeter/common/meter/MeterGroup.java new file mode 100644 index 00000000..561d6ed8 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/MeterGroup.java @@ -0,0 +1,228 @@ +package redstone.multimeter.common.meter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.log.LogManager; +import redstone.multimeter.util.NbtUtils; + +public abstract class MeterGroup { + + private final String name; + private final List meters; + private final Map byId; + private final Map byPos; + + protected MeterGroup(String name) { + this.name = name; + this.meters = new ArrayList<>(); + this.byId = new HashMap<>(); + this.byPos = new HashMap<>(); + } + + public static boolean isValidName(String name) { + return !name.trim().isEmpty() && name.length() <= getMaxNameLength(); + } + + public static int getMaxNameLength() { + return 64; + } + + public String getName() { + return name; + } + + public void clear() { + meters.clear(); + byId.clear(); + byPos.clear(); + getLogManager().clearLogs(); + } + + public boolean hasMeters() { + return !meters.isEmpty(); + } + + public List getMeters() { + return Collections.unmodifiableList(meters); + } + + public boolean hasMeter(long id) { + return byId.containsKey(id); + } + + public boolean hasMeterAt(DimPos pos) { + return byPos.containsKey(pos); + } + + public Meter getMeter(long id) { + return fromIndex(byId.getOrDefault(id, -1)); + } + + public Meter getMeterAt(DimPos pos) { + return fromIndex(byPos.getOrDefault(pos, -1)); + } + + private Meter fromIndex(int index) { + return (index < 0 || index >= meters.size()) ? null : meters.get(index); + } + + protected boolean addMeter(Meter meter) { + // This check prevents meters from being added twice and + // multiple meters from being added at the same position. + if (byId.containsKey(meter.getId()) || byPos.containsKey(meter.getPos())) { + return false; + } + + byId.put(meter.getId(), meters.size()); + byPos.put(meter.getPos(), meters.size()); + meters.add(meter); + + meterAdded(meter); + + return true; + } + + protected boolean removeMeter(Meter meter) { + int index = byId.getOrDefault(meter.getId(), -1); + + if (index < 0 || index >= meters.size()) { + return false; + } + + meters.remove(index); + byId.remove(meter.getId(), index); + byPos.remove(meter.getPos(), index); + + for (; index < meters.size(); index++) { + Meter m = meters.get(index); + + byId.compute(m.getId(), (id, prevIndex) -> prevIndex - 1); + byPos.compute(m.getPos(), (pos, prevIndex) -> prevIndex - 1); + } + + meterRemoved(meter); + + return true; + } + + protected boolean updateMeter(Meter meter, MeterProperties newProperties) { + meter.applyUpdate(properties -> { + boolean changed = false; + + if (newProperties.getPos() != null) { + moveMeter(meter, newProperties.getPos()); + } + if (newProperties.getName() != null) { + changed |= properties.setName(newProperties.getName()); + } + if (newProperties.getColor() != null) { + changed |= properties.setColor(newProperties.getColor()); + } + if (newProperties.getMovable() != null) { + changed |= properties.setMovable(newProperties.getMovable()); + } + if (newProperties.getEventTypes() != null) { + changed |= properties.setEventTypes(newProperties.getEventTypes()); + } + + if (changed) { + meterUpdated(meter); + } + }); + + return true; + } + + protected void moveMeter(Meter meter, DimPos newPos) { + long id = meter.getId(); + DimPos pos = meter.getPos(); + + if (pos.equals(newPos)) { + return; + } + + int index = byId.getOrDefault(id, -1); + + if (index < 0 || index >= meters.size()) { + return; + } + + byPos.remove(pos, index); + byPos.put(newPos, index); + + meter.applyUpdate(properties -> { + if (properties.setPos(newPos)) { + meterUpdated(meter); + } + }); + } + + protected boolean setIndex(Meter meter, int index) { + int oldIndex = byId.getOrDefault(meter.getId(), -1); + + if (index < 0 || index >= meters.size() || oldIndex < 0) { + return false; + } + + meters.remove(oldIndex); + meters.add(index, meter); + + int start = Math.min(oldIndex, index); + int end = Math.max(oldIndex, index); + + for (index = start; index <= end; index++) { + meter = meters.get(index); + + byId.put(meter.getId(), index); + byPos.put(meter.getPos(), index); + + indexChanged(meter); + } + + return true; + } + + protected abstract void meterAdded(Meter meter); + + protected abstract void meterRemoved(Meter meter); + + protected abstract void meterUpdated(Meter meter); + + protected abstract void indexChanged(Meter meter); + + public abstract LogManager getLogManager(); + + public NBTTagCompound toNbt() { + NBTTagList list = new NBTTagList(); + + for (Meter meter : meters) { + list.appendTag(meter.toNbt()); + } + + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setTag("meters", list); + + return nbt; + } + + public void updateFromNbt(NBTTagCompound nbt) { + clear(); + + NBTTagList list = nbt.getTagList("meters", NbtUtils.TYPE_COMPOUND); + + for (int index = 0; index < list.tagCount(); index++) { + NBTTagCompound meterNbt = list.getCompoundTagAt(index); + Meter meter = Meter.fromNbt(meterNbt); + + addMeter(meter); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/MeterProperties.java b/carpetmodSrc/redstone/multimeter/common/meter/MeterProperties.java new file mode 100644 index 00000000..23538d32 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/MeterProperties.java @@ -0,0 +1,273 @@ +package redstone.multimeter.common.meter; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import net.minecraft.nbt.NBTTagCompound; +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.util.ColorUtils; + +public class MeterProperties { + + private DimPos pos; + private String name; + private Integer color; + private Boolean movable; + private Integer eventTypes; + + public MeterProperties() { + + } + + public MeterProperties(DimPos pos, String name, Integer color, Boolean movable, Integer eventTypes) { + this.pos = pos; + this.name = name; + this.color = color; + this.movable = movable; + this.eventTypes = eventTypes; + } + + @Override + public String toString() { + return String.format("MeterProperties[pos: %s, name: %s, color: %s, movable: %s, event types: %s]", pos, name, color, movable, eventTypes); + } + + public DimPos getPos() { + return pos; + } + + public String getName() { + return name; + } + + public Integer getColor() { + return color; + } + + public Boolean getMovable() { + return movable; + } + + public Integer getEventTypes() { + return eventTypes; + } + + public boolean hasEventType(EventType type) { + return eventTypes != null && (eventTypes & type.flag()) != 0; + } + + public MutableMeterProperties mutable() { + return new MutableMeterProperties().fill(this); + } + + public MeterProperties immutable() { + return this; + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + if (pos != null) { + nbt.setTag("pos", pos.toNbt()); + } + if (name != null) { + nbt.setString("name", name); + } + if (color != null) { + nbt.setInteger("color", color); + } + if (movable != null) { + nbt.setBoolean("movable", movable); + } + if (eventTypes != null) { + nbt.setInteger("event types", eventTypes); + } + + return nbt; + } + + public static MeterProperties fromNbt(NBTTagCompound nbt) { + MeterProperties properties = new MeterProperties(); + + if (nbt.hasKey("pos")) { + properties.pos = DimPos.fromNbt(nbt.getCompoundTag("pos")); + } + if (nbt.hasKey("name")) { + properties.name = nbt.getString("name"); + } + if (nbt.hasKey("color")) { + properties.color = nbt.getInteger("color"); + } + if (nbt.hasKey("movable")) { + properties.movable = nbt.getBoolean("movable"); + } + if (nbt.hasKey("event types")) { + properties.eventTypes = nbt.getInteger("event types"); + } + + return properties; + } + + public JsonObject toJson() { + JsonObject json = new JsonObject(); + + if (name != null) { + json.addProperty("name", name); + } + if (color != null) { + json.addProperty("color", ColorUtils.toRGBString(color)); + } + if (movable != null) { + json.addProperty("movable", movable); + } + if (eventTypes != null) { + JsonArray types = new JsonArray(); + + for (EventType type : EventType.ALL) { + if (hasEventType(type)) { + types.add(type.getName()); + } + } + + json.add("event_types", types); + } + + return json; + } + + public static MeterProperties fromJson(JsonObject json) { + MeterProperties properties = new MeterProperties(); + + if (json.has("name")) { + JsonElement nameJson = json.get("name"); + + if (nameJson.isJsonPrimitive()) { + properties.name = nameJson.getAsString(); + } + } + if (json.has("color")) { + JsonElement colorJson = json.get("color"); + + if (colorJson.isJsonPrimitive()) { + try { + properties.color = ColorUtils.fromRGBString(colorJson.getAsString()); + } catch (NumberFormatException e) { + + } + } + } + if (json.has("movable")) { + JsonElement movableJson = json.get("movable"); + + if (movableJson.isJsonPrimitive()) { + properties.movable = movableJson.getAsBoolean(); + } + } + if (json.has("event_types")) { + JsonElement typesJson = json.get("event_types"); + + if (typesJson.isJsonArray()) { + properties.eventTypes = 0; + JsonArray types = typesJson.getAsJsonArray(); + + for (int index = 0; index < types.size(); index++) { + JsonElement typeJson = types.get(index); + + if (typeJson.isJsonPrimitive()) { + String typeName = typeJson.getAsString(); + EventType type = EventType.byName(typeName); + + if (type != null) { + properties.eventTypes |= type.flag(); + } + } + } + } + } + + return properties; + } + + public static class MutableMeterProperties extends MeterProperties { + + public boolean setPos(DimPos pos) { + DimPos prevPos = super.pos; + super.pos = pos; + + return prevPos == null || !prevPos.equals(pos); + } + + public boolean setName(String name) { + String prevName = super.name; + super.name = name; + + return prevName == null || !prevName.equals(name); + } + + public boolean setColor(Integer color) { + Integer prevColor = super.color; + super.color = color; + + return prevColor == null || !prevColor.equals(color); + } + + public boolean setMovable(Boolean movable) { + Boolean prevMovable = super.movable; + super.movable = movable; + + return prevMovable == null || !prevMovable.equals(movable); + } + + public boolean setEventTypes(Integer eventTypes) { + Integer prevEventTypes = super.eventTypes; + super.eventTypes = eventTypes; + + return prevEventTypes == null || !prevEventTypes.equals(eventTypes); + } + + public boolean toggleEventType(EventType type) { + if (super.eventTypes == null) { + super.eventTypes = 0; + } + + return setEventTypes(super.eventTypes ^ type.flag()); + } + + public MutableMeterProperties mutable() { + return this; + } + + public MeterProperties immutable() { + return new MeterProperties(super.pos, super.name, super.color, super.movable, super.eventTypes); + } + + /** + * If a property does not yet have a value, copy the value from the given properties. + */ + public MutableMeterProperties fill(MeterProperties properties) { + if (properties == null) { + return this; + } + + if (super.pos == null) { + super.pos = properties.pos; + } + if (super.name == null) { + super.name = properties.name; + } + if (super.color == null) { + super.color = properties.color; + } + if (super.movable == null) { + super.movable = properties.movable; + } + if (super.eventTypes == null) { + super.eventTypes = properties.eventTypes; + } + + return this; + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/MeterPropertiesManager.java b/carpetmodSrc/redstone/multimeter/common/meter/MeterPropertiesManager.java new file mode 100644 index 00000000..c456bb26 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/MeterPropertiesManager.java @@ -0,0 +1,33 @@ +package redstone.multimeter.common.meter; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.MeterProperties.MutableMeterProperties; + +public abstract class MeterPropertiesManager { + + public boolean validate(MutableMeterProperties properties) { + DimPos pos = properties.getPos(); + + if (pos == null) { + return false; + } + + World world = getWorld(pos); + + if (world == null) { + return false; + } + + postValidation(properties, world, pos.getBlockPos()); + + return true; + } + + protected abstract World getWorld(DimPos pos); + + protected abstract void postValidation(MutableMeterProperties properties, World world, BlockPos pos); + +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/event/EventType.java b/carpetmodSrc/redstone/multimeter/common/meter/event/EventType.java new file mode 100644 index 00000000..c8cb2e4c --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/event/EventType.java @@ -0,0 +1,93 @@ +package redstone.multimeter.common.meter.event; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagByte; + +import redstone.multimeter.util.NbtUtils; + +public enum EventType { + + UNKNOWN(-1, "unknown"), + POWERED(0, "powered"), + ACTIVE(1, "active"), + MOVED(2, "moved"), + POWER_CHANGE(3, "power_change"), + RANDOM_TICK(4, "random_tick"), + SCHEDULED_TICK(5, "scheduled_tick"), + BLOCK_EVENT(6, "block_event"), + ENTITY_TICK(7, "entity_tick"), + BLOCK_ENTITY_TICK(8, "block_entity_tick"), + BLOCK_UPDATE(9, "block_update"), + COMPARATOR_UPDATE(10, "comparator_update"), + SHAPE_UPDATE(11, "shape_update"), + OBSERVER_UPDATE(12, "observer_update"), + INTERACT_BLOCK(13, "interact_block"); + + public static final EventType[] ALL; + private static final Map BY_NAME; + + static { + + EventType[] types = values(); + + ALL = new EventType[types.length - 1]; + BY_NAME = new HashMap<>(); + + for (int index = 1; index < types.length; index++) { + EventType type = types[index]; + + ALL[type.index] = type; + BY_NAME.put(type.name, type); + } + } + + private final int index; + private final String name; + + private EventType(int index, String name) { + this.index = index; + this.name = name; + } + + public int getIndex() { + return index; + } + + public static EventType byIndex(int index) { + if (index >= 0 && index < ALL.length) { + return ALL[index]; + } + + return UNKNOWN; + } + + public String getName() { + return name; + } + + public static EventType byName(String name) { + return BY_NAME.getOrDefault(name, UNKNOWN); + } + + public int flag() { + return 1 << index; + } + + public NBTBase toNbt() { + return new NBTTagByte((byte)index); + } + + public static EventType fromNbt(NBTBase nbt) { + if (nbt.getId() != NbtUtils.TYPE_BYTE) { + return UNKNOWN; + } + + NBTTagByte NBTTagByte = (NBTTagByte)nbt; + int index = NBTTagByte.getByte(); + + return byIndex(index); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/event/MeterEvent.java b/carpetmodSrc/redstone/multimeter/common/meter/event/MeterEvent.java new file mode 100644 index 00000000..cee89289 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/event/MeterEvent.java @@ -0,0 +1,43 @@ +package redstone.multimeter.common.meter.event; + +import net.minecraft.nbt.NBTTagCompound; + +public class MeterEvent { + + private EventType type; + private int metadata; + + private MeterEvent() { + } + + public MeterEvent(EventType type, int metadata) { + this.type = type; + this.metadata = metadata; + } + + public EventType getType() { + return type; + } + + public int getMetadata() { + return metadata; + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setTag("type", type.toNbt()); + nbt.setInteger("metadata", metadata); + + return nbt; + } + + public static MeterEvent fromNbt(NBTTagCompound nbt) { + MeterEvent event = new MeterEvent(); + + event.type = EventType.fromNbt(nbt.getTag("type")); + event.metadata = nbt.getInteger("metadata"); + + return event; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/log/EventLog.java b/carpetmodSrc/redstone/multimeter/common/meter/log/EventLog.java new file mode 100644 index 00000000..f671271f --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/log/EventLog.java @@ -0,0 +1,102 @@ +package redstone.multimeter.common.meter.log; + +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.TickPhase; +import redstone.multimeter.common.meter.event.MeterEvent; + +public class EventLog { + + private long tick; + private int subtick; + private TickPhase tickPhase; + private MeterEvent event; + + private EventLog() { + } + + public EventLog(long tick, int subtick, TickPhase tickPhase, MeterEvent event) { + this.tick = tick; + this.subtick = subtick; + this.tickPhase = tickPhase; + this.event = event; + } + + public long getTick() { + return tick; + } + + public int getSubtick() { + return subtick; + } + + public boolean isAt(long tick) { + return this.tick == tick; + } + + public boolean isAt(long tick, int subtick) { + return this.tick == tick && this.subtick == subtick; + } + + public boolean isBefore(long tick) { + return this.tick < tick; + } + + public boolean isBefore(long tick, int subtick) { + if (this.tick == tick) { + return this.subtick < subtick; + } + + return this.tick < tick; + } + + public boolean isBefore(EventLog event) { + return isBefore(event.getTick(), event.getSubtick()); + } + + public boolean isAfter(long tick) { + return this.tick > tick; + } + + public boolean isAfter(long tick, int subtick) { + if (this.tick == tick) { + return this.subtick > subtick; + } + + return this.tick > tick; + } + + public boolean isAfter(EventLog event) { + return isAfter(event.getTick(), event.getSubtick()); + } + + public TickPhase getTickPhase() { + return tickPhase; + } + + public MeterEvent getEvent() { + return event; + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setTag("meter event", event.toNbt()); + nbt.setLong("tick", tick); + nbt.setInteger("subtick", subtick); + nbt.setTag("tick phase", tickPhase.toNbt()); + + return nbt; + } + + public static EventLog fromNbt(NBTTagCompound nbt) { + EventLog log = new EventLog(); + + log.event = MeterEvent.fromNbt(nbt.getCompoundTag("meter event")); + log.tick = nbt.getLong("tick"); + log.subtick = nbt.getInteger("subtick"); + log.tickPhase = TickPhase.fromNbt(nbt.getTag("tick phase")); + + return log; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/log/LogManager.java b/carpetmodSrc/redstone/multimeter/common/meter/log/LogManager.java new file mode 100644 index 00000000..f8746252 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/log/LogManager.java @@ -0,0 +1,15 @@ +package redstone.multimeter.common.meter.log; + +import redstone.multimeter.common.meter.Meter; +import redstone.multimeter.common.meter.MeterGroup; + +public abstract class LogManager { + + protected abstract MeterGroup getMeterGroup(); + + public void clearLogs() { + for (Meter meter : getMeterGroup().getMeters()) { + meter.getLogs().clear(); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/meter/log/MeterLogs.java b/carpetmodSrc/redstone/multimeter/common/meter/log/MeterLogs.java new file mode 100644 index 00000000..62a1e2a1 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/meter/log/MeterLogs.java @@ -0,0 +1,183 @@ +package redstone.multimeter.common.meter.log; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.util.ListUtils; +import redstone.multimeter.util.NbtUtils; + +public class MeterLogs { + + private final List[] eventLogs; + + private long count = 0; + + public MeterLogs() { + @SuppressWarnings("unchecked") + List[] lists = new List[EventType.ALL.length]; + + for (int index = 0; index < lists.length; index++) { + lists[index] = new ArrayList<>(); + } + + this.eventLogs = lists; + } + + public void clear() { + for (List logs : eventLogs) { + logs.clear(); + } + + count = 0; + } + + public boolean isEmpty() { + return count == 0; + } + + private List getLogs(EventType type) { + return eventLogs[type.getIndex()]; + } + + public void add(EventLog log) { + EventType type = log.getEvent().getType(); + List logs = getLogs(type); + + logs.add(getLastLogBefore(type, log.getTick(), log.getSubtick()) + 1, log); + + count++; + } + + public void clearOldLogs(long cutoff) { + for (List logs : eventLogs) { + while (!logs.isEmpty()) { + EventLog log = logs.get(0); + + if (log.getTick() > cutoff) { + break; + } + + logs.remove(0); + } + } + } + + public EventLog getLog(EventType type, int index) { + if (index < 0) { + return null; + } + + List logs = getLogs(type); + + if (index >= logs.size()) { + return null; + } + + return logs.get(index); + } + + public int getLastLogBefore(EventType type, long tick) { + return getLastLogBefore(type, tick, 0); + } + + public int getLastLogBefore(EventType type, long tick, int subtick) { + List logs = getLogs(type); + + if (logs.isEmpty() || !logs.get(0).isBefore(tick, subtick)) { + return -1; + } + if (logs.get(logs.size() - 1).isBefore(tick, subtick)) { + return logs.size() - 1; + } + + int index = ListUtils.binarySearch(logs, event -> event.isBefore(tick, subtick)); + EventLog log = logs.get(index); + + while (!log.isBefore(tick, subtick)) { + if (index == 0) { + return -1; + } + + log = logs.get(--index); + } + + return index; + } + + public EventLog getLastLogBefore(long tick) { + return getLastLogBefore(tick, 0); + } + + public EventLog getLastLogBefore(long tick, int subtick) { + EventLog lastLog = null; + + for (EventType type : EventType.ALL) { + int index = getLastLogBefore(type, tick, subtick); + EventLog log = getLog(type, index); + + if (lastLog == null || (log != null && log.isAfter(lastLog))) { + lastLog = log; + } + } + + return lastLog; + } + + public EventLog getLogAt(long tick, int subtick) { + EventLog log = getLastLogBefore(tick, subtick + 1); + return log != null && log.isAt(tick, subtick) ? log : null; + } + + public NBTTagCompound toNbt() { + NBTTagCompound nbt = new NBTTagCompound(); + + for (EventType type : EventType.ALL) { + NBTTagList logs = toNbt(type); + + if (!logs.isEmpty()) { + nbt.setTag(type.getName(), logs); + } + } + + return nbt; + } + + private NBTTagList toNbt(EventType type) { + NBTTagList list = new NBTTagList(); + + for (EventLog log : getLogs(type)) { + list.appendTag(log.toNbt()); + } + + return list; + } + + public static Collection fromNbt(NBTTagCompound nbt) { + Collection logs = new ArrayList<>(); + + for (String key : nbt.getKeySet()) { + EventType type = EventType.byName(key); + + if (type != null) { + logs.addAll(fromNbt(type, nbt.getTagList(key, NbtUtils.TYPE_COMPOUND))); + } + } + + return logs; + } + + public static Collection fromNbt(EventType type, NBTTagList nbt) { + Collection logs = new ArrayList<>(); + + for (int i = 0; i < nbt.tagCount(); i++) { + logs.add(EventLog.fromNbt(nbt.getCompoundTagAt(i))); + } + + return logs; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/PacketHandler.java b/carpetmodSrc/redstone/multimeter/common/network/PacketHandler.java new file mode 100644 index 00000000..bd92bd75 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/PacketHandler.java @@ -0,0 +1,46 @@ +package redstone.multimeter.common.network; + +import java.io.IOException; + +import io.netty.buffer.Unpooled; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketBuffer; + +public abstract class PacketHandler { + + public Packet encode(RSMMPacket packet) { + String key = Packets.getKey(packet); + + if (key == null) { + throw new IllegalStateException("Unable to encode packet: " + packet.getClass()); + } + + NBTTagCompound data = new NBTTagCompound(); + packet.encode(data); + + PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + + buffer.writeString(key); + buffer.writeCompoundTag(data); + + return toCustomPayload(Packets.getChannel(), buffer); + } + + protected abstract Packet toCustomPayload(String channel, PacketBuffer data); + + protected RSMMPacket decode(PacketBuffer buffer) throws IOException { + String key = buffer.readString(32767); + RSMMPacket packet = Packets.create(key); + + if (packet == null) { + throw new IllegalStateException("Unable to decode packet: " + key); + } + + NBTTagCompound data = buffer.readCompoundTag(); + packet.decode(data); + + return packet; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/Packets.java b/carpetmodSrc/redstone/multimeter/common/network/Packets.java new file mode 100644 index 00000000..206b9510 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/Packets.java @@ -0,0 +1,43 @@ +package redstone.multimeter.common.network; + +import redstone.multimeter.common.network.packets.*; +import redstone.multimeter.registry.SupplierRegistry; + +public class Packets { + + private static final SupplierRegistry REGISTRY; + + public static String getChannel() { + return REGISTRY.getRegistryKey(); + } + + public static String getKey(RSMMPacket packet) { + return REGISTRY.getKey(packet); + } + + public static RSMMPacket create(String key) { + return REGISTRY.get(key); + } + + static { + + REGISTRY = new SupplierRegistry<>(); + + REGISTRY.register("handshake" , HandshakePacket.class , () -> new HandshakePacket()); + REGISTRY.register("tick_phase_tree" , TickPhaseTreePacket.class , () -> new TickPhaseTreePacket()); + REGISTRY.register("rebuild_tick_phase_tree" , RebuildTickPhaseTreePacket.class , () -> new RebuildTickPhaseTreePacket()); + REGISTRY.register("tick_time" , TickTimePacket.class , () -> new TickTimePacket()); + REGISTRY.register("meter_group_subscription", MeterGroupSubscriptionPacket.class, () -> new MeterGroupSubscriptionPacket()); + REGISTRY.register("meter_group_default" , MeterGroupDefaultPacket.class , () -> new MeterGroupDefaultPacket()); + REGISTRY.register("meter_group_refresh" , MeterGroupRefreshPacket.class , () -> new MeterGroupRefreshPacket()); + REGISTRY.register("meter_updates" , MeterUpdatesPacket.class , () -> new MeterUpdatesPacket()); + REGISTRY.register("meter_logs" , MeterLogsPacket.class , () -> new MeterLogsPacket()); + REGISTRY.register("clear_meter_group" , ClearMeterGroupPacket.class , () -> new ClearMeterGroupPacket()); + REGISTRY.register("add_meter" , AddMeterPacket.class , () -> new AddMeterPacket()); + REGISTRY.register("remove_meter" , RemoveMeterPacket.class , () -> new RemoveMeterPacket()); + REGISTRY.register("meter_update" , MeterUpdatePacket.class , () -> new MeterUpdatePacket()); + REGISTRY.register("meter_index" , MeterIndexPacket.class , () -> new MeterIndexPacket()); + REGISTRY.register("teleport_to_meter" , TeleportToMeterPacket.class , () -> new TeleportToMeterPacket()); + + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/RSMMPacket.java b/carpetmodSrc/redstone/multimeter/common/network/RSMMPacket.java new file mode 100644 index 00000000..8cad13d6 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/RSMMPacket.java @@ -0,0 +1,24 @@ +package redstone.multimeter.common.network; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.server.MultimeterServer; + +public interface RSMMPacket { + + public void encode(NBTTagCompound data); + + public void decode(NBTTagCompound data); + + public void handle(MultimeterServer server, EntityPlayerMP player); + + /** + * Most RSMM packets are ignored if the redstoneMultimeter carpet + * rule is not enabled. Some packets are handled anyway in order + * to keep RSMM working properly when the carpet rule is toggled. + */ + default boolean force() { + return false; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/AddMeterPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/AddMeterPacket.java new file mode 100644 index 00000000..8fdad9fa --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/AddMeterPacket.java @@ -0,0 +1,35 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.meter.MeterProperties; +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class AddMeterPacket implements RSMMPacket { + + private MeterProperties properties; + + public AddMeterPacket() { + } + + public AddMeterPacket(MeterProperties properties) { + this.properties = properties; + } + + @Override + public void encode(NBTTagCompound data) { + data.setTag("properties", properties.toNbt()); + } + + @Override + public void decode(NBTTagCompound data) { + properties = MeterProperties.fromNbt(data.getCompoundTag("properties")); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.getMultimeter().addMeter(player, properties); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/ClearMeterGroupPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/ClearMeterGroupPacket.java new file mode 100644 index 00000000..e986f0d6 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/ClearMeterGroupPacket.java @@ -0,0 +1,25 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class ClearMeterGroupPacket implements RSMMPacket { + + public ClearMeterGroupPacket() { + } + + @Override + public void encode(NBTTagCompound data) { + } + + @Override + public void decode(NBTTagCompound data) { + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/HandshakePacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/HandshakePacket.java new file mode 100644 index 00000000..30289fa4 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/HandshakePacket.java @@ -0,0 +1,37 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.RedstoneMultimeter; +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class HandshakePacket implements RSMMPacket { + + private String modVersion; + + public HandshakePacket() { + modVersion = RedstoneMultimeter.MOD_VERSION; + } + + @Override + public void encode(NBTTagCompound data) { + data.setString("mod version", modVersion); + } + + @Override + public void decode(NBTTagCompound data) { + modVersion = data.getString("mod version"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.onHandshake(player, modVersion); + } + + @Override + public boolean force() { + return true; + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupDefaultPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupDefaultPacket.java new file mode 100644 index 00000000..a380e5f4 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupDefaultPacket.java @@ -0,0 +1,25 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class MeterGroupDefaultPacket implements RSMMPacket { + + public MeterGroupDefaultPacket() { + } + + @Override + public void encode(NBTTagCompound data) { + } + + @Override + public void decode(NBTTagCompound data) { + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupRefreshPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupRefreshPacket.java new file mode 100644 index 00000000..18fb181f --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupRefreshPacket.java @@ -0,0 +1,44 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.meter.MeterGroup; +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.MultimeterServer; + +public class MeterGroupRefreshPacket implements RSMMPacket { + + private String name; + private NBTTagCompound meterGroupData; + + public MeterGroupRefreshPacket() { + } + + public MeterGroupRefreshPacket(MeterGroup meterGroup) { + this.name = meterGroup.getName(); + this.meterGroupData = meterGroup.toNbt(); + } + + @Override + public void encode(NBTTagCompound data) { + data.setString("name", name); + data.setTag("data", meterGroupData); + } + + @Override + public void decode(NBTTagCompound data) { + name = data.getString("name"); + meterGroupData = data.getCompoundTag("data"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + Multimeter multimeter = server.getMultimeter(); + + if (multimeter.hasSubscription(player)) { + multimeter.refreshMeterGroup(player); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupSubscriptionPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupSubscriptionPacket.java new file mode 100644 index 00000000..fc904a14 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterGroupSubscriptionPacket.java @@ -0,0 +1,55 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.MultimeterServer; +import redstone.multimeter.server.meter.ServerMeterGroup; + +public class MeterGroupSubscriptionPacket implements RSMMPacket { + + private String name; + private boolean subscribe; + + public MeterGroupSubscriptionPacket() { + } + + public MeterGroupSubscriptionPacket(String name, boolean subscribed) { + this.name = name; + this.subscribe = subscribed; + } + + @Override + public void encode(NBTTagCompound data) { + data.setString("name", name); + data.setBoolean("subscribe", subscribe); + } + + @Override + public void decode(NBTTagCompound data) { + name = data.getString("name"); + subscribe = data.getBoolean("subscribe"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + Multimeter multimeter = server.getMultimeter(); + ServerMeterGroup meterGroup = multimeter.getMeterGroup(name); + + if (subscribe) { + if (meterGroup == null) { + multimeter.createMeterGroup(player, name); + } else { + multimeter.subscribeToMeterGroup(meterGroup, player); + } + } else { + if (meterGroup == null) { + multimeter.refreshMeterGroup(player); + } else { + multimeter.unsubscribeFromMeterGroup(meterGroup, player); + } + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterIndexPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterIndexPacket.java new file mode 100644 index 00000000..bbb1bad2 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterIndexPacket.java @@ -0,0 +1,38 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class MeterIndexPacket implements RSMMPacket { + + private long id; + private int index; + + public MeterIndexPacket() { + } + + public MeterIndexPacket(long id, int index) { + this.id = id; + this.index = index; + } + + @Override + public void encode(NBTTagCompound data) { + data.setLong("id", id); + data.setInteger("index", index); + } + + @Override + public void decode(NBTTagCompound data) { + id = data.getLong("id"); + index = data.getInteger("index"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.getMultimeter().setMeterIndex(player, id, index); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterLogsPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterLogsPacket.java new file mode 100644 index 00000000..f4cf862f --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterLogsPacket.java @@ -0,0 +1,35 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; +import redstone.multimeter.util.NbtUtils; + +public class MeterLogsPacket implements RSMMPacket { + + private NBTTagList logsData; + + public MeterLogsPacket() { + } + + public MeterLogsPacket(NBTTagList logsData) { + this.logsData = logsData; + } + + @Override + public void encode(NBTTagCompound data) { + data.setTag("logs", logsData); + } + + @Override + public void decode(NBTTagCompound data) { + logsData = data.getTagList("logs", NbtUtils.TYPE_COMPOUND); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatePacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatePacket.java new file mode 100644 index 00000000..d2503ca6 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatePacket.java @@ -0,0 +1,39 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.meter.MeterProperties; +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class MeterUpdatePacket implements RSMMPacket { + + private long id; + private MeterProperties properties; + + public MeterUpdatePacket() { + } + + public MeterUpdatePacket(long id, MeterProperties properties) { + this.id = id; + this.properties = properties; + } + + @Override + public void encode(NBTTagCompound data) { + data.setLong("id", id); + data.setTag("properties", properties.toNbt()); + } + + @Override + public void decode(NBTTagCompound data) { + id = data.getLong("id"); + properties = MeterProperties.fromNbt(data.getCompoundTag("properties")); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.getMultimeter().updateMeter(player, id, properties); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatesPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatesPacket.java new file mode 100644 index 00000000..f71edf56 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/MeterUpdatesPacket.java @@ -0,0 +1,113 @@ +package redstone.multimeter.common.network.packets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagLong; + +import redstone.multimeter.common.meter.MeterProperties; +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; +import redstone.multimeter.util.NbtUtils; + +public class MeterUpdatesPacket implements RSMMPacket { + + private List removedMeters; + private Long2ObjectMap meterUpdates; + private List meters; + + public MeterUpdatesPacket() { + this.removedMeters = new ArrayList<>(); + this.meterUpdates = new Long2ObjectOpenHashMap<>(); + this.meters = new ArrayList<>(); + } + + public MeterUpdatesPacket(List removedMeters, Map updates, List meters) { + this.removedMeters = new ArrayList<>(removedMeters); + this.meterUpdates = new Long2ObjectOpenHashMap<>(updates); + this.meters = new ArrayList<>(meters); + } + + @Override + public void encode(NBTTagCompound data) { + if (!removedMeters.isEmpty()) { + NBTTagList list = new NBTTagList(); + + for (int i = 0; i < removedMeters.size(); i++) { + list.appendTag(new NBTTagLong(removedMeters.get(i))); + } + + data.setTag("removed", list); + } + if (!meterUpdates.isEmpty()) { + NBTTagList list = new NBTTagList(); + + for (Entry entry : meterUpdates.long2ObjectEntrySet()) { + long id = entry.getLongKey(); + MeterProperties update = entry.getValue(); + + NBTTagCompound nbt = update.toNbt(); + nbt.setLong("id", id); + list.appendTag(nbt); + } + + data.setTag("updates", list); + } + if (!meters.isEmpty()) { + NBTTagList list = new NBTTagList(); + + for (int i = 0; i < meters.size(); i++) { + list.appendTag(new NBTTagLong(meters.get(i))); + } + + data.setTag("meters", list); + } + } + + @Override + public void decode(NBTTagCompound data) { + if (data.hasKey("removed")) { + NBTTagList ids = data.getTagList("removed", NbtUtils.TYPE_LONG); + + for (int i = 0; i < ids.tagCount(); i++) { + NBTTagLong nbt = (NBTTagLong)ids.get(i); + long id = nbt.getLong(); + + removedMeters.add(id); + } + } + if (data.hasKey("updates")) { + NBTTagList updates = data.getTagList("updates", NbtUtils.TYPE_COMPOUND); + + for (int i = 0; i < updates.tagCount(); i++) { + NBTTagCompound nbt = updates.getCompoundTagAt(i); + long id = nbt.getLong("id"); + MeterProperties update = MeterProperties.fromNbt(nbt); + + meterUpdates.put(id, update); + } + } + if (data.hasKey("meters")) { + NBTTagList ids = data.getTagList("meters", NbtUtils.TYPE_LONG); + + for (int i = 0; i < ids.tagCount(); i++) { + NBTTagLong nbt = (NBTTagLong)ids.get(i); + long id = nbt.getLong(); + + meters.add(id); + } + } + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/RebuildTickPhaseTreePacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/RebuildTickPhaseTreePacket.java new file mode 100644 index 00000000..bd381ea5 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/RebuildTickPhaseTreePacket.java @@ -0,0 +1,26 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class RebuildTickPhaseTreePacket implements RSMMPacket { + + public RebuildTickPhaseTreePacket() { + } + + @Override + public void encode(NBTTagCompound data) { + } + + @Override + public void decode(NBTTagCompound data) { + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.rebuildTickPhaseTree(player); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/RemoveMeterPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/RemoveMeterPacket.java new file mode 100644 index 00000000..f17c63a1 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/RemoveMeterPacket.java @@ -0,0 +1,34 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class RemoveMeterPacket implements RSMMPacket { + + private long id; + + public RemoveMeterPacket() { + } + + public RemoveMeterPacket(long id) { + this.id = id; + } + + @Override + public void encode(NBTTagCompound data) { + data.setLong("id", id); + } + + @Override + public void decode(NBTTagCompound data) { + id = data.getLong("id"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.getMultimeter().removeMeter(player, id); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/TeleportToMeterPacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/TeleportToMeterPacket.java new file mode 100644 index 00000000..1e6bf5fe --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/TeleportToMeterPacket.java @@ -0,0 +1,34 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class TeleportToMeterPacket implements RSMMPacket { + + private long id; + + public TeleportToMeterPacket() { + } + + public TeleportToMeterPacket(long id) { + this.id = id; + } + + @Override + public void encode(NBTTagCompound data) { + data.setLong("id", id); + } + + @Override + public void decode(NBTTagCompound data) { + id = data.getLong("id"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.getMultimeter().teleportToMeter(player, id); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/TickPhaseTreePacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/TickPhaseTreePacket.java new file mode 100644 index 00000000..375e99c4 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/TickPhaseTreePacket.java @@ -0,0 +1,34 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class TickPhaseTreePacket implements RSMMPacket { + + private NBTTagCompound nbt; + + public TickPhaseTreePacket() { + } + + public TickPhaseTreePacket(NBTTagCompound nbt) { + this.nbt = nbt; + } + + @Override + public void encode(NBTTagCompound data) { + data.setTag("tick phase tree", nbt); + } + + @Override + public void decode(NBTTagCompound data) { + nbt = data.getCompoundTag("tick phase tree"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + server.refreshTickPhaseTree(player); + } +} diff --git a/carpetmodSrc/redstone/multimeter/common/network/packets/TickTimePacket.java b/carpetmodSrc/redstone/multimeter/common/network/packets/TickTimePacket.java new file mode 100644 index 00000000..8020fe79 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/common/network/packets/TickTimePacket.java @@ -0,0 +1,33 @@ +package redstone.multimeter.common.network.packets; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.MultimeterServer; + +public class TickTimePacket implements RSMMPacket { + + private long gameTime; + + public TickTimePacket() { + } + + public TickTimePacket(long serverTime) { + this.gameTime = serverTime; + } + + @Override + public void encode(NBTTagCompound data) { + data.setLong("game time", gameTime); + } + + @Override + public void decode(NBTTagCompound data) { + gameTime = data.getLong("game time"); + } + + @Override + public void handle(MultimeterServer server, EntityPlayerMP player) { + } +} diff --git a/carpetmodSrc/redstone/multimeter/helper/BlockChestHelper.java b/carpetmodSrc/redstone/multimeter/helper/BlockChestHelper.java new file mode 100644 index 00000000..09af3870 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/helper/BlockChestHelper.java @@ -0,0 +1,59 @@ +package redstone.multimeter.helper; + +import carpet.CarpetSettings; +import net.minecraft.block.BlockChest; +import net.minecraft.block.state.IBlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +import redstone.multimeter.block.PowerSource; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.MultimeterServer; + +public class BlockChestHelper { + + public static boolean isTrapped(BlockChest chest) { + return chest.chestType == BlockChest.Type.TRAP; + } + + public static boolean isTrapped(TileEntityChest chest) { + return chest.getChestType() == BlockChest.Type.TRAP; + } + + public static int getPower(World world, BlockPos pos, IBlockState state) { + TileEntity blockEntity = world.getTileEntity(pos); + + if (blockEntity instanceof TileEntityChest) { + return getPowerFromViewerCount(((TileEntityChest)blockEntity).numPlayersUsing); + } + + return PowerSource.MIN_POWER; + } + + public static int getPowerFromViewerCount(int viewerCount) { + return MathHelper.clamp(viewerCount, PowerSource.MIN_POWER, PowerSource.MAX_POWER); + } + + public static void onInvOpenOrClosed(TileEntityChest chest, boolean open) { + if (CarpetSettings.redstoneMultimeter && isTrapped(chest)) { + WorldServer world = (WorldServer)chest.getWorld(); + BlockPos pos = chest.getPos(); + + MultimeterServer server = WorldHelper.getMultimeterServer(); + Multimeter multimeter = server.getMultimeter(); + + int viewerCount = chest.numPlayersUsing; + int oldViewerCount = open ? viewerCount - 1 : viewerCount + 1; + + int oldPower = BlockChestHelper.getPowerFromViewerCount(oldViewerCount); + int newPower = BlockChestHelper.getPowerFromViewerCount(viewerCount); + + multimeter.logPowerChange(world, pos, oldPower, newPower); + multimeter.logActive(world, pos, newPower > PowerSource.MIN_POWER); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/helper/WorldHelper.java b/carpetmodSrc/redstone/multimeter/helper/WorldHelper.java new file mode 100644 index 00000000..b94bc5e0 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/helper/WorldHelper.java @@ -0,0 +1,100 @@ +package redstone.multimeter.helper; + +import carpet.CarpetServer; +import carpet.CarpetSettings; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.common.TickTask; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.MultimeterServer; + +public class WorldHelper { + + public static int currentBlockEventDepth; + + public static MultimeterServer getMultimeterServer() { + return CarpetServer.rsmmServer; + } + + public static Multimeter getMultimeter() { + return CarpetServer.rsmmServer.getMultimeter(); + } + + public static void startTickTask(TickTask task, String... args) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeterServer().startTickTask(task, args); + } + } + + public static void endTickTask() { + if (CarpetSettings.redstoneMultimeter) { + getMultimeterServer().endTickTask(); + } + } + + public static void swapTickTask(TickTask task, String... args) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeterServer().swapTickTask(task, args); + } + } + + public static void onBlockUpdate(World world, BlockPos pos, IBlockState state) { + if (CarpetSettings.redstoneMultimeter) { + MultimeterServer server = getMultimeterServer(); + Multimeter multimeter = server.getMultimeter(); + + multimeter.logBlockUpdate(world, pos); + + if (state.getBlock().rsmm$logPoweredOnBlockUpdate()) { + multimeter.logPowered(world, pos, state); + } + } + } + + public static void onObserverUpdate(World world, BlockPos pos) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logObserverUpdate(world, pos); + } + } + + public static void onEntityTick(World world, Entity entity) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logEntityTick(world, entity); + } + } + + public static void onBlockEntityTick(World world, TileEntity blockEntity) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logBlockEntityTick(world, blockEntity); + } + } + + public static void onComparatorUpdate(World world, BlockPos pos) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logComparatorUpdate(world, pos); + } + } + + public static void onRandomTick(World world, BlockPos pos) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logRandomTick(world, pos); + } + } + + public static void onScheduledTick(World world, BlockPos pos, int priority, boolean scheduling) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logScheduledTick(world, pos, priority, scheduling); + } + } + + public static void onBlockEvent(World world, BlockPos pos, int type, boolean scheduling) { + if (CarpetSettings.redstoneMultimeter) { + getMultimeter().logBlockEvent(world, pos, type, currentBlockEventDepth, scheduling); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/interfaces/IBlock.java b/carpetmodSrc/redstone/multimeter/interfaces/IBlock.java new file mode 100644 index 00000000..c762c8b0 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/interfaces/IBlock.java @@ -0,0 +1,24 @@ +package redstone.multimeter.interfaces; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface IBlock { + + default boolean rsmm$isMeterable() { + return false; + } + + default boolean rsmm$isPowerSource() { + return false; + } + + default boolean rsmm$logPoweredOnBlockUpdate() { + return true; + } + + default boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { + return world.isBlockPowered(pos); + } +} diff --git a/carpetmodSrc/redstone/multimeter/registry/SupplierRegistry.java b/carpetmodSrc/redstone/multimeter/registry/SupplierRegistry.java new file mode 100644 index 00000000..bf63645c --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/registry/SupplierRegistry.java @@ -0,0 +1,51 @@ +package redstone.multimeter.registry; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import redstone.multimeter.RedstoneMultimeter; + +public class SupplierRegistry { + + private final String key; + private final Map, String> byKey; + private final Map> keys; + + public SupplierRegistry() { + this(RedstoneMultimeter.NAMESPACE); + } + + public SupplierRegistry(String key) { + this.key = key; + this.byKey = new HashMap<>(); + this.keys = new HashMap<>(); + } + + public String getRegistryKey() { + return key; + } + + public T get(String key) { + Supplier supplier = keys.get(key); + return supplier == null ? null : supplier.get(); + } + + public String getKey(T obj) { + return byKey.get(obj.getClass()); + } + + public

void register(String name, Class

type, Supplier

supplier) { + String key = this.key + "|" + name; + + if (byKey.containsKey(type)) { + throw new IllegalStateException("Registry " + this.key + " already registered an entry with type " + type); + } + if (keys.containsKey(key)) { + throw new IllegalStateException("Registry " + this.key + " already registered an entry with key " + key); + } + + byKey.put(type, key); + keys.put(key, supplier); + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/Multimeter.java b/carpetmodSrc/redstone/multimeter/server/Multimeter.java new file mode 100644 index 00000000..29c39dc5 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/Multimeter.java @@ -0,0 +1,582 @@ +package redstone.multimeter.server; + +import java.text.NumberFormat; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; +import net.minecraft.util.text.event.HoverEvent; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; + +import redstone.multimeter.block.Meterable; +import redstone.multimeter.block.PowerSource; +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.Meter; +import redstone.multimeter.common.meter.MeterGroup; +import redstone.multimeter.common.meter.MeterProperties; +import redstone.multimeter.common.meter.MeterProperties.MutableMeterProperties; +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.common.network.packets.ClearMeterGroupPacket; +import redstone.multimeter.common.network.packets.MeterGroupDefaultPacket; +import redstone.multimeter.common.network.packets.MeterGroupRefreshPacket; +import redstone.multimeter.common.network.packets.MeterGroupSubscriptionPacket; +import redstone.multimeter.server.meter.ServerMeterGroup; +import redstone.multimeter.server.meter.ServerMeterPropertiesManager; +import redstone.multimeter.server.meter.event.MeterEventPredicate; +import redstone.multimeter.server.option.Options; +import redstone.multimeter.server.option.OptionsManager; + +public class Multimeter { + + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(Locale.US); + + private final MultimeterServer server; + private final Map meterGroups; + private final Map subscriptions; + private final Set activeMeterGroups; + private final Set idleMeterGroups; + private final ServerMeterPropertiesManager meterPropertiesManager; + + public Options options; + + public Multimeter(MultimeterServer server) { + this.server = server; + this.meterGroups = new LinkedHashMap<>(); + this.subscriptions = new HashMap<>(); + this.activeMeterGroups = new HashSet<>(); + this.idleMeterGroups = new HashSet<>(); + this.meterPropertiesManager = new ServerMeterPropertiesManager(this); + + reloadOptions(); + } + + public MultimeterServer getServer() { + return server; + } + + public Collection getMeterGroups() { + return Collections.unmodifiableCollection(meterGroups.values()); + } + + public ServerMeterGroup getMeterGroup(String name) { + return meterGroups.get(name); + } + + public boolean hasMeterGroup(String name) { + return meterGroups.containsKey(name); + } + + public ServerMeterGroup getSubscription(EntityPlayerMP player) { + return subscriptions.get(player.getUniqueID()); + } + + public boolean hasSubscription(EntityPlayerMP player) { + return subscriptions.containsKey(player.getUniqueID()); + } + + public boolean isOwnerOfSubscription(EntityPlayerMP player) { + ServerMeterGroup meterGroup = getSubscription(player); + return meterGroup != null && meterGroup.isOwnedBy(player); + } + + public void reloadOptions() { + if (server.isDedicated()) { + options = OptionsManager.load(server.getConfigDirectory()); + } else { + options = new Options(); + } + } + + public void tickStart(boolean paused) { + if (!paused) { + removeIdleMeterGroups(); + + for (ServerMeterGroup meterGroup : meterGroups.values()) { + meterGroup.tick(); + } + } + } + + public void tickEnd(boolean paused) { + broadcastMeterUpdates(); + + if (!paused) { + broadcastMeterLogs(); + } + } + + private void removeIdleMeterGroups() { + Iterator it = idleMeterGroups.iterator(); + + while (it.hasNext()) { + ServerMeterGroup meterGroup = it.next(); + + if (removeIdleMeterGroup(meterGroup)) { + it.remove(); + } + } + } + + private boolean removeIdleMeterGroup(ServerMeterGroup meterGroup) { + if (meterGroup.hasMeters() && !meterGroup.isPastIdleTimeLimit()) { + return false; + } + + meterGroups.remove(meterGroup.getName(), meterGroup); + + if (meterGroup.hasMeters()) { + notifyOwnerOfRemoval(meterGroup); + } + + return true; + } + + private void notifyOwnerOfRemoval(ServerMeterGroup meterGroup) { + UUID ownerUuid = meterGroup.getOwner(); + EntityPlayerMP owner = server.getPlayerList().get(ownerUuid); + + if (owner != null) { + ITextComponent message = new TextComponentString(String.format("One of your meter groups, \'%s\', was idle for more than %d ticks and has been removed.", meterGroup.getName(), options.meter_group.max_idle_time)); + server.sendMessage(owner, message, false); + } + } + + private void broadcastMeterUpdates() { + for (ServerMeterGroup meterGroup : meterGroups.values()) { + meterGroup.broadcastUpdates(); + } + } + + private void broadcastMeterLogs() { + for (ServerMeterGroup meterGroup : meterGroups.values()) { + meterGroup.getLogManager().broadcastLogs(); + } + } + + public void onPlayerJoin(EntityPlayerMP player) { + server.refreshTickPhaseTree(player); + server.getPlayerList().updatePermissions(player); + } + + public void onPlayerLeave(EntityPlayerMP player) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + removeSubscriberFromMeterGroup(meterGroup, player); + } + } + + public void addMeter(EntityPlayerMP player, MeterProperties properties) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + if (meterGroup.isPastMeterLimit()) { + ITextComponent message = new TextComponentString(String.format("meter limit (%d) reached!", options.meter_group.meter_limit)); + server.sendMessage(player, message, true); + } else if (!addMeter(meterGroup, properties)) { + refreshMeterGroup(meterGroup, player); + } + } + } + + public boolean addMeter(ServerMeterGroup meterGroup, MeterProperties meterProperties) { + MutableMeterProperties properties = meterProperties.mutable(); + + if (!meterPropertiesManager.validate(properties) || !meterGroup.addMeter(properties)) { + return false; + } + + DimPos pos = properties.getPos(); + World world = server.getWorld(pos); + BlockPos blockPos = pos.getBlockPos(); + IBlockState state = world.getBlockState(blockPos); + + logPowered(world, blockPos, state); + logActive(world, blockPos, state); + + return true; + } + + public void removeMeter(EntityPlayerMP player, long id) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null && !meterGroup.removeMeter(id)) { + refreshMeterGroup(meterGroup, player); + } + } + + public void updateMeter(EntityPlayerMP player, long id, MeterProperties newProperties) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null && !meterGroup.updateMeter(id, newProperties)) { + refreshMeterGroup(meterGroup, player); + } + } + + public void setMeterIndex(EntityPlayerMP player, long id, int index) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null && !meterGroup.setMeterIndex(id, index)) { + refreshMeterGroup(meterGroup, player); + } + } + + public void clearMeterGroup(EntityPlayerMP player) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + clearMeterGroup(meterGroup); + } + } + + public void clearMeterGroup(ServerMeterGroup meterGroup) { + meterGroup.clear(); + + ClearMeterGroupPacket packet = new ClearMeterGroupPacket(); + server.getPlayerList().send(packet, meterGroup); + } + + public void createMeterGroup(EntityPlayerMP player, String name) { + if (!MeterGroup.isValidName(name) || meterGroups.containsKey(name)) { + return; + } + + ServerMeterGroup meterGroup = new ServerMeterGroup(this, name, player); + meterGroups.put(name, meterGroup); + + subscribeToMeterGroup(meterGroup, player); + } + + public void subscribeToMeterGroup(ServerMeterGroup meterGroup, EntityPlayerMP player) { + ServerMeterGroup prevSubscription = getSubscription(player); + + if (prevSubscription == meterGroup) { + refreshMeterGroup(meterGroup, player); + } else { + if (prevSubscription != null) { + removeSubscriberFromMeterGroup(prevSubscription, player); + } + + addSubscriberToMeterGroup(meterGroup, player); + onSubscriptionChanged(player, prevSubscription, meterGroup); + } + } + + public void subscribeToDefaultMeterGroup(EntityPlayerMP player) { + MeterGroupDefaultPacket packet = new MeterGroupDefaultPacket(); + server.getPlayerList().send(packet, player); + } + + private void addSubscriberToMeterGroup(ServerMeterGroup meterGroup, EntityPlayerMP player) { + UUID playerUuid = player.getUniqueID(); + + subscriptions.put(playerUuid, meterGroup); + meterGroup.addSubscriber(playerUuid); + + if (meterGroup.updateIdleState()) { + activeMeterGroups.add(meterGroup); + idleMeterGroups.remove(meterGroup); + } + } + + public void unsubscribeFromMeterGroup(EntityPlayerMP player) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + unsubscribeFromMeterGroup(meterGroup, player); + } + } + + public void unsubscribeFromMeterGroup(ServerMeterGroup meterGroup, EntityPlayerMP player) { + if (meterGroup.hasSubscriber(player)) { + removeSubscriberFromMeterGroup(meterGroup, player); + onSubscriptionChanged(player, meterGroup, null); + } + } + + private void removeSubscriberFromMeterGroup(ServerMeterGroup meterGroup, EntityPlayerMP player) { + UUID playerUuid = player.getUniqueID(); + + subscriptions.remove(playerUuid, meterGroup); + meterGroup.removeSubscriber(playerUuid); + + if (meterGroup.updateIdleState()) { + activeMeterGroups.remove(meterGroup); + idleMeterGroups.add(meterGroup); + } + } + + private void onSubscriptionChanged(EntityPlayerMP player, ServerMeterGroup prevSubscription, ServerMeterGroup newSubscription) { + MeterGroupSubscriptionPacket packet; + + if (newSubscription == null) { + packet = new MeterGroupSubscriptionPacket(prevSubscription.getName(), false); + } else { + packet = new MeterGroupSubscriptionPacket(newSubscription.getName(), true); + } + + server.getPlayerList().send(packet, player); + server.getPlayerList().updatePermissions(player); + } + + public void clearMembersOfMeterGroup(ServerMeterGroup meterGroup) { + for (UUID playerUuid : meterGroup.getMembers()) { + removeMemberFromMeterGroup(meterGroup, playerUuid); + } + } + + public void addMemberToMeterGroup(ServerMeterGroup meterGroup, UUID playerUuid) { + if (meterGroup.hasMember(playerUuid) || meterGroup.isOwnedBy(playerUuid)) { + return; + } + + EntityPlayerMP player = server.getPlayerList().get(playerUuid); + + if (player == null) { + return; + } + + meterGroup.addMember(playerUuid); + + ITextComponent message = new TextComponentString("") + .appendSibling(new TextComponentString(String.format("You have been invited to meter group \'%s\' - click ", meterGroup.getName()))) + .appendSibling(new TextComponentString("[here]").setStyle(new Style() + .setColor(TextFormatting.GREEN) + .setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new TextComponentString(String.format("Subscribe to meter group \'%s\'", meterGroup.getName())))) + .setClickEvent( + new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/metergroup subscribe %s", meterGroup.getName()))) + )).appendSibling(new TextComponentString(" to subscribe to it.")); + server.sendMessage(player, message, false); + } + + public void removeMemberFromMeterGroup(ServerMeterGroup meterGroup, UUID playerUuid) { + if (!meterGroup.hasMember(playerUuid)) { + return; + } + + meterGroup.removeMember(playerUuid); + + if (meterGroup.isPrivate()) { + EntityPlayerMP player = server.getPlayerList().get(playerUuid); + + if (player != null && meterGroup.hasSubscriber(playerUuid)) { + unsubscribeFromMeterGroup(meterGroup, player); + + ITextComponent message = new TextComponentString(String.format("The owner of meter group \'%s\' has removed you as a member!", meterGroup.getName())); + server.sendMessage(player, message, false); + } + } + } + + public void refreshMeterGroup(EntityPlayerMP player) { + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + refreshMeterGroup(meterGroup, player); + } + } + + private void refreshMeterGroup(ServerMeterGroup meterGroup, EntityPlayerMP player) { + MeterGroupRefreshPacket packet = new MeterGroupRefreshPacket(meterGroup); + server.getPlayerList().send(packet, player); + } + + public void teleportToMeter(EntityPlayerMP player, long id) { + if (!options.meter.allow_teleports) { + ITextComponent message = new TextComponentString("This server does not allow meter teleporting!"); + server.sendMessage(player, message, false); + + return; + } + + ServerMeterGroup meterGroup = getSubscription(player); + + if (meterGroup != null) { + Meter meter = meterGroup.getMeter(id); + + if (meter != null) { + DimPos pos = meter.getPos(); + WorldServer newWorld = server.getWorld(pos); + + if (newWorld != null) { + BlockPos blockPos = pos.getBlockPos(); + + double newX = blockPos.getX() + 0.5D; + double newY = blockPos.getY(); + double newZ = blockPos.getZ() + 0.5D; + float newYaw = player.rotationYaw; + float newPitch = player.rotationPitch; + + player.changeDimension(newWorld.provider.getDimensionType().getId()); + player.connection.setPlayerLocation(newX, newY, newZ, newYaw, newPitch); + + ITextComponent text = new TextComponentString(String.format("Teleported to meter \"%s\"", meter.getName())); + server.sendMessage(player, text, false); + } + } + } + } + + public void onBlockChange(World world, BlockPos pos, IBlockState oldState, IBlockState newState) { + Block oldBlock = oldState.getBlock(); + Block newBlock = newState.getBlock(); + + if (oldBlock == newBlock && newBlock.rsmm$isPowerSource() && ((PowerSource)newBlock).rsmm$logPowerChangeOnStateChange()) { + logPowerChange(world, pos, oldState, newState); + } + + boolean wasMeterable = oldBlock.rsmm$isMeterable(); + boolean isMeterable = newBlock.rsmm$isMeterable(); + + if (wasMeterable || isMeterable) { + logActive(world, pos, newState); + } + } + + public void logPowered(World world, BlockPos pos, boolean powered) { + tryLogEvent(world, pos, EventType.POWERED, powered ? 1 : 0, (meterGroup, meter, event) -> meter.setPowered(powered)); + } + + public void logPowered(World world, BlockPos pos, IBlockState state) { + tryLogEvent(world, pos, EventType.POWERED, () -> { + return state.getBlock().rsmm$isPowered(world, pos, state) ? 1 : 0; + }, (meterGroup, meter, event) -> { + return meter.setPowered(event.getMetadata() != 0); + }); + } + + public void logActive(World world, BlockPos pos, boolean active) { + tryLogEvent(world, pos, EventType.ACTIVE, active ? 1 : 0, (meterGroup, meter, event) -> meter.setActive(active)); + } + + public void logActive(World world, BlockPos pos, IBlockState state) { + tryLogEvent(world, pos, EventType.ACTIVE, () -> { + Block block = state.getBlock(); + return block.rsmm$isMeterable() && ((Meterable)block).rsmm$isActive(world, pos, state) ? 1 : 0; + }, (meterGroup, meter, event) -> meter.setActive(event.getMetadata() != 0)); + } + + public void logMoved(World world, BlockPos blockPos, EnumFacing dir) { + tryLogEvent(world, blockPos, EventType.MOVED, dir.getIndex()); + } + + public void moveMeters(World world, BlockPos blockPos, EnumFacing dir) { + DimPos pos = new DimPos(world, blockPos); + + for (ServerMeterGroup meterGroup : activeMeterGroups) { + meterGroup.tryMoveMeter(pos, dir); + } + } + + public void logPowerChange(World world, BlockPos pos, int oldPower, int newPower) { + if (oldPower != newPower) { + tryLogEvent(world, pos, EventType.POWER_CHANGE, (oldPower << 8) | newPower); + } + } + + public void logPowerChange(World world, BlockPos pos, IBlockState oldState, IBlockState newState) { + tryLogEvent(world, pos, EventType.POWER_CHANGE, () -> { + PowerSource block = (PowerSource)newState.getBlock(); + int oldPower = block.rsmm$getPowerLevel(world, pos, oldState); + int newPower = block.rsmm$getPowerLevel(world, pos, newState); + + return (oldPower << 8) | newPower; + }, (meterGroup, meter, event) -> { + int data = event.getMetadata(); + int oldPower = (data >> 8) & 0xFF; + int newPower = data & 0xFF; + + return oldPower != newPower; + }); + } + + public void logRandomTick(World world, BlockPos pos) { + tryLogEvent(world, pos, EventType.RANDOM_TICK); + } + + public void logScheduledTick(World world, BlockPos pos, int priority, boolean scheduling) { + tryLogEvent(world, pos, EventType.SCHEDULED_TICK, (scheduling ? (1 << 30) : 0) | (priority + 3)); + } + + public void logBlockEvent(World world, BlockPos pos, int type, int depth, boolean queueing) { + tryLogEvent(world, pos, EventType.BLOCK_EVENT, (queueing ? (1 << 30) : 0) | (depth << 4) | type); + } + + public void logEntityTick(World world, Entity entity) { + tryLogEvent(world, entity.getPosition(), EventType.ENTITY_TICK); + } + + public void logBlockEntityTick(World world, TileEntity blockEntity) { + tryLogEvent(world, blockEntity.getPos(), EventType.BLOCK_ENTITY_TICK); + } + + public void logBlockUpdate(World world, BlockPos pos) { + tryLogEvent(world, pos, EventType.BLOCK_UPDATE); + } + + public void logComparatorUpdate(World world, BlockPos pos) { + tryLogEvent(world, pos, EventType.COMPARATOR_UPDATE); + } + + public void logShapeUpdate(World world, BlockPos pos, EnumFacing dir) { + tryLogEvent(world, pos, EventType.SHAPE_UPDATE, dir.getIndex()); + } + + public void logObserverUpdate(World world, BlockPos pos) { + tryLogEvent(world, pos, EventType.OBSERVER_UPDATE); + } + + public void logInteractBlock(World world, BlockPos pos) { + tryLogEvent(world, pos, EventType.INTERACT_BLOCK); + } + + private void tryLogEvent(World world, BlockPos pos, EventType type) { + tryLogEvent(world, pos, type, 0); + } + + private void tryLogEvent(World world, BlockPos pos, EventType type, int data) { + tryLogEvent(world, pos, type, data, (meterGroup, meter, event) -> true); + } + + private void tryLogEvent(World world, BlockPos pos, EventType type, int data, MeterEventPredicate predicate) { + tryLogEvent(world, pos, type, Suppliers.memoize(() -> data), predicate); + } + + private void tryLogEvent(World world, BlockPos pos, EventType type, Supplier data, MeterEventPredicate predicate) { + if (options.hasEventType(type)) { + for (ServerMeterGroup meterGroup : activeMeterGroups) { + meterGroup.tryLogEvent(world, pos, type, data, predicate); + } + } + } + + static { + + NUMBER_FORMAT.setGroupingUsed(false); + + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/MultimeterServer.java b/carpetmodSrc/redstone/multimeter/server/MultimeterServer.java new file mode 100644 index 00000000..d71e2502 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/MultimeterServer.java @@ -0,0 +1,215 @@ +package redstone.multimeter.server; + +import java.io.File; +import java.util.UUID; + +import carpet.helpers.TickSpeed; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.DimensionType; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import redstone.multimeter.RedstoneMultimeter; +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.TickPhase; +import redstone.multimeter.common.TickPhaseTree; +import redstone.multimeter.common.TickTask; +import redstone.multimeter.common.network.packets.HandshakePacket; +import redstone.multimeter.common.network.packets.TickTimePacket; +import redstone.multimeter.common.network.packets.TickPhaseTreePacket; + +public class MultimeterServer { + + private final MinecraftServer server; + private final ServerPacketHandler packetHandler; + private final PlayerList playerList; + private final Multimeter multimeter; + private final TickPhaseTree tickPhaseTree; + + private boolean loaded; + private TickPhase tickPhase; + + public MultimeterServer(MinecraftServer server) { + this.server = server; + this.packetHandler = new ServerPacketHandler(this); + this.playerList = new PlayerList(this); + this.multimeter = new Multimeter(this); + this.tickPhaseTree = new TickPhaseTree(); + + this.tickPhase = TickPhase.UNKNOWN; + } + + public MinecraftServer getMinecraftServer() { + return server; + } + + public ServerPacketHandler getPacketHandler() { + return packetHandler; + } + + public Multimeter getMultimeter() { + return multimeter; + } + + public TickPhaseTree getTickPhaseTree() { + return tickPhaseTree; + } + + public long getTicks() { + return server.getTickCounter(); + } + + public boolean isDedicated() { + return server.isDedicatedServer(); + } + + public File getConfigDirectory() { + return new File(server.getDataDirectory(), RedstoneMultimeter.CONFIG_PATH); + } + + public TickPhase getTickPhase() { + return tickPhase; + } + + public void worldLoaded() { + loaded = true; + } + + public void startTickTask(TickTask task, String... args) { + tickPhase = tickPhase.startTask(task); + if (tickPhaseTree.isBuilding()) { + tickPhaseTree.startTask(task, args); + } + } + + public void endTickTask() { + tickPhase = tickPhase.endTask(); + if (tickPhaseTree.isBuilding()) { + tickPhaseTree.endTask(); + } + } + + public void swapTickTask(TickTask task, String... args) { + tickPhase = tickPhase.swapTask(task); + if (tickPhaseTree.isBuilding()) { + tickPhaseTree.swapTask(task, args); + } + } + + public TickTask getCurrentTickTask() { + return tickPhase.peekTask(); + } + + public boolean isPaused() { + return false; // integrated servers only + } + + public boolean isPausedOrFrozen() { + return isPaused() || !TickSpeed.process_entities; + } + + public void tickStart() { + boolean paused = isPaused(); + + if (!paused) { + if (shouldBuildTickPhaseTree()) { + tickPhaseTree.start(); + } + + playerList.tick(); + } + + tickPhase = TickPhase.UNKNOWN; + multimeter.tickStart(paused); + } + + private boolean shouldBuildTickPhaseTree() { + return loaded && !tickPhaseTree.isComplete() && !tickPhaseTree.isBuilding() && !isPausedOrFrozen() && !playerList.get().isEmpty(); + } + + public void tickEnd() { + boolean paused = isPaused(); + + if (tickPhaseTree.isBuilding()) { + tickPhaseTree.end(); + } + + tickPhase = TickPhase.UNKNOWN; + multimeter.tickEnd(paused); + } + + public void tickTime(World world) { + TickTimePacket packet = new TickTimePacket(world.getWorldTime()); + playerList.send(packet, world.provider.getDimensionType()); + } + + public void onHandshake(EntityPlayerMP player, String modVersion) { + if (!playerList.has(player.getUniqueID())) { + playerList.add(player); + + HandshakePacket packet = new HandshakePacket(); + playerList.send(packet, player); + } + } + + public void onPlayerJoin(EntityPlayerMP player) { + multimeter.onPlayerJoin(player); + } + + public void onPlayerLeave(EntityPlayerMP player) { + multimeter.onPlayerLeave(player); + } + + public void refreshTickPhaseTree(EntityPlayerMP player) { + if (tickPhaseTree.isComplete()) { + TickPhaseTreePacket packet = new TickPhaseTreePacket(tickPhaseTree.toNbt()); + playerList.send(packet, player); + } + } + + public void rebuildTickPhaseTree(EntityPlayerMP player) { + if (tickPhaseTree.isComplete()) { + tickPhaseTree.reset(); + } + } + + public WorldServer[] getWorlds() { + return server.worlds; + } + + public WorldServer getWorld(String key) { + return server.getWorld(DimensionType.byName(key).getId()); + } + + public WorldServer getWorld(DimPos pos) { + return getWorld(pos.getDimension()); + } + + public IBlockState getIBlockState(DimPos pos) { + World world = getWorld(pos); + + if (world == null) { + return null; + } + + return world.getBlockState(pos.getBlockPos()); + } + + public PlayerList getPlayerList() { + return playerList; + } + + public boolean isMultimeterClient(UUID uuid) { + return playerList.has(uuid); + } + + public boolean isMultimeterClient(EntityPlayerMP player) { + return playerList.has(player.getUniqueID()); + } + + public void sendMessage(EntityPlayerMP player, ITextComponent message, boolean actionBar) { + player.sendStatusMessage(message, actionBar); + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/PlayerList.java b/carpetmodSrc/redstone/multimeter/server/PlayerList.java new file mode 100644 index 00000000..f32ba9c7 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/PlayerList.java @@ -0,0 +1,138 @@ +package redstone.multimeter.server; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.Packet; +import net.minecraft.world.DimensionType; + +import redstone.multimeter.common.network.RSMMPacket; +import redstone.multimeter.server.meter.ServerMeterGroup; + +public class PlayerList { + + private final MultimeterServer server; + + private final Map playersByUuid; + private final Map playersByName; + private final Map nameCache; + + public PlayerList(MultimeterServer server) { + this.server = server; + + this.playersByUuid = new HashMap<>(); + this.playersByName = new HashMap<>(); + this.nameCache = new HashMap<>(); + } + + public MultimeterServer getServer() { + return server; + } + + public void tick() { + if (server.getTicks() % 72000 == 0) { + cleanNameCache(); + } + } + + private void cleanNameCache() { + Collection meterGroups = server.getMultimeter().getMeterGroups(); + + nameCache.keySet().removeIf(uuid -> { + for (ServerMeterGroup meterGroup : meterGroups) { + if (meterGroup.hasMember(uuid)) { + return false; + } + } + + return true; + }); + } + + public void add(EntityPlayerMP player) { + if (!has(player.getUniqueID())) { + playersByUuid.put(player.getUniqueID(), player); + playersByName.put(player.getName(), player); + nameCache.remove(player.getUniqueID()); + + server.onPlayerJoin(player); + } + } + + public void remove(EntityPlayerMP player) { + if (has(player.getUniqueID())) { + playersByUuid.remove(player.getUniqueID()); + playersByName.remove(player.getName()); + nameCache.put(player.getUniqueID(), player.getName()); + + server.onPlayerLeave(player); + } + } + + public void respawn(EntityPlayerMP player) { + if (has(player.getUniqueID())) { + playersByUuid.put(player.getUniqueID(), player); + playersByName.put(player.getName(), player); + } + } + + public Collection get() { + return playersByUuid.values(); + } + + public EntityPlayerMP get(UUID uuid) { + return playersByUuid.get(uuid); + } + + public EntityPlayerMP get(String name) { + return playersByName.get(name); + } + + public boolean has(UUID uuid) { + return playersByUuid.containsKey(uuid); + } + + public boolean has(String name) { + return playersByName.containsKey(name); + } + + public String getName(UUID uuid) { + EntityPlayerMP player = get(uuid); + return player == null ? nameCache.get(uuid) : player.getName(); + } + + public void send(RSMMPacket packet) { + send(packet, player -> true); + } + + public void send(RSMMPacket packet, ServerMeterGroup meterGroup) { + send(packet, player -> meterGroup.hasSubscriber(player)); + } + + public void send(RSMMPacket packet, DimensionType dimension) { + send(packet, player -> player.world.provider.getDimensionType() == dimension); + } + + public void send(RSMMPacket packet, Predicate predicate) { + Packet mcPacket = server.getPacketHandler().encode(packet); + + for (EntityPlayerMP player : playersByUuid.values()) { + if (predicate.test(player)) { + player.connection.sendPacket(mcPacket); + } + } + } + + public void send(RSMMPacket packet, EntityPlayerMP player) { + Packet mcPacket = server.getPacketHandler().encode(packet); + player.connection.sendPacket(mcPacket); + } + + public void updatePermissions(EntityPlayerMP player) { + server.getMinecraftServer().getPlayerList().updatePermissionLevel(player); + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/ServerPacketHandler.java b/carpetmodSrc/redstone/multimeter/server/ServerPacketHandler.java new file mode 100644 index 00000000..ab809439 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/ServerPacketHandler.java @@ -0,0 +1,30 @@ +package redstone.multimeter.server; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.SPacketCustomPayload; + +import redstone.multimeter.common.network.PacketHandler; + +public class ServerPacketHandler extends PacketHandler { + + private final MultimeterServer server; + + public ServerPacketHandler(MultimeterServer server) { + this.server = server; + } + + @Override + protected Packet toCustomPayload(String channel, PacketBuffer data) { + return new SPacketCustomPayload(channel, data); + } + + public void handlePacket(PacketBuffer data, EntityPlayerMP player) { + try { + decode(data).handle(server, player); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterGroup.java b/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterGroup.java new file mode 100644 index 00000000..1f5a85c6 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterGroup.java @@ -0,0 +1,298 @@ +package redstone.multimeter.server.meter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.Meter; +import redstone.multimeter.common.meter.MeterGroup; +import redstone.multimeter.common.meter.MeterProperties; +import redstone.multimeter.common.meter.MeterProperties.MutableMeterProperties; +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.common.meter.event.MeterEvent; +import redstone.multimeter.common.network.packets.MeterUpdatesPacket; +import redstone.multimeter.server.Multimeter; +import redstone.multimeter.server.meter.event.MeterEventPredicate; +import redstone.multimeter.server.meter.log.ServerLogManager; + +public class ServerMeterGroup extends MeterGroup { + + private final Multimeter multimeter; + private final ServerLogManager logManager; + + private final UUID owner; + private final Set members; + private final Set subscribers; + + private final List removedMeters; + private final Map meterUpdates; + private boolean meterIndicesChanged; + + private boolean isPrivate; + private boolean idle; + private long idleTime; + + public ServerMeterGroup(Multimeter multimeter, String name, EntityPlayerMP owner) { + super(name); + + this.multimeter = multimeter; + this.logManager = new ServerLogManager(this); + + this.owner = owner.getUniqueID(); + this.members = new HashSet<>(); + this.subscribers = new HashSet<>(); + + this.removedMeters = new ArrayList<>(); + this.meterUpdates = new LinkedHashMap<>(); + + this.isPrivate = false; + this.idle = true; + this.idleTime = 0L; + } + + @Override + public void clear() { + super.clear(); + + removedMeters.clear(); + meterUpdates.clear(); + } + + @Override + protected void moveMeter(Meter meter, DimPos newPos) { + if (hasMeterAt(newPos)) { + return; + } + + World world = multimeter.getServer().getWorld(newPos); + + if (world == null) { + return; + } + + super.moveMeter(meter, newPos); + } + + @Override + protected void meterAdded(Meter meter) { + meterUpdates.putIfAbsent(meter.getId(), meter.getProperties()); + } + + @Override + protected void meterRemoved(Meter meter) { + removedMeters.add(meter.getId()); + meterUpdates.remove(meter.getId()); + } + + @Override + protected void meterUpdated(Meter meter) { + meterUpdates.putIfAbsent(meter.getId(), meter.getProperties()); + } + + @Override + protected void indexChanged(Meter meter) { + meterIndicesChanged = true; + } + + @Override + public ServerLogManager getLogManager() { + return logManager; + } + + public Multimeter getMultimeter() { + return multimeter; + } + + public boolean addMeter(MutableMeterProperties properties) { + return addMeter(new Meter(properties)); + } + + public boolean removeMeter(long id) { + return hasMeter(id) && removeMeter(getMeter(id)); + } + + public boolean updateMeter(long id, MeterProperties newProperties) { + return hasMeter(id) && updateMeter(getMeter(id), newProperties); + } + + public void tryMoveMeter(DimPos pos, EnumFacing dir) { + if (!hasMeterAt(pos)) { + return; + } + + Meter meter = getMeterAt(pos); + + if (!meter.isMovable()) { + return; + } + + moveMeter(meter, pos.offset(dir)); + } + + public boolean setMeterIndex(long id, int index) { + return hasMeter(id) && setIndex(getMeter(id), index); + } + + public boolean isPastMeterLimit() { + int limit = multimeter.options.meter_group.meter_limit; + return limit >= 0 && getMeters().size() >= limit; + } + + public UUID getOwner() { + return owner; + } + + public boolean isOwnedBy(EntityPlayerMP player) { + return isOwnedBy(player.getUniqueID()); + } + + public boolean isOwnedBy(UUID playerUuid) { + return owner.equals(playerUuid); + } + + public boolean hasMembers() { + return !members.isEmpty(); + } + + public Collection getMembers() { + return Collections.unmodifiableCollection(members); + } + + public boolean hasMember(EntityPlayerMP player) { + return hasMember(player.getUniqueID()); + } + + public boolean hasMember(UUID playerUuid) { + return members.contains(playerUuid); + } + + public void addMember(UUID playerUuid) { + members.add(playerUuid); + } + + public void removeMember(UUID playerUuid) { + members.remove(playerUuid); + } + + public void clearMembers() { + members.clear(); + } + + public boolean hasSubscribers() { + return !subscribers.isEmpty(); + } + + public Collection getSubscribers() { + return Collections.unmodifiableCollection(subscribers); + } + + public boolean hasSubscriber(EntityPlayerMP player) { + return hasSubscriber(player.getUniqueID()); + } + + public boolean hasSubscriber(UUID playerUuid) { + return subscribers.contains(playerUuid); + } + + public void addSubscriber(UUID playerUuid) { + subscribers.add(playerUuid); + } + + public void removeSubscriber(UUID playerUuid) { + subscribers.remove(playerUuid); + } + + public boolean isPrivate() { + return isPrivate; + } + + public void setPrivate(boolean isPrivate) { + this.isPrivate = isPrivate; + + if (isPrivate) { + for (UUID playerUuid : subscribers) { + if (playerUuid != owner) { + addMember(playerUuid); + } + } + } + } + + public boolean isIdle() { + return idle; + } + + public long getIdleTime() { + return idleTime; + } + + public boolean updateIdleState() { + boolean wasIdle = idle; + idle = !hasSubscribers(); + + if (wasIdle && !idle) { + idleTime = 0L; + } + + return wasIdle != idle; + } + + public boolean isPastIdleTimeLimit() { + return idle && multimeter.options.meter_group.max_idle_time >= 0 && idleTime > multimeter.options.meter_group.max_idle_time; + } + + public void tick() { + if (idle) { + idleTime++; + } + } + + public void broadcastUpdates() { + if (removedMeters.isEmpty() && meterUpdates.isEmpty() && !meterIndicesChanged) { + return; + } + + List meters = new LinkedList<>(); + + if (meterIndicesChanged) { + for (Meter meter : getMeters()) { + meters.add(meter.getId()); + } + } + + MeterUpdatesPacket packet = new MeterUpdatesPacket(removedMeters, meterUpdates, meters); + multimeter.getServer().getPlayerList().send(packet, this); + + removedMeters.clear(); + meterUpdates.clear(); + + meterIndicesChanged = false; + } + + public void tryLogEvent(World world, BlockPos blockPos, EventType type, Supplier data, MeterEventPredicate predicate) { + DimPos pos = new DimPos(world, blockPos); + Meter meter = getMeterAt(pos); + + if (meter != null && meter.isMetering(type)) { + MeterEvent event = new MeterEvent(type, data.get()); + + if (predicate.test(this, meter, event)) { + logManager.logEvent(world, meter, event); + } + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterPropertiesManager.java b/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterPropertiesManager.java new file mode 100644 index 00000000..863d73a1 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/meter/ServerMeterPropertiesManager.java @@ -0,0 +1,44 @@ +package redstone.multimeter.server.meter; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import redstone.multimeter.common.DimPos; +import redstone.multimeter.common.meter.ColorPicker; +import redstone.multimeter.common.meter.MeterProperties.MutableMeterProperties; +import redstone.multimeter.common.meter.MeterPropertiesManager; +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.server.Multimeter; + +public class ServerMeterPropertiesManager extends MeterPropertiesManager { + + private final Multimeter multimeter; + + public ServerMeterPropertiesManager(Multimeter multimeter) { + this.multimeter = multimeter; + } + + @Override + protected World getWorld(DimPos pos) { + return multimeter.getServer().getWorld(pos); + } + + @Override + protected void postValidation(MutableMeterProperties properties, World world, BlockPos pos) { + // These are the backup values for if the saved defaults + // do not fully populate the meter settings. + + if (properties.getName() == null) { + properties.setName("Meter"); + } + if (properties.getColor() == null) { + properties.setColor(ColorPicker.RANDOM.next()); + } + if (properties.getMovable() == null) { + properties.setMovable(true); + } + if (properties.getEventTypes() == null) { + properties.setEventTypes(EventType.POWERED.flag() | EventType.MOVED.flag()); + } + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventPredicate.java b/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventPredicate.java new file mode 100644 index 00000000..27a9f776 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventPredicate.java @@ -0,0 +1,11 @@ +package redstone.multimeter.server.meter.event; + +import redstone.multimeter.common.meter.Meter; +import redstone.multimeter.common.meter.event.MeterEvent; +import redstone.multimeter.server.meter.ServerMeterGroup; + +public interface MeterEventPredicate { + + public boolean test(ServerMeterGroup meterGroup, Meter meter, MeterEvent event); + +} diff --git a/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventSupplier.java b/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventSupplier.java new file mode 100644 index 00000000..86cc38df --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/meter/event/MeterEventSupplier.java @@ -0,0 +1,31 @@ +package redstone.multimeter.server.meter.event; + +import java.util.function.Supplier; + +import redstone.multimeter.common.meter.event.EventType; +import redstone.multimeter.common.meter.event.MeterEvent; + +public class MeterEventSupplier { + + private final EventType type; + private final Supplier dataSupplier; + + private MeterEvent event; + + public MeterEventSupplier(EventType type, Supplier dataSupplier) { + this.type = type; + this.dataSupplier = dataSupplier; + } + + public EventType type() { + return type; + } + + public MeterEvent get() { + if (event == null) { + event = new MeterEvent(type, dataSupplier.get()); + } + + return event; + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/meter/log/ServerLogManager.java b/carpetmodSrc/redstone/multimeter/server/meter/log/ServerLogManager.java new file mode 100644 index 00000000..8440b14d --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/meter/log/ServerLogManager.java @@ -0,0 +1,112 @@ +package redstone.multimeter.server.meter.log; + +import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2IntMap; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import redstone.multimeter.common.TickPhase; +import redstone.multimeter.common.meter.Meter; +import redstone.multimeter.common.meter.event.MeterEvent; +import redstone.multimeter.common.meter.log.EventLog; +import redstone.multimeter.common.meter.log.LogManager; +import redstone.multimeter.common.network.packets.MeterLogsPacket; +import redstone.multimeter.server.meter.ServerMeterGroup; + +public class ServerLogManager extends LogManager { + + private final ServerMeterGroup meterGroup; + private final Long2IntMap subticks; + + private long cutoff; + private int unsentLogs; + + public ServerLogManager(ServerMeterGroup meterGroup) { + this.meterGroup = meterGroup; + this.subticks = new Long2IntLinkedOpenHashMap(); + + this.cutoff = -1L; + } + + @Override + protected ServerMeterGroup getMeterGroup() { + return meterGroup; + } + + @Override + public void clearLogs() { + super.clearLogs(); + + subticks.clear(); + + cutoff = -1L; + unsentLogs = 0; + } + + public void tick() { + cutoff = Long.MAX_VALUE; + + for (World world : meterGroup.getMultimeter().getServer().getWorlds()) { + long gameTime = world.getWorldTime(); + + if (gameTime < cutoff) { + cutoff = gameTime; + } + } + + subticks.long2IntEntrySet().removeIf(e -> e.getLongKey() < cutoff); + } + + private int nextSubtick(long tick) { + return subticks.compute(tick, (key, value) -> { + return value == null ? 0 : ++value; + }); + } + + public void logEvent(World world, Meter meter, MeterEvent event) { + long tick = world.getWorldTime(); + int subtick = nextSubtick(tick); + TickPhase phase = meterGroup.getMultimeter().getServer().getTickPhase(); + + meter.getLogs().add(new EventLog(tick, subtick, phase, event)); + + unsentLogs++; + } + + public void broadcastLogs() { + if (unsentLogs == 0) { + return; + } + + NBTTagList list = new NBTTagList(); + + for (Meter meter : meterGroup.getMeters()) { + if (meter.getLogs().isEmpty()) { + continue; + } + + long id = meter.getId(); + NBTTagCompound logs = meter.getLogs().toNbt(); + + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setLong("id", id); + nbt.setTag("logs", logs); + nbt.setBoolean("powered", meter.isPowered()); + nbt.setBoolean("active", meter.isActive()); + list.appendTag(nbt); + + meter.getLogs().clear(); + } + + if (list.isEmpty()) { + return; + } + + MeterLogsPacket packet = new MeterLogsPacket(list); + meterGroup.getMultimeter().getServer().getPlayerList().send(packet, meterGroup); + + unsentLogs = 0; + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/option/Options.java b/carpetmodSrc/redstone/multimeter/server/option/Options.java new file mode 100644 index 00000000..d07bf08e --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/option/Options.java @@ -0,0 +1,37 @@ +package redstone.multimeter.server.option; + +import redstone.multimeter.common.meter.event.EventType; + +public class Options { + + public Meter meter = new Meter(); + public MeterGroup meter_group = new MeterGroup(); + public EventTypes event_types = new EventTypes(); + + public class Meter { + + public boolean allow_teleports = true; + + } + + public class MeterGroup { + + public int meter_limit = -1; + public int max_idle_time = 72000; + + } + + public class EventTypes { + + public String allowed = "all"; // "all", "blacklist", "whitelist" + public String[] blacklist = { }; + public String[] whitelist = { }; + + } + + protected transient int enabledEventTypes = ~0; + + public boolean hasEventType(EventType type) { + return (enabledEventTypes & type.flag()) != 0; + } +} diff --git a/carpetmodSrc/redstone/multimeter/server/option/OptionsManager.java b/carpetmodSrc/redstone/multimeter/server/option/OptionsManager.java new file mode 100644 index 00000000..2bab7b78 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/server/option/OptionsManager.java @@ -0,0 +1,75 @@ +package redstone.multimeter.server.option; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import redstone.multimeter.common.meter.event.EventType; + +public class OptionsManager { + + private static final String FILE_NAME = "options.json"; + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + public static Options load(File dir) { + File file = new File(dir, FILE_NAME); + return validate(file.exists() ? read(file) : write(file)); + } + + private static Options read(File file) { + try (FileReader fr = new FileReader(file)) { + return GSON.fromJson(fr, Options.class); + } catch (IOException e) { + return new Options(); + } + } + + private static Options write(File file) { + Options options = new Options(); + + try (FileWriter fw = new FileWriter(file)) { + fw.write(GSON.toJson(options)); + } catch (IOException e) { + + } + + return options; + } + + private static Options validate(Options options) { + switch (options.event_types.allowed) { + case "all": + break; + case "blacklist": + for (String name : options.event_types.blacklist) { + EventType type = EventType.byName(name); + + if (type != null) { + options.enabledEventTypes &= ~type.flag(); + } + } + + break; + case "whitelist": + options.enabledEventTypes = 0; + + for (String name : options.event_types.whitelist) { + EventType type = EventType.byName(name); + + if (type != null) { + options.enabledEventTypes |= type.flag(); + } + } + + break; + default: + throw new IllegalStateException("unknown event types filter " + options.event_types.allowed); + } + + return options; + } +} diff --git a/carpetmodSrc/redstone/multimeter/util/AxisUtils.java b/carpetmodSrc/redstone/multimeter/util/AxisUtils.java new file mode 100644 index 00000000..322a73ac --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/util/AxisUtils.java @@ -0,0 +1,19 @@ +package redstone.multimeter.util; + +import net.minecraft.util.EnumFacing.Axis; + +public class AxisUtils { + + public static int choose(Axis axis, int x, int y, int z) { + switch (axis) { + case X: + return x; + case Y: + return y; + case Z: + return z; + } + + return 0; + } +} diff --git a/carpetmodSrc/redstone/multimeter/util/ColorUtils.java b/carpetmodSrc/redstone/multimeter/util/ColorUtils.java new file mode 100644 index 00000000..2afa7935 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/util/ColorUtils.java @@ -0,0 +1,100 @@ +package redstone.multimeter.util; + +public class ColorUtils { + + public static int getAlpha(int argb) { + return (argb >> 24) & 0xFF; + } + + public static int getRed(int argb) { + return (argb >> 16) & 0xFF; + } + + public static int getGreen(int argb) { + return (argb >> 8) & 0xFF; + } + + public static int getBlue(int argb) { + return argb & 0xFF; + } + + public static int fromAlpha(int alpha) { + return (alpha & 0xFF) << 24; + } + + public static int fromRed(int red) { + return (red & 0xFF) << 16; + } + + public static int fromGreen(int green) { + return (green & 0xFF) << 8; + } + + public static int fromBlue(int blue) { + return blue & 0xFF; + } + + public static int setAlpha(int color, int alpha) { + return color & (~(0xFF << 24)) | (alpha << 24); + } + + public static int setRed(int color, int red) { + return color & (~(0xFF << 16)) | (red << 16); + } + + public static int setGreen(int color, int green) { + return color & (~(0xFF << 8)) | (green << 8); + } + + public static int setBlue(int color, int blue) { + return color & ~0xFF | blue; + } + + public static int fromRGB(int red, int green, int blue) { + return fromRed(red) | fromGreen(green) | fromBlue(blue); + } + + public static int fromARGB(int alpha, int red, int green, int blue) { + return fromARGB(alpha, fromRGB(red, green, blue)); + } + + public static int fromARGB(int alpha, int rgb) { + return fromAlpha(alpha) | rgb; + } + + public static int fromRGBString(String string) { + if (string.length() > 6) { + throw new NumberFormatException("Too many characters!"); + } + + return Integer.valueOf(string, 16); + } + + public static int fromARGBString(String string) { + if (string.length() > 8) { + throw new NumberFormatException("Too many characters!"); + } + + return Integer.valueOf(string, 16); + } + + public static String toRGBString(int color) { + String hex = Integer.toHexString(color & 0xFFFFFF); + + while (hex.length() < 6) { + hex = "0" + hex; + } + + return hex.toUpperCase(); + } + + public static String toARGBString(int color) { + String hex = Integer.toHexString(color & 0xFFFFFFFF); + + while (hex.length() < 8) { + hex = "0" + hex; + } + + return hex.toUpperCase(); + } +} diff --git a/carpetmodSrc/redstone/multimeter/util/IdentifierUtils.java b/carpetmodSrc/redstone/multimeter/util/IdentifierUtils.java new file mode 100644 index 00000000..01095e1a --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/util/IdentifierUtils.java @@ -0,0 +1,26 @@ +package redstone.multimeter.util; + +import net.minecraft.util.ResourceLocation; + +public class IdentifierUtils { + + public static boolean isValid(ResourceLocation id) { + return isValid(id.getNamespace(), id.getPath()); + } + + public static boolean isValid(String namespace, String path) { + return isValidNamespace(namespace) && isValidPath(path); + } + + public static boolean isValidNamespace(String namespace) { + return namespace.chars().allMatch(chr -> { + return chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9'); + }); + } + + public static boolean isValidPath(String namespace) { + return namespace.chars().allMatch(chr -> { + return chr == '-' || chr == '.' || chr == '/' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9'); + }); + } +} diff --git a/carpetmodSrc/redstone/multimeter/util/ListUtils.java b/carpetmodSrc/redstone/multimeter/util/ListUtils.java new file mode 100644 index 00000000..8639ec59 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/util/ListUtils.java @@ -0,0 +1,29 @@ +package redstone.multimeter.util; + +import java.util.List; +import java.util.function.Predicate; + +public class ListUtils { + + public static int binarySearch(List list, Predicate tooLow) { + return binarySearch(list, 0, list.size() - 1, tooLow); + } + + public static int binarySearch(List list, int low, int high, Predicate tooLow) { + if (list.isEmpty()) { + return -1; + } + + while (high > low) { + int mid = (low + high) / 2; + + if (tooLow.test(list.get(mid))) { + low = mid + 1; + } else { + high = mid; + } + } + + return low; + } +} diff --git a/carpetmodSrc/redstone/multimeter/util/NbtUtils.java b/carpetmodSrc/redstone/multimeter/util/NbtUtils.java new file mode 100644 index 00000000..1dec17b4 --- /dev/null +++ b/carpetmodSrc/redstone/multimeter/util/NbtUtils.java @@ -0,0 +1,24 @@ +package redstone.multimeter.util; + +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagByte; + +public class NbtUtils { + + public static final byte TYPE_NULL = 0; + public static final byte TYPE_BYTE = 1; + public static final byte TYPE_SHORT = 2; + public static final byte TYPE_INT = 3; + public static final byte TYPE_LONG = 4; + public static final byte TYPE_FLOAT = 5; + public static final byte TYPE_DOUBLE = 6; + public static final byte TYPE_BYTE_ARRAY = 7; + public static final byte TYPE_STRING = 8; + public static final byte TYPE_LIST = 9; + public static final byte TYPE_COMPOUND = 10; + public static final byte TYPE_INT_ARRAY = 11; + public static final byte TYPE_LONG_ARRAY = 12; + + public static final NBTBase NULL = new NBTTagByte((byte)0); + +} diff --git a/docs/usage/install.rst b/docs/usage/install.rst index ad148c2f..ae195133 100644 --- a/docs/usage/install.rst +++ b/docs/usage/install.rst @@ -35,7 +35,7 @@ First, create a clean directory (folder). For this tutorial, we call it ``carpet``. There, download the vanilla jar and Carpet patch. * `Download the 1.12.2 vanilla server jar - `_. + `_. * `Download the latest Carpet patch `_. diff --git a/jsons/1.12.2-dev.json b/jsons/1.12.2-dev.json index d0cea265..c0c15a38 100644 --- a/jsons/1.12.2-dev.json +++ b/jsons/1.12.2-dev.json @@ -3,18 +3,18 @@ "libraries": [ { "name": "com.sk89q.worldedit:worldedit-core:6.1", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" }, { "name": "com.sk89q:jchronic:0.2.4a", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" }, { "name": "com.thoughtworks.paranamer:paranamer:2.6" }, { "name": "com.sk89q.lib:jlibnoise:1.0.0", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" } ] } diff --git a/jsons/1.12.2-rel.json b/jsons/1.12.2-rel.json index d0cea265..c0c15a38 100644 --- a/jsons/1.12.2-rel.json +++ b/jsons/1.12.2-rel.json @@ -3,18 +3,18 @@ "libraries": [ { "name": "com.sk89q.worldedit:worldedit-core:6.1", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" }, { "name": "com.sk89q:jchronic:0.2.4a", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" }, { "name": "com.thoughtworks.paranamer:paranamer:2.6" }, { "name": "com.sk89q.lib:jlibnoise:1.0.0", - "url": "https://maven.sk89q.com/repo" + "url": "https://maven.enginehub.org/repo" } ] } diff --git a/jsons/1.12.2.json b/jsons/1.12.2.json index dbe4d3f4..fd4c093a 100644 --- a/jsons/1.12.2.json +++ b/jsons/1.12.2.json @@ -1 +1 @@ -{"assetIndex": {"id": "1.12", "sha1": "1584b57c1a0b5e593fad1f5b8f78536ca640547b", "size": 143138, "totalSize": 129336389, "url": "https://launchermeta.mojang.com/v1/packages/1584b57c1a0b5e593fad1f5b8f78536ca640547b/1.12.json"}, "assets": "1.12", "downloads": {"client": {"sha1": "0f275bc1547d01fa5f56ba34bdc87d981ee12daf", "size": 10180113, "url": "https://launcher.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar"}, "server": {"sha1": "886945bfb2b978778c3a0288fd7fab09d315b25f", "size": 30222121, "url": "https://launcher.mojang.com/v1/objects/886945bfb2b978778c3a0288fd7fab09d315b25f/server.jar"}}, "id": "1.12.2", "libraries": [{"downloads": {"artifact": {"path": "com/mojang/patchy/1.1/patchy-1.1.jar", "sha1": "aef610b34a1be37fa851825f12372b78424d8903", "size": 15817, "url": "https://libraries.minecraft.net/com/mojang/patchy/1.1/patchy-1.1.jar"}}, "name": "com.mojang:patchy:1.1"}, {"downloads": {"artifact": {"path": "oshi-project/oshi-core/1.1/oshi-core-1.1.jar", "sha1": "9ddf7b048a8d701be231c0f4f95fd986198fd2d8", "size": 30973, "url": "https://libraries.minecraft.net/oshi-project/oshi-core/1.1/oshi-core-1.1.jar"}}, "name": "oshi-project:oshi-core:1.1"}, {"downloads": {"artifact": {"path": "net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar", "sha1": "cb208278274bf12ebdb56c61bd7407e6f774d65a", "size": 1091208, "url": "https://libraries.minecraft.net/net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar"}}, "name": "net.java.dev.jna:jna:4.4.0"}, {"downloads": {"artifact": {"path": "net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar", "sha1": "e3f70017be8100d3d6923f50b3d2ee17714e9c13", "size": 913436, "url": "https://libraries.minecraft.net/net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar"}}, "name": "net.java.dev.jna:platform:3.4.0"}, {"downloads": {"artifact": {"path": "com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar", "sha1": "63d216a9311cca6be337c1e458e587f99d382b84", "size": 1634692, "url": "https://libraries.minecraft.net/com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar"}}, "name": "com.ibm.icu:icu4j-core-mojang:51.2"}, {"downloads": {"artifact": {"path": "net/sf/jopt-simple/jopt-simple/5.0.3/jopt-simple-5.0.3.jar", "sha1": "cdd846cfc4e0f7eefafc02c0f5dce32b9303aa2a", "size": 78175, "url": "https://libraries.minecraft.net/net/sf/jopt-simple/jopt-simple/5.0.3/jopt-simple-5.0.3.jar"}}, "name": "net.sf.jopt-simple:jopt-simple:5.0.3"}, {"downloads": {"artifact": {"path": "com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar", "sha1": "c73b5636faf089d9f00e8732a829577de25237ee", "size": 103871, "url": "https://libraries.minecraft.net/com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar"}}, "name": "com.paulscode:codecjorbis:20101023"}, {"downloads": {"artifact": {"path": "com/paulscode/codecwav/20101023/codecwav-20101023.jar", "sha1": "12f031cfe88fef5c1dd36c563c0a3a69bd7261da", "size": 5618, "url": "https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar"}}, "name": "com.paulscode:codecwav:20101023"}, {"downloads": {"artifact": {"path": "com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar", "sha1": "5c5e304366f75f9eaa2e8cca546a1fb6109348b3", "size": 21679, "url": "https://libraries.minecraft.net/com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar"}}, "name": "com.paulscode:libraryjavasound:20101123"}, {"downloads": {"artifact": {"path": "com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar", "sha1": "73e80d0794c39665aec3f62eee88ca91676674ef", "size": 18981, "url": "https://libraries.minecraft.net/com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar"}}, "name": "com.paulscode:librarylwjglopenal:20100824"}, {"downloads": {"artifact": {"path": "com/paulscode/soundsystem/20120107/soundsystem-20120107.jar", "sha1": "419c05fe9be71f792b2d76cfc9b67f1ed0fec7f6", "size": 65020, "url": "https://libraries.minecraft.net/com/paulscode/soundsystem/20120107/soundsystem-20120107.jar"}}, "name": "com.paulscode:soundsystem:20120107"}, {"downloads": {"artifact": {"path": "io/netty/netty-all/4.1.9.Final/netty-all-4.1.9.Final.jar", "sha1": "0097860965d6a0a6b98e7f569f3f966727b8db75", "size": 3511093, "url": "https://libraries.minecraft.net/io/netty/netty-all/4.1.9.Final/netty-all-4.1.9.Final.jar"}}, "name": "io.netty:netty-all:4.1.9.Final"}, {"downloads": {"artifact": {"path": "com/google/guava/guava/21.0/guava-21.0.jar", "sha1": "3a3d111be1be1b745edfa7d91678a12d7ed38709", "size": 2521113, "url": "https://libraries.minecraft.net/com/google/guava/guava/21.0/guava-21.0.jar"}}, "name": "com.google.guava:guava:21.0"}, {"downloads": {"artifact": {"path": "org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar", "sha1": "6c6c702c89bfff3cd9e80b04d668c5e190d588c6", "size": 479881, "url": "https://libraries.minecraft.net/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar"}}, "name": "org.apache.commons:commons-lang3:3.5"}, {"downloads": {"artifact": {"path": "commons-io/commons-io/2.5/commons-io-2.5.jar", "sha1": "2852e6e05fbb95076fc091f6d1780f1f8fe35e0f", "size": 208700, "url": "https://libraries.minecraft.net/commons-io/commons-io/2.5/commons-io-2.5.jar"}}, "name": "commons-io:commons-io:2.5"}, {"downloads": {"artifact": {"path": "commons-codec/commons-codec/1.10/commons-codec-1.10.jar", "sha1": "4b95f4897fa13f2cd904aee711aeafc0c5295cd8", "size": 284184, "url": "https://libraries.minecraft.net/commons-codec/commons-codec/1.10/commons-codec-1.10.jar"}}, "name": "commons-codec:commons-codec:1.10"}, {"downloads": {"artifact": {"path": "net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar", "sha1": "39c7796b469a600f72380316f6b1f11db6c2c7c4", "size": 208338, "url": "https://libraries.minecraft.net/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar"}}, "name": "net.java.jinput:jinput:2.0.5"}, {"downloads": {"artifact": {"path": "net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar", "sha1": "e12fe1fda814bd348c1579329c86943d2cd3c6a6", "size": 7508, "url": "https://libraries.minecraft.net/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar"}}, "name": "net.java.jutils:jutils:1.0.0"}, {"downloads": {"artifact": {"path": "com/google/code/gson/gson/2.8.0/gson-2.8.0.jar", "sha1": "c4ba5371a29ac9b2ad6129b1d39ea38750043eff", "size": 231952, "url": "https://libraries.minecraft.net/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar"}}, "name": "com.google.code.gson:gson:2.8.0"}, {"downloads": {"artifact": {"path": "com/mojang/authlib/1.5.25/authlib-1.5.25.jar", "sha1": "9834cdf236c22e84b946bba989e2f94ef5897c3c", "size": 65621, "url": "https://libraries.minecraft.net/com/mojang/authlib/1.5.25/authlib-1.5.25.jar"}}, "name": "com.mojang:authlib:1.5.25"}, {"downloads": {"artifact": {"path": "com/mojang/realms/1.10.22/realms-1.10.22.jar", "sha1": "bd0dccebdf3744c75f1ca20063f16e8f7d5e663f", "size": 7135057, "url": "https://libraries.minecraft.net/com/mojang/realms/1.10.22/realms-1.10.22.jar"}}, "name": "com.mojang:realms:1.10.22"}, {"downloads": {"artifact": {"path": "org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar", "sha1": "a698750c16740fd5b3871425f4cb3bbaa87f529d", "size": 365552, "url": "https://libraries.minecraft.net/org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar"}}, "name": "org.apache.commons:commons-compress:1.8.1"}, {"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar", "sha1": "18f4247ff4572a074444572cee34647c43e7c9c7", "size": 589512, "url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar"}}, "name": "org.apache.httpcomponents:httpclient:4.3.3"}, {"downloads": {"artifact": {"path": "commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar", "sha1": "f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f", "size": 62050, "url": "https://libraries.minecraft.net/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"}}, "name": "commons-logging:commons-logging:1.1.3"}, {"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar", "sha1": "31fbbff1ddbf98f3aa7377c94d33b0447c646b6e", "size": 282269, "url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar"}}, "name": "org.apache.httpcomponents:httpcore:4.3.2"}, {"downloads": {"artifact": {"path": "it/unimi/dsi/fastutil/7.1.0/fastutil-7.1.0.jar", "sha1": "9835253257524c1be7ab50c057aa2d418fb72082", "size": 17655579, "url": "https://libraries.minecraft.net/it/unimi/dsi/fastutil/7.1.0/fastutil-7.1.0.jar"}}, "name": "it.unimi.dsi:fastutil:7.1.0"}, {"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-api/2.8.1/log4j-api-2.8.1.jar", "sha1": "e801d13612e22cad62a3f4f3fe7fdbe6334a8e72", "size": 228859, "url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-api/2.8.1/log4j-api-2.8.1.jar"}}, "name": "org.apache.logging.log4j:log4j-api:2.8.1"}, {"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-core/2.8.1/log4j-core-2.8.1.jar", "sha1": "4ac28ff2f1ddf05dae3043a190451e8c46b73c31", "size": 1402925, "url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-core/2.8.1/log4j-core-2.8.1.jar"}}, "name": "org.apache.logging.log4j:log4j-core:2.8.1"}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar", "sha1": "697517568c68e78ae0b4544145af031c81082dfe", "size": 1047168, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209", "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar", "sha1": "d51a7c040a721d13efdfbd34f8b257b2df882ad0", "size": 173887, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209", "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar", "sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33", "size": 22, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"}, "classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar", "sha1": "931074f46c795d2f7b30ed6395df5715cfd7675b", "size": 578680, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar"}, "natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar", "sha1": "bcab850f8f487c3f4c4dbabde778bb82bd1a40ed", "size": 426822, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"}, "natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar", "sha1": "b84d5102b9dbfabfeb5e43c7e2828d98a7fc80e0", "size": 613748, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}, "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar", "sha1": "7707204c9ffa5d91662de95f0a224e2f721b22af", "size": 1045632, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl:2.9.2-nightly-20140822", "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar", "sha1": "f0e612c840a7639c1f77f68d72a28dae2f0c8490", "size": 173887, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.2-nightly-20140822", "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar", "sha1": "d898a33b5d0a6ef3fed3a4ead506566dce6720a5", "size": 578539, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar"}, "natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar", "sha1": "79f5ce2fea02e77fe47a3c745219167a542121d7", "size": 468116, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar"}, "natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar", "sha1": "78b2a55ce4dc29c6b3ec4df8ca165eba05f9b341", "size": 613680, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.2-nightly-20140822", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}, "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"classifiers": {"natives-linux": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar", "sha1": "7ff832a6eb9ab6a767f1ade2b548092d0fa64795", "size": 10362, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar"}, "natives-osx": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar", "sha1": "53f9c919f34d2ca9de8c51fc4e1e8282029a9232", "size": 12186, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar"}, "natives-windows": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar", "sha1": "385ee093e01f587f30ee1c8a2ee7d408fd732e16", "size": 155179, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "net.java.jinput:jinput-platform:2.0.5", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}}, {"downloads": {"artifact": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar", "sha1": "48fd510879dff266c3815947de66e3d4809f8668", "size": 11055, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar"}}, "name": "com.mojang:text2speech:1.10.3"}, {"downloads": {"artifact": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar", "sha1": "48fd510879dff266c3815947de66e3d4809f8668", "size": 11055, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar"}, "classifiers": {"natives-linux": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-linux.jar", "sha1": "ab7896aec3b3dd272b06194357f2d98f832c0cfc", "size": 7833, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-linux.jar"}, "natives-windows": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-windows.jar", "sha1": "84a4b856389cc4f485275b1f63497a95a857a443", "size": 81217, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-windows.jar"}, "sources": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3-sources.jar", "sha1": "404339fe43d1011ee046a249b0ec7ae9ce04a834", "size": 4632, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3-sources.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "com.mojang:text2speech:1.10.3", "natives": {"linux": "natives-linux", "windows": "natives-windows"}}, {"downloads": {"artifact": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar", "sha1": "6ef160c3133a78de015830860197602ca1c855d3", "size": 40502, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar"}, "classifiers": {"javadoc": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-javadoc.jar", "sha1": "fb0092f22cb4fe8e631452f577b7a238778abf2a", "size": 174060, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-javadoc.jar"}, "natives-osx": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-natives-osx.jar", "sha1": "08befab4894d55875f33c3d300f4f71e6e828f64", "size": 5629, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-natives-osx.jar"}, "sources": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-sources.jar", "sha1": "865837a198189aee737019561ece842827f24278", "size": 43283, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-sources.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "ca.weblite:java-objc-bridge:1.0.0", "natives": {"osx": "natives-osx"}, "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar", "sha1": "6ef160c3133a78de015830860197602ca1c855d3", "size": 40502, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar"}}, "name": "ca.weblite:java-objc-bridge:1.0.0", "rules": [{"action": "allow", "os": {"name": "osx"}}]}], "logging": {"client": {"argument": "-Dlog4j.configurationFile=${path}", "file": {"id": "client-1.12.xml", "sha1": "ef4f57b922df243d0cef096efe808c72db042149", "size": 877, "url": "https://launcher.mojang.com/v1/objects/ef4f57b922df243d0cef096efe808c72db042149/client-1.12.xml"}, "type": "log4j2-xml"}}, "mainClass": "net.minecraft.client.main.Main", "minecraftArguments": "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userType ${user_type} --versionType ${version_type}", "minimumLauncherVersion": 18, "releaseTime": "2017-09-18T08:39:46+00:00", "time": "2017-09-18T08:39:46+00:00", "type": "release"} +{"assetIndex": {"id": "1.12", "sha1": "a21e1ded1a24ea1548dd8db0cf30b6acb02655a9", "size": 143136, "totalSize": 129843781, "url": "https://piston-meta.mojang.com/v1/packages/a21e1ded1a24ea1548dd8db0cf30b6acb02655a9/1.12.json"}, "assets": "1.12", "complianceLevel": 0, "downloads": {"client": {"sha1": "0f275bc1547d01fa5f56ba34bdc87d981ee12daf", "size": 10180113, "url": "https://piston-data.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar"}, "server": {"sha1": "886945bfb2b978778c3a0288fd7fab09d315b25f", "size": 30222121, "url": "https://piston-data.mojang.com/v1/objects/886945bfb2b978778c3a0288fd7fab09d315b25f/server.jar"}}, "id": "1.12.2", "javaVersion": {"component": "jre-legacy", "majorVersion": 8}, "libraries": [{"downloads": {"artifact": {"path": "com/mojang/patchy/1.3.9/patchy-1.3.9.jar", "sha1": "eb8bb7b66fa0e2152b1b40b3856e82f7619439ee", "size": 23581, "url": "https://libraries.minecraft.net/com/mojang/patchy/1.3.9/patchy-1.3.9.jar"}}, "name": "com.mojang:patchy:1.3.9"}, {"downloads": {"artifact": {"path": "oshi-project/oshi-core/1.1/oshi-core-1.1.jar", "sha1": "9ddf7b048a8d701be231c0f4f95fd986198fd2d8", "size": 30973, "url": "https://libraries.minecraft.net/oshi-project/oshi-core/1.1/oshi-core-1.1.jar"}}, "name": "oshi-project:oshi-core:1.1"}, {"downloads": {"artifact": {"path": "net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar", "sha1": "cb208278274bf12ebdb56c61bd7407e6f774d65a", "size": 1091208, "url": "https://libraries.minecraft.net/net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar"}}, "name": "net.java.dev.jna:jna:4.4.0"}, {"downloads": {"artifact": {"path": "net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar", "sha1": "e3f70017be8100d3d6923f50b3d2ee17714e9c13", "size": 913436, "url": "https://libraries.minecraft.net/net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar"}}, "name": "net.java.dev.jna:platform:3.4.0"}, {"downloads": {"artifact": {"path": "com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar", "sha1": "63d216a9311cca6be337c1e458e587f99d382b84", "size": 1634692, "url": "https://libraries.minecraft.net/com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar"}}, "name": "com.ibm.icu:icu4j-core-mojang:51.2"}, {"downloads": {"artifact": {"path": "net/sf/jopt-simple/jopt-simple/5.0.3/jopt-simple-5.0.3.jar", "sha1": "cdd846cfc4e0f7eefafc02c0f5dce32b9303aa2a", "size": 78175, "url": "https://libraries.minecraft.net/net/sf/jopt-simple/jopt-simple/5.0.3/jopt-simple-5.0.3.jar"}}, "name": "net.sf.jopt-simple:jopt-simple:5.0.3"}, {"downloads": {"artifact": {"path": "com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar", "sha1": "c73b5636faf089d9f00e8732a829577de25237ee", "size": 103871, "url": "https://libraries.minecraft.net/com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar"}}, "name": "com.paulscode:codecjorbis:20101023"}, {"downloads": {"artifact": {"path": "com/paulscode/codecwav/20101023/codecwav-20101023.jar", "sha1": "12f031cfe88fef5c1dd36c563c0a3a69bd7261da", "size": 5618, "url": "https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar"}}, "name": "com.paulscode:codecwav:20101023"}, {"downloads": {"artifact": {"path": "com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar", "sha1": "5c5e304366f75f9eaa2e8cca546a1fb6109348b3", "size": 21679, "url": "https://libraries.minecraft.net/com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar"}}, "name": "com.paulscode:libraryjavasound:20101123"}, {"downloads": {"artifact": {"path": "com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar", "sha1": "73e80d0794c39665aec3f62eee88ca91676674ef", "size": 18981, "url": "https://libraries.minecraft.net/com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar"}}, "name": "com.paulscode:librarylwjglopenal:20100824"}, {"downloads": {"artifact": {"path": "com/paulscode/soundsystem/20120107/soundsystem-20120107.jar", "sha1": "419c05fe9be71f792b2d76cfc9b67f1ed0fec7f6", "size": 65020, "url": "https://libraries.minecraft.net/com/paulscode/soundsystem/20120107/soundsystem-20120107.jar"}}, "name": "com.paulscode:soundsystem:20120107"}, {"downloads": {"artifact": {"path": "io/netty/netty-all/4.1.9.Final/netty-all-4.1.9.Final.jar", "sha1": "0097860965d6a0a6b98e7f569f3f966727b8db75", "size": 3511093, "url": "https://libraries.minecraft.net/io/netty/netty-all/4.1.9.Final/netty-all-4.1.9.Final.jar"}}, "name": "io.netty:netty-all:4.1.9.Final"}, {"downloads": {"artifact": {"path": "com/google/guava/guava/21.0/guava-21.0.jar", "sha1": "3a3d111be1be1b745edfa7d91678a12d7ed38709", "size": 2521113, "url": "https://libraries.minecraft.net/com/google/guava/guava/21.0/guava-21.0.jar"}}, "name": "com.google.guava:guava:21.0"}, {"downloads": {"artifact": {"path": "org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar", "sha1": "6c6c702c89bfff3cd9e80b04d668c5e190d588c6", "size": 479881, "url": "https://libraries.minecraft.net/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar"}}, "name": "org.apache.commons:commons-lang3:3.5"}, {"downloads": {"artifact": {"path": "commons-io/commons-io/2.5/commons-io-2.5.jar", "sha1": "2852e6e05fbb95076fc091f6d1780f1f8fe35e0f", "size": 208700, "url": "https://libraries.minecraft.net/commons-io/commons-io/2.5/commons-io-2.5.jar"}}, "name": "commons-io:commons-io:2.5"}, {"downloads": {"artifact": {"path": "commons-codec/commons-codec/1.10/commons-codec-1.10.jar", "sha1": "4b95f4897fa13f2cd904aee711aeafc0c5295cd8", "size": 284184, "url": "https://libraries.minecraft.net/commons-codec/commons-codec/1.10/commons-codec-1.10.jar"}}, "name": "commons-codec:commons-codec:1.10"}, {"downloads": {"artifact": {"path": "net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar", "sha1": "39c7796b469a600f72380316f6b1f11db6c2c7c4", "size": 208338, "url": "https://libraries.minecraft.net/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar"}}, "name": "net.java.jinput:jinput:2.0.5"}, {"downloads": {"artifact": {"path": "net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar", "sha1": "e12fe1fda814bd348c1579329c86943d2cd3c6a6", "size": 7508, "url": "https://libraries.minecraft.net/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar"}}, "name": "net.java.jutils:jutils:1.0.0"}, {"downloads": {"artifact": {"path": "com/google/code/gson/gson/2.8.0/gson-2.8.0.jar", "sha1": "c4ba5371a29ac9b2ad6129b1d39ea38750043eff", "size": 231952, "url": "https://libraries.minecraft.net/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar"}}, "name": "com.google.code.gson:gson:2.8.0"}, {"downloads": {"artifact": {"path": "com/mojang/authlib/1.5.25/authlib-1.5.25.jar", "sha1": "9834cdf236c22e84b946bba989e2f94ef5897c3c", "size": 65621, "url": "https://libraries.minecraft.net/com/mojang/authlib/1.5.25/authlib-1.5.25.jar"}}, "name": "com.mojang:authlib:1.5.25"}, {"downloads": {"artifact": {"path": "com/mojang/realms/1.10.22/realms-1.10.22.jar", "sha1": "bd0dccebdf3744c75f1ca20063f16e8f7d5e663f", "size": 7135057, "url": "https://libraries.minecraft.net/com/mojang/realms/1.10.22/realms-1.10.22.jar"}}, "name": "com.mojang:realms:1.10.22"}, {"downloads": {"artifact": {"path": "org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar", "sha1": "a698750c16740fd5b3871425f4cb3bbaa87f529d", "size": 365552, "url": "https://libraries.minecraft.net/org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar"}}, "name": "org.apache.commons:commons-compress:1.8.1"}, {"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar", "sha1": "18f4247ff4572a074444572cee34647c43e7c9c7", "size": 589512, "url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar"}}, "name": "org.apache.httpcomponents:httpclient:4.3.3"}, {"downloads": {"artifact": {"path": "commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar", "sha1": "f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f", "size": 62050, "url": "https://libraries.minecraft.net/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"}}, "name": "commons-logging:commons-logging:1.1.3"}, {"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar", "sha1": "31fbbff1ddbf98f3aa7377c94d33b0447c646b6e", "size": 282269, "url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar"}}, "name": "org.apache.httpcomponents:httpcore:4.3.2"}, {"downloads": {"artifact": {"path": "it/unimi/dsi/fastutil/7.1.0/fastutil-7.1.0.jar", "sha1": "9835253257524c1be7ab50c057aa2d418fb72082", "size": 17655579, "url": "https://libraries.minecraft.net/it/unimi/dsi/fastutil/7.1.0/fastutil-7.1.0.jar"}}, "name": "it.unimi.dsi:fastutil:7.1.0"}, {"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-api/2.8.1/log4j-api-2.8.1.jar", "sha1": "e801d13612e22cad62a3f4f3fe7fdbe6334a8e72", "size": 228859, "url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-api/2.8.1/log4j-api-2.8.1.jar"}}, "name": "org.apache.logging.log4j:log4j-api:2.8.1"}, {"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-core/2.8.1/log4j-core-2.8.1.jar", "sha1": "4ac28ff2f1ddf05dae3043a190451e8c46b73c31", "size": 1402925, "url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-core/2.8.1/log4j-core-2.8.1.jar"}}, "name": "org.apache.logging.log4j:log4j-core:2.8.1"}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar", "sha1": "697517568c68e78ae0b4544145af031c81082dfe", "size": 1047168, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209", "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar", "sha1": "d51a7c040a721d13efdfbd34f8b257b2df882ad0", "size": 173887, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209", "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar", "sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33", "size": 22, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"}, "classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar", "sha1": "931074f46c795d2f7b30ed6395df5715cfd7675b", "size": 578680, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar"}, "natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar", "sha1": "bcab850f8f487c3f4c4dbabde778bb82bd1a40ed", "size": 426822, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"}, "natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar", "sha1": "b84d5102b9dbfabfeb5e43c7e2828d98a7fc80e0", "size": 613748, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}, "rules": [{"action": "allow"}, {"action": "disallow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar", "sha1": "7707204c9ffa5d91662de95f0a224e2f721b22af", "size": 1045632, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl:2.9.2-nightly-20140822", "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar", "sha1": "f0e612c840a7639c1f77f68d72a28dae2f0c8490", "size": 173887, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar"}}, "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.2-nightly-20140822", "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar", "sha1": "d898a33b5d0a6ef3fed3a4ead506566dce6720a5", "size": 578539, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar"}, "natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar", "sha1": "79f5ce2fea02e77fe47a3c745219167a542121d7", "size": 468116, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar"}, "natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar", "sha1": "78b2a55ce4dc29c6b3ec4df8ca165eba05f9b341", "size": 613680, "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.2-nightly-20140822", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}, "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"classifiers": {"natives-linux": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar", "sha1": "7ff832a6eb9ab6a767f1ade2b548092d0fa64795", "size": 10362, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar"}, "natives-osx": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar", "sha1": "53f9c919f34d2ca9de8c51fc4e1e8282029a9232", "size": 12186, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar"}, "natives-windows": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar", "sha1": "385ee093e01f587f30ee1c8a2ee7d408fd732e16", "size": 155179, "url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "net.java.jinput:jinput-platform:2.0.5", "natives": {"linux": "natives-linux", "osx": "natives-osx", "windows": "natives-windows"}}, {"downloads": {"artifact": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar", "sha1": "48fd510879dff266c3815947de66e3d4809f8668", "size": 11055, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar"}}, "name": "com.mojang:text2speech:1.10.3"}, {"downloads": {"artifact": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar", "sha1": "48fd510879dff266c3815947de66e3d4809f8668", "size": 11055, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3.jar"}, "classifiers": {"natives-linux": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-linux.jar", "sha1": "ab7896aec3b3dd272b06194357f2d98f832c0cfc", "size": 7833, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-linux.jar"}, "natives-windows": {"path": "com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-windows.jar", "sha1": "84a4b856389cc4f485275b1f63497a95a857a443", "size": 81217, "url": "https://libraries.minecraft.net/com/mojang/text2speech/1.10.3/text2speech-1.10.3-natives-windows.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "com.mojang:text2speech:1.10.3", "natives": {"linux": "natives-linux", "windows": "natives-windows"}}, {"downloads": {"artifact": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar", "sha1": "6ef160c3133a78de015830860197602ca1c855d3", "size": 40502, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar"}, "classifiers": {"natives-osx": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-natives-osx.jar", "sha1": "08befab4894d55875f33c3d300f4f71e6e828f64", "size": 5629, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-natives-osx.jar"}}}, "extract": {"exclude": ["META-INF/"]}, "name": "ca.weblite:java-objc-bridge:1.0.0", "natives": {"osx": "natives-osx"}, "rules": [{"action": "allow", "os": {"name": "osx"}}]}, {"downloads": {"artifact": {"path": "ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar", "sha1": "6ef160c3133a78de015830860197602ca1c855d3", "size": 40502, "url": "https://libraries.minecraft.net/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar"}}, "name": "ca.weblite:java-objc-bridge:1.0.0", "rules": [{"action": "allow", "os": {"name": "osx"}}]}], "logging": {"client": {"argument": "-Dlog4j.configurationFile=${path}", "file": {"id": "client-1.12.xml", "sha1": "bd65e7d2e3c237be76cfbef4c2405033d7f91521", "size": 888, "url": "https://piston-data.mojang.com/v1/objects/bd65e7d2e3c237be76cfbef4c2405033d7f91521/client-1.12.xml"}, "type": "log4j2-xml"}}, "mainClass": "net.minecraft.client.main.Main", "minecraftArguments": "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userType ${user_type} --versionType ${version_type}", "minimumLauncherVersion": 18, "releaseTime": "2017-09-18T08:39:46+00:00", "time": "2017-09-18T08:39:46+00:00", "type": "release"} diff --git a/mktest.sh b/mktest.sh index 8beb25e7..ca3ca148 100755 --- a/mktest.sh +++ b/mktest.sh @@ -69,7 +69,7 @@ else cp "$GRADLE_CACHE_JAR" "$MC_JAR" else echo "Downloading server ..." - wget "https://s3.amazonaws.com/Minecraft.Download/versions/1.12.2/minecraft_server.1.12.2.jar" -O "$MC_JAR" || { echo "failed to download MC jar" && exit 1; } + wget "https://launcher.mojang.com/v1/objects/886945bfb2b978778c3a0288fd7fab09d315b25f/server.jar" -O "$MC_JAR" || { echo "failed to download MC jar" && exit 1; } cp "$MC_JAR" "$MC_JAR.orig" fi fi diff --git a/patches/net/minecraft/block/Block.java.patch b/patches/net/minecraft/block/Block.java.patch index 81bc4606..1e5afda9 100644 --- a/patches/net/minecraft/block/Block.java.patch +++ b/patches/net/minecraft/block/Block.java.patch @@ -42,18 +42,22 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -@@ -48,6 +49,10 @@ +@@ -48,7 +49,13 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class Block ++import redstone.multimeter.interfaces.IBlock; ++ +import carpet.helpers.CapturedDrops; +import carpet.helpers.StatHelper; +import carpet.patches.BlockWool; + - public class Block ++public class Block implements IBlock /* RSMM */ { private static final ResourceLocation field_176230_a = new ResourceLocation("air"); -@@ -74,7 +79,7 @@ + public static final RegistryNamespacedDefaultedByKey field_149771_c = new RegistryNamespacedDefaultedByKey(field_176230_a); +@@ -74,7 +81,7 @@ public float field_149765_K; protected final BlockStateContainer field_176227_L; private IBlockState field_176228_M; @@ -62,7 +66,7 @@ public static int func_149682_b(Block p_149682_0_) { -@@ -236,7 +241,7 @@ +@@ -236,7 +243,7 @@ return this; } @@ -71,7 +75,7 @@ { this.field_149786_r = p_149713_1_; return this; -@@ -328,7 +333,7 @@ +@@ -328,7 +335,7 @@ return this.field_149782_v; } @@ -80,7 +84,7 @@ { this.field_149789_z = p_149675_1_; return this; -@@ -400,7 +405,10 @@ +@@ -400,7 +407,10 @@ public void func_180645_a(World p_180645_1_, BlockPos p_180645_2_, IBlockState p_180645_3_, Random p_180645_4_) { @@ -91,7 +95,7 @@ } public void func_180650_b(World p_180650_1_, BlockPos p_180650_2_, IBlockState p_180650_3_, Random p_180650_4_) -@@ -489,8 +497,17 @@ +@@ -489,8 +499,17 @@ double d1 = (double)(p_180635_0_.field_73012_v.nextFloat() * 0.5F) + 0.25D; double d2 = (double)(p_180635_0_.field_73012_v.nextFloat() * 0.5F) + 0.25D; EntityItem entityitem = new EntityItem(p_180635_0_, (double)p_180635_1_.func_177958_n() + d0, (double)p_180635_1_.func_177956_o() + d1, (double)p_180635_1_.func_177952_p() + d2, p_180635_2_); @@ -109,7 +113,7 @@ } } -@@ -594,7 +611,10 @@ +@@ -594,7 +613,10 @@ public void func_180657_a(World p_180657_1_, EntityPlayer p_180657_2_, BlockPos p_180657_3_, IBlockState p_180657_4_, @Nullable TileEntity p_180657_5_, ItemStack p_180657_6_) { @@ -121,7 +125,7 @@ p_180657_2_.func_71020_j(0.005F); if (this.func_149700_E() && EnchantmentHelper.func_77506_a(Enchantments.field_185306_r, p_180657_6_) > 0) -@@ -849,7 +869,8 @@ +@@ -849,7 +871,8 @@ func_176219_a(32, "deadbush", (new BlockDeadBush()).func_149711_c(0.0F).func_149672_a(SoundType.field_185850_c).func_149663_c("deadbush")); func_176219_a(33, "piston", (new BlockPistonBase(false)).func_149663_c("pistonBase")); func_176219_a(34, "piston_head", (new BlockPistonExtension()).func_149663_c("pistonBase")); diff --git a/patches/net/minecraft/block/BlockBeacon.java.patch b/patches/net/minecraft/block/BlockBeacon.java.patch index e48b7c8c..dbefa816 100644 --- a/patches/net/minecraft/block/BlockBeacon.java.patch +++ b/patches/net/minecraft/block/BlockBeacon.java.patch @@ -9,14 +9,22 @@ public class BlockBeacon extends BlockContainer { public BlockBeacon() -@@ -93,6 +95,11 @@ +@@ -93,6 +95,19 @@ ((TileEntityBeacon)tileentity).func_174908_m(); p_189540_2_.func_175641_c(p_189540_3_, this, 1, 0); } + + if (CarpetSettings.asyncBeaconUpdates && p_189540_2_.func_175640_z(p_189540_3_)) + { -+ HttpUtil.field_180193_a.submit(() -> p_189540_2_.func_175722_b(p_189540_3_, this, true)); ++ HttpUtil.field_180193_a.submit(() -> { ++ try { ++ p_189540_2_.func_175722_b(p_189540_3_, this, true); ++ } catch(Throwable e) { ++ e.printStackTrace(); ++ } finally { ++ System.out.println("Beacon thread exiting."); ++ } ++ }); + } } diff --git a/patches/net/minecraft/block/BlockButton.java.patch b/patches/net/minecraft/block/BlockButton.java.patch new file mode 100644 index 00000000..0cc49585 --- /dev/null +++ b/patches/net/minecraft/block/BlockButton.java.patch @@ -0,0 +1,31 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockButton.java ++++ ../src-work/minecraft/net/minecraft/block/BlockButton.java +@@ -24,7 +24,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public abstract class BlockButton extends BlockDirectional ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public abstract class BlockButton extends BlockDirectional implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyBool field_176584_b = PropertyBool.func_177716_a("powered"); + protected static final AxisAlignedBB field_185618_b = new AxisAlignedBB(0.3125D, 0.875D, 0.375D, 0.6875D, 1.0D, 0.625D); +@@ -365,4 +368,16 @@ + { + return BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176584_b); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176584_b) ? MAX_POWER : MIN_POWER; ++ } + } diff --git a/patches/net/minecraft/block/BlockChest.java.patch b/patches/net/minecraft/block/BlockChest.java.patch index d0a1edc5..50366fcc 100644 --- a/patches/net/minecraft/block/BlockChest.java.patch +++ b/patches/net/minecraft/block/BlockChest.java.patch @@ -1,6 +1,19 @@ --- ../src-base/minecraft/net/minecraft/block/BlockChest.java +++ ../src-work/minecraft/net/minecraft/block/BlockChest.java -@@ -67,21 +67,21 @@ +@@ -32,7 +32,11 @@ + import net.minecraft.world.ILockableContainer; + import net.minecraft.world.World; + +-public class BlockChest extends BlockContainer ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++import redstone.multimeter.helper.BlockChestHelper; ++ ++public class BlockChest extends BlockContainer implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyDirection field_176459_a = BlockHorizontal.field_185512_D; + protected static final AxisAlignedBB field_185557_b = new AxisAlignedBB(0.0625D, 0.0D, 0.0D, 0.9375D, 0.875D, 0.9375D); +@@ -67,21 +71,21 @@ public AxisAlignedBB func_185496_a(IBlockState p_185496_1_, IBlockAccess p_185496_2_, BlockPos p_185496_3_) { @@ -26,7 +39,7 @@ } } -@@ -92,7 +92,7 @@ +@@ -92,7 +96,7 @@ for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) { BlockPos blockpos = p_176213_2_.func_177972_a(enumfacing); @@ -35,7 +48,7 @@ if (iblockstate.func_177230_c() == this) { -@@ -172,10 +172,10 @@ +@@ -172,10 +176,10 @@ } else { @@ -50,7 +63,7 @@ EnumFacing enumfacing = (EnumFacing)p_176455_3_.func_177229_b(field_176459_a); if (iblockstate.func_177230_c() != this && iblockstate1.func_177230_c() != this) -@@ -186,8 +186,8 @@ +@@ -186,8 +190,8 @@ if (iblockstate2.func_177230_c() == this || iblockstate3.func_177230_c() == this) { BlockPos blockpos1 = iblockstate2.func_177230_c() == this ? p_176455_2_.func_177976_e() : p_176455_2_.func_177974_f(); @@ -61,7 +74,7 @@ enumfacing = EnumFacing.SOUTH; EnumFacing enumfacing2; -@@ -219,8 +219,8 @@ +@@ -219,8 +223,8 @@ else { BlockPos blockpos = iblockstate.func_177230_c() == this ? p_176455_2_.func_177978_c() : p_176455_2_.func_177968_d(); @@ -72,7 +85,7 @@ enumfacing = EnumFacing.EAST; EnumFacing enumfacing1; -@@ -368,7 +368,7 @@ +@@ -368,7 +372,7 @@ { for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) { @@ -81,7 +94,7 @@ { return true; } -@@ -458,7 +458,7 @@ +@@ -458,7 +462,7 @@ for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) { BlockPos blockpos = p_189418_2_.func_177972_a(enumfacing); @@ -90,3 +103,40 @@ if (block == this) { +@@ -595,6 +599,36 @@ + return BlockFaceShape.UNDEFINED; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$isMeterable() { ++ return BlockChestHelper.isTrapped(this); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowerSource() { ++ return BlockChestHelper.isTrapped(this); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return BlockChestHelper.isTrapped(this) && BlockChestHelper.getPower(world, pos, state) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPowerChangeOnStateChange() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return BlockChestHelper.isTrapped(this) ? BlockChestHelper.getPower(world, pos, state) : MIN_POWER; ++ } ++ + public static enum Type + { + BASIC, diff --git a/patches/net/minecraft/block/BlockDaylightDetector.java.patch b/patches/net/minecraft/block/BlockDaylightDetector.java.patch new file mode 100644 index 00000000..53376eff --- /dev/null +++ b/patches/net/minecraft/block/BlockDaylightDetector.java.patch @@ -0,0 +1,31 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockDaylightDetector.java ++++ ../src-work/minecraft/net/minecraft/block/BlockDaylightDetector.java +@@ -25,7 +25,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockDaylightDetector extends BlockContainer ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockDaylightDetector extends BlockContainer implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyInteger field_176436_a = PropertyInteger.func_177719_a("power", 0, 15); + protected static final AxisAlignedBB field_185566_b = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.375D, 1.0D); +@@ -173,4 +176,16 @@ + { + return p_193383_4_ == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176436_a) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176436_a); ++ } + } diff --git a/patches/net/minecraft/block/BlockDispenser.java.patch b/patches/net/minecraft/block/BlockDispenser.java.patch index 7f8ea668..9bc6c58b 100644 --- a/patches/net/minecraft/block/BlockDispenser.java.patch +++ b/patches/net/minecraft/block/BlockDispenser.java.patch @@ -1,15 +1,19 @@ --- ../src-base/minecraft/net/minecraft/block/BlockDispenser.java +++ ../src-work/minecraft/net/minecraft/block/BlockDispenser.java -@@ -32,6 +32,8 @@ +@@ -32,7 +32,11 @@ import net.minecraft.util.registry.RegistryDefaulted; import net.minecraft.world.World; +-public class BlockDispenser extends BlockContainer ++import redstone.multimeter.block.MeterableBlock; ++ +import carpet.CarpetSettings; + - public class BlockDispenser extends BlockContainer ++public class BlockDispenser extends BlockContainer implements MeterableBlock /* RSMM */ { public static final PropertyDirection field_176441_a = BlockDirectional.field_176387_N; -@@ -54,6 +56,8 @@ + public static final PropertyBool field_176440_b = PropertyBool.func_177716_a("triggered"); +@@ -54,6 +58,8 @@ public void func_176213_c(World p_176213_1_, BlockPos p_176213_2_, IBlockState p_176213_3_) { super.func_176213_c(p_176213_1_, p_176213_2_, p_176213_3_); @@ -18,7 +22,7 @@ this.func_176438_e(p_176213_1_, p_176213_2_, p_176213_3_); } -@@ -153,7 +157,17 @@ +@@ -153,9 +159,21 @@ public void func_189540_a(IBlockState p_189540_1_, World p_189540_2_, BlockPos p_189540_3_, Block p_189540_4_, BlockPos p_189540_5_) { @@ -36,8 +40,12 @@ + /* end */ boolean flag1 = ((Boolean)p_189540_1_.func_177229_b(field_176440_b)).booleanValue(); ++ rsmm$logPowered(p_189540_2_, p_189540_3_, flag); // RSMM ++ if (flag && !flag1) -@@ -187,7 +201,8 @@ + { + p_189540_2_.func_175684_a(p_189540_3_, this, this.func_149738_a(p_189540_2_)); +@@ -187,7 +205,8 @@ public void func_180633_a(World p_180633_1_, BlockPos p_180633_2_, IBlockState p_180633_3_, EntityLivingBase p_180633_4_, ItemStack p_180633_5_) { @@ -47,3 +55,26 @@ if (p_180633_5_.func_82837_s()) { +@@ -269,4 +288,22 @@ + { + return new BlockStateContainer(this, new IProperty[] {field_176441_a, field_176440_b}); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return world.func_175640_z(pos) || (CarpetSettings.quasiConnectivity && world.func_175640_z(pos.func_177984_a())); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176440_b); ++ } + } diff --git a/patches/net/minecraft/block/BlockDoor.java.patch b/patches/net/minecraft/block/BlockDoor.java.patch new file mode 100644 index 00000000..fb9051af --- /dev/null +++ b/patches/net/minecraft/block/BlockDoor.java.patch @@ -0,0 +1,65 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockDoor.java ++++ ../src-work/minecraft/net/minecraft/block/BlockDoor.java +@@ -1,6 +1,8 @@ + package net.minecraft.block; + + import java.util.Random; ++ ++import net.minecraft.block.BlockDoor.EnumDoorHalf; + import net.minecraft.block.material.EnumPushReaction; + import net.minecraft.block.material.MapColor; + import net.minecraft.block.material.Material; +@@ -27,7 +29,9 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockDoor extends Block ++import redstone.multimeter.block.MeterableBlock; ++ ++public class BlockDoor extends Block implements MeterableBlock /* RSMM */ + { + public static final PropertyDirection field_176520_a = BlockHorizontal.field_185512_D; + public static final PropertyBool field_176519_b = PropertyBool.func_177716_a("open"); +@@ -222,6 +226,9 @@ + { + boolean flag = p_189540_2_.func_175640_z(p_189540_3_) || p_189540_2_.func_175640_z(blockpos1); + ++ rsmm$logPowered(p_189540_2_, p_189540_3_, flag); // RSMM ++ rsmm$logPowered(p_189540_2_, blockpos1, flag); // RSMM ++ + if (p_189540_4_ != this && (flag || p_189540_4_.func_176223_P().func_185897_m()) && flag != ((Boolean)iblockstate1.func_177229_b(field_176522_N)).booleanValue()) + { + p_189540_2_.func_180501_a(blockpos1, iblockstate1.func_177226_a(field_176522_N, Boolean.valueOf(flag)), 2); +@@ -439,6 +446,32 @@ + return BlockFaceShape.UNDEFINED; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return world.func_175640_z(pos) || world.func_175640_z(getOtherHalf(pos, state)); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176519_b); ++ } ++ ++ // RSMM ++ private BlockPos getOtherHalf(BlockPos pos, IBlockState state) { ++ EnumDoorHalf half = state.func_177229_b(field_176523_O); ++ EnumFacing dir = (half == EnumDoorHalf.LOWER) ? EnumFacing.UP : EnumFacing.DOWN; ++ ++ return pos.func_177972_a(dir); ++ } ++ + public static enum EnumDoorHalf implements IStringSerializable + { + UPPER, diff --git a/patches/net/minecraft/block/BlockEndPortalFrame.java.patch b/patches/net/minecraft/block/BlockEndPortalFrame.java.patch new file mode 100644 index 00000000..2ca44af4 --- /dev/null +++ b/patches/net/minecraft/block/BlockEndPortalFrame.java.patch @@ -0,0 +1,24 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockEndPortalFrame.java ++++ ../src-work/minecraft/net/minecraft/block/BlockEndPortalFrame.java +@@ -29,7 +29,9 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockEndPortalFrame extends Block ++import redstone.multimeter.block.Meterable; ++ ++public class BlockEndPortalFrame extends Block implements Meterable /* RSMM */ + { + public static final PropertyDirection field_176508_a = BlockHorizontal.field_185512_D; + public static final PropertyBool field_176507_b = PropertyBool.func_177716_a("eye"); +@@ -135,4 +137,10 @@ + { + return p_193383_4_ == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176507_b); ++ } + } diff --git a/patches/net/minecraft/block/BlockFenceGate.java.patch b/patches/net/minecraft/block/BlockFenceGate.java.patch index ebd179ad..d23c77e9 100644 --- a/patches/net/minecraft/block/BlockFenceGate.java.patch +++ b/patches/net/minecraft/block/BlockFenceGate.java.patch @@ -1,17 +1,21 @@ --- ../src-base/minecraft/net/minecraft/block/BlockFenceGate.java +++ ../src-work/minecraft/net/minecraft/block/BlockFenceGate.java -@@ -20,6 +20,10 @@ +@@ -20,7 +20,13 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockFenceGate extends BlockHorizontal ++import redstone.multimeter.block.MeterableBlock; ++ +import carpet.CarpetSettings; + + import carpet.CarpetSettings; + - public class BlockFenceGate extends BlockHorizontal ++public class BlockFenceGate extends BlockHorizontal implements MeterableBlock /* RSMM */ { public static final PropertyBool field_176466_a = PropertyBool.func_177716_a("open"); -@@ -77,7 +81,7 @@ + public static final PropertyBool field_176465_b = PropertyBool.func_177716_a("powered"); +@@ -77,7 +83,7 @@ public boolean func_176196_c(World p_176196_1_, BlockPos p_176196_2_) { @@ -20,3 +24,29 @@ } @Nullable +@@ -144,6 +150,8 @@ + { + boolean flag = p_189540_2_.func_175640_z(p_189540_3_); + ++ rsmm$logPowered(p_189540_2_, p_189540_3_, flag); // RSMM ++ + if (((Boolean)p_189540_1_.func_177229_b(field_176465_b)).booleanValue() != flag) + { + p_189540_2_.func_180501_a(p_189540_3_, p_189540_1_.func_177226_a(field_176465_b, Boolean.valueOf(flag)).func_177226_a(field_176466_a, Boolean.valueOf(flag)), 2); +@@ -195,4 +203,16 @@ + return BlockFaceShape.UNDEFINED; + } + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176466_a); ++ } + } diff --git a/patches/net/minecraft/block/BlockHopper.java.patch b/patches/net/minecraft/block/BlockHopper.java.patch index 3aa79af7..2f1dcd12 100644 --- a/patches/net/minecraft/block/BlockHopper.java.patch +++ b/patches/net/minecraft/block/BlockHopper.java.patch @@ -1,15 +1,19 @@ --- ../src-base/minecraft/net/minecraft/block/BlockHopper.java +++ ../src-work/minecraft/net/minecraft/block/BlockHopper.java -@@ -31,6 +31,8 @@ +@@ -31,7 +31,11 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockHopper extends BlockContainer ++import redstone.multimeter.block.MeterableBlock; ++ +import carpet.helpers.BlockRotator; + - public class BlockHopper extends BlockContainer ++public class BlockHopper extends BlockContainer implements MeterableBlock /* RSMM */ { public static final PropertyDirection field_176430_a = PropertyDirection.func_177712_a("facing", new Predicate() -@@ -71,6 +73,8 @@ + { +@@ -71,6 +75,8 @@ public IBlockState func_180642_a(World p_180642_1_, BlockPos p_180642_2_, EnumFacing p_180642_3_, float p_180642_4_, float p_180642_5_, float p_180642_6_, int p_180642_7_, EntityLivingBase p_180642_8_) { EnumFacing enumfacing = p_180642_3_.func_176734_d(); @@ -18,3 +22,35 @@ if (enumfacing == EnumFacing.UP) { +@@ -139,6 +145,8 @@ + { + boolean flag = !p_176427_1_.func_175640_z(p_176427_2_); + ++ rsmm$logPowered(p_176427_1_, p_176427_2_, !flag); // RSMM ++ + if (flag != ((Boolean)p_176427_3_.func_177229_b(field_176429_b)).booleanValue()) + { + p_176427_1_.func_180501_a(p_176427_2_, p_176427_3_.func_177226_a(field_176429_b, Boolean.valueOf(flag)), 4); +@@ -230,4 +238,22 @@ + { + return p_193383_4_ == EnumFacing.UP ? BlockFaceShape.BOWL : BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ TileEntity blockEntity = world.func_175625_s(pos); ++ ++ if (blockEntity instanceof TileEntityHopper) { ++ return !((TileEntityHopper)blockEntity).func_145888_j(); ++ } ++ ++ return false; ++ } + } diff --git a/patches/net/minecraft/block/BlockLever.java.patch b/patches/net/minecraft/block/BlockLever.java.patch new file mode 100644 index 00000000..7aec7bd7 --- /dev/null +++ b/patches/net/minecraft/block/BlockLever.java.patch @@ -0,0 +1,33 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockLever.java ++++ ../src-work/minecraft/net/minecraft/block/BlockLever.java +@@ -23,7 +23,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockLever extends Block ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockLever extends Block implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyEnum field_176360_a = PropertyEnum.func_177709_a("facing", BlockLever.EnumOrientation.class); + public static final PropertyBool field_176359_b = PropertyBool.func_177716_a("powered"); +@@ -309,6 +312,18 @@ + return BlockFaceShape.UNDEFINED; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176359_b); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176359_b) ? MAX_POWER : MIN_POWER; ++ } ++ + public static enum EnumOrientation implements IStringSerializable + { + DOWN_X(0, "down_x", EnumFacing.DOWN), diff --git a/patches/net/minecraft/block/BlockNote.java.patch b/patches/net/minecraft/block/BlockNote.java.patch index 0410eae1..ba72c8c8 100644 --- a/patches/net/minecraft/block/BlockNote.java.patch +++ b/patches/net/minecraft/block/BlockNote.java.patch @@ -1,20 +1,28 @@ --- ../src-base/minecraft/net/minecraft/block/BlockNote.java +++ ../src-work/minecraft/net/minecraft/block/BlockNote.java -@@ -19,9 +19,13 @@ +@@ -19,9 +19,15 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +-public class BlockNote extends BlockContainer ++import redstone.multimeter.block.MeterableBlock; ++import redstone.multimeter.helper.WorldHelper; +import carpet.CarpetSettings; +import net.minecraft.init.Blocks; + - public class BlockNote extends BlockContainer ++public class BlockNote extends BlockContainer implements MeterableBlock /* RSMM */ { private static final List field_176434_a = Lists.newArrayList(SoundEvents.field_187682_dG, SoundEvents.field_187676_dE, SoundEvents.field_187688_dI, SoundEvents.field_187685_dH, SoundEvents.field_187679_dF, SoundEvents.field_193809_ey, SoundEvents.field_193807_ew, SoundEvents.field_193810_ez, SoundEvents.field_193808_ex, SoundEvents.field_193785_eE); + private SoundEvent saveSoundEvent; public BlockNote() { -@@ -37,6 +41,8 @@ +@@ -34,9 +40,13 @@ + boolean flag = p_189540_2_.func_175640_z(p_189540_3_); + TileEntity tileentity = p_189540_2_.func_175625_s(p_189540_3_); + ++ rsmm$logPowered(p_189540_2_, p_189540_3_, flag); // RSMM ++ if (tileentity instanceof TileEntityNote) { TileEntityNote tileentitynote = (TileEntityNote)tileentity; @@ -23,10 +31,16 @@ if (tileentitynote.field_145880_i != flag) { -@@ -46,6 +52,12 @@ +@@ -46,6 +56,18 @@ } tileentitynote.field_145880_i = flag; ++ ++ // RSMM start ++ if (CarpetSettings.redstoneMultimeter) { ++ WorldHelper.getMultimeter().logActive(p_189540_2_, p_189540_3_, flag); ++ } ++ // RSMM end + + //Added note block imitation in 1.13 CARPET-XCOM + if(CarpetSettings.noteBlockImitationOf1_13) p_189540_2_.func_175685_c(p_189540_3_, this, true); @@ -36,7 +50,7 @@ } } } -@@ -68,6 +80,9 @@ +@@ -68,6 +90,9 @@ p_180639_4_.func_71029_a(StatList.field_188087_U); } @@ -46,7 +60,7 @@ return true; } } -@@ -113,4 +128,60 @@ +@@ -113,4 +138,78 @@ { return EnumBlockRenderType.MODEL; } @@ -105,5 +119,23 @@ + } + + return i; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ TileEntity blockEntity = world.func_175625_s(pos); ++ ++ if (blockEntity instanceof TileEntityNote) { ++ return ((TileEntityNote)blockEntity).field_145880_i; ++ } ++ ++ return false; + } } diff --git a/patches/net/minecraft/block/BlockObserver.java.patch b/patches/net/minecraft/block/BlockObserver.java.patch index 76d3fdfe..653af19c 100644 --- a/patches/net/minecraft/block/BlockObserver.java.patch +++ b/patches/net/minecraft/block/BlockObserver.java.patch @@ -8,16 +8,21 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.Mirror; import net.minecraft.util.Rotation; -@@ -15,6 +16,8 @@ +@@ -15,7 +16,12 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockObserver extends BlockDirectional ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ +import carpet.CarpetSettings; + - public class BlockObserver extends BlockDirectional ++public class BlockObserver extends BlockDirectional implements Meterable /* RSMM */, PowerSource /* RSMM */ { public static final PropertyBool field_190963_a = PropertyBool.func_177716_a("powered"); -@@ -74,7 +77,18 @@ + +@@ -74,7 +80,18 @@ { if (!p_190960_2_.func_184145_b(p_190960_3_, this)) { @@ -37,7 +42,7 @@ } } } -@@ -125,7 +139,12 @@ +@@ -125,7 +142,12 @@ public IBlockState func_180642_a(World p_180642_1_, BlockPos p_180642_2_, EnumFacing p_180642_3_, float p_180642_4_, float p_180642_5_, float p_180642_6_, int p_180642_7_, EntityLivingBase p_180642_8_) { @@ -51,3 +56,20 @@ } public int func_176201_c(IBlockState p_176201_1_) +@@ -145,4 +167,16 @@ + { + return this.func_176223_P().func_177226_a(field_176387_N, EnumFacing.func_82600_a(p_176203_1_ & 7)); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_190963_a); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_190963_a) ? MAX_POWER : MIN_POWER; ++ } + } diff --git a/patches/net/minecraft/block/BlockPistonBase.java.patch b/patches/net/minecraft/block/BlockPistonBase.java.patch index 89aa2ee4..1986489c 100644 --- a/patches/net/minecraft/block/BlockPistonBase.java.patch +++ b/patches/net/minecraft/block/BlockPistonBase.java.patch @@ -13,19 +13,25 @@ import net.minecraft.block.material.EnumPushReaction; import net.minecraft.block.material.Material; import net.minecraft.block.properties.IProperty; -@@ -29,6 +33,11 @@ +@@ -29,7 +33,16 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockPistonBase extends BlockDirectional +import narcolepticfrog.rsmm.events.PistonPushEventDispatcher; +import carpet.CarpetSettings; +import carpet.utils.PistonFixes; +import net.minecraft.world.WorldServer; + - public class BlockPistonBase extends BlockDirectional ++import redstone.multimeter.block.MeterableBlock; ++import redstone.multimeter.helper.WorldHelper; ++import redstone.multimeter.server.Multimeter; ++ ++public class BlockPistonBase extends BlockDirectional implements MeterableBlock /* RSMM */ { public static final PropertyBool field_176320_b = PropertyBool.func_177716_a("extended"); -@@ -39,6 +48,7 @@ + protected static final AxisAlignedBB field_185648_b = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.75D, 1.0D, 1.0D); +@@ -39,6 +52,7 @@ protected static final AxisAlignedBB field_185652_f = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D); protected static final AxisAlignedBB field_185653_g = new AxisAlignedBB(0.0D, 0.25D, 0.0D, 1.0D, 1.0D, 1.0D); private final boolean field_150082_a; @@ -33,7 +39,7 @@ public BlockPistonBase(boolean p_i45443_1_) { -@@ -99,7 +109,8 @@ +@@ -99,7 +113,8 @@ public void func_180633_a(World p_180633_1_, BlockPos p_180633_2_, IBlockState p_180633_3_, EntityLivingBase p_180633_4_, ItemStack p_180633_5_) { @@ -43,7 +49,7 @@ if (!p_180633_1_.field_72995_K) { -@@ -130,23 +141,83 @@ +@@ -130,43 +145,117 @@ private void func_176316_e(World p_176316_1_, BlockPos p_176316_2_, IBlockState p_176316_3_) { @@ -127,24 +133,49 @@ + return 0; + } + ++ // RSMM - wrapped method to capture return value + public boolean func_176318_b(World p_176318_1_, BlockPos p_176318_2_, EnumFacing p_176318_3_) { ++ boolean powered = _shouldBeExtended(p_176318_1_, p_176318_2_, p_176318_3_); ++ rsmm$logPowered(p_176318_1_, p_176318_2_, powered); // RSMM ++ return powered; ++ } ++ ++ private boolean _shouldBeExtended(World worldIn, BlockPos pos, EnumFacing facing) ++ { for (EnumFacing enumfacing : EnumFacing.values()) { -@@ -162,6 +233,12 @@ +- if (enumfacing != p_176318_3_ && p_176318_1_.func_175709_b(p_176318_2_.func_177972_a(enumfacing), enumfacing)) ++ if (enumfacing != facing && worldIn.func_175709_b(pos.func_177972_a(enumfacing), enumfacing)) + { + return true; + } + } + +- if (p_176318_1_.func_175709_b(p_176318_2_, EnumFacing.DOWN)) ++ if (worldIn.func_175709_b(pos, EnumFacing.DOWN)) + { + return true; } else { +- BlockPos blockpos = p_176318_2_.func_177984_a(); + /* carpet mod */ + if (!CarpetSettings.quasiConnectivity) + { + return false; + } + /* end */ - BlockPos blockpos = p_176318_2_.func_177984_a(); ++ BlockPos blockpos = pos.func_177984_a(); for (EnumFacing enumfacing1 : EnumFacing.values()) -@@ -240,7 +317,11 @@ + { +- if (enumfacing1 != EnumFacing.DOWN && p_176318_1_.func_175709_b(blockpos.func_177972_a(enumfacing1), enumfacing1)) ++ if (enumfacing1 != EnumFacing.DOWN && worldIn.func_175709_b(blockpos.func_177972_a(enumfacing1), enumfacing1)) + { + return true; + } +@@ -240,7 +329,11 @@ } } } @@ -157,7 +188,7 @@ if (!flag1 && iblockstate.func_185904_a() != Material.field_151579_a && func_185646_a(iblockstate, p_189539_2_, blockpos, enumfacing.func_176734_d(), false, enumfacing) && (iblockstate.func_185905_o() == EnumPushReaction.NORMAL || block == Blocks.field_150331_J || block == Blocks.field_150320_F)) { this.func_176319_a(p_189539_2_, p_189539_3_, enumfacing, false); -@@ -307,7 +388,15 @@ +@@ -307,7 +400,15 @@ return false; } @@ -174,7 +205,7 @@ } else { -@@ -319,6 +408,14 @@ +@@ -319,6 +420,14 @@ return false; } } @@ -189,7 +220,7 @@ private boolean func_176319_a(World p_176319_1_, BlockPos p_176319_2_, EnumFacing p_176319_3_, boolean p_176319_4_) { -@@ -342,6 +439,7 @@ +@@ -342,6 +451,7 @@ { BlockPos blockpos = list.get(i); list1.add(p_176319_1_.func_180495_p(blockpos).func_185899_b(p_176319_1_, blockpos)); @@ -197,7 +228,7 @@ } List list2 = blockpistonstructurehelper.func_177252_d(); -@@ -358,15 +456,70 @@ +@@ -358,15 +468,56 @@ --k; aiblockstate[k] = iblockstate; } @@ -223,38 +254,22 @@ { BlockPos blockpos3 = list.get(l); + // ----- RSMM Start ------ // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + PistonPushEventDispatcher.dispatchEvent(p_176319_1_, blockpos3, enumfacing); + } ++ if (CarpetSettings.redstoneMultimeter) { ++ Multimeter multimeter = WorldHelper.getMultimeter(); ++ ++ multimeter.logMoved(p_176319_1_, blockpos3, enumfacing); ++ multimeter.moveMeters(p_176319_1_, blockpos3, enumfacing); ++ } + // ----- RSMM End ----- // IBlockState iblockstate2 = p_176319_1_.func_180495_p(blockpos3); -- p_176319_1_.func_180501_a(blockpos3, Blocks.field_150350_a.func_176223_P(), 2); + p_176319_1_.func_180501_a(blockpos3, Blocks.field_150350_a.func_176223_P(), 2); blockpos3 = blockpos3.func_177972_a(enumfacing); -- p_176319_1_.func_180501_a(blockpos3, Blocks.field_180384_M.func_176223_P().func_177226_a(field_176387_N, p_176319_3_), 4); + p_176319_1_.func_180501_a(blockpos3, Blocks.field_180384_M.func_176223_P().func_177226_a(field_176387_N, p_176319_3_), 4); - p_176319_1_.func_175690_a(blockpos3, BlockPistonMoving.func_185588_a(list1.get(l), p_176319_3_, p_176319_4_, false)); -+ // Added the properties of opacity and light to the moving block as to minimize light updates. CARPET-XCOM -+ if(CarpetSettings.movingBlockLightOptimization){ -+ BlockPos posOld = list.get(l); -+ boolean remove = true; -+ for (int backwardCheck = l - 1; backwardCheck >= 0; --backwardCheck){ -+ BlockPos blockposCheck = list.get(backwardCheck); -+ if(blockposCheck.func_177972_a(enumfacing).equals(posOld)){ -+ remove = false; -+ break; -+ } -+ } -+ IBlockState iBlockState = Blocks.field_180384_M.func_176223_P().func_177226_a(field_176387_N, p_176319_3_) -+ .func_177226_a(BlockPistonMoving.OPACITY, Math.min(iblockstate2.func_185891_c(), 15)) -+ .func_177226_a(BlockPistonMoving.LIGHT, iblockstate2.func_185906_d()); -+ p_176319_1_.func_180501_a(blockpos3, iBlockState, 20); -+ if(remove){ -+ p_176319_1_.func_180501_a(posOld, Blocks.field_150350_a.func_176223_P(), 2); -+ } -+ p_176319_1_.func_190522_c(blockpos3, iBlockState.func_177230_c()); -+ }else{ -+ p_176319_1_.func_180501_a(list.get(l), Blocks.field_150350_a.func_176223_P(), 2); -+ p_176319_1_.func_180501_a(blockpos3, Blocks.field_180384_M.func_176223_P().func_177226_a(field_176387_N, p_176319_3_), 4); -+ } ++ + // Movable Tile entity fix CARPET-2No2Name + if(CarpetSettings.autocrafter && iblockstate2 instanceof BlockWorkbench){ + TileEntity tilePiston = BlockPistonMoving.func_185588_a(list1.get(l), p_176319_3_, p_176319_4_, false); @@ -271,7 +286,7 @@ --k; aiblockstate[k] = iblockstate2; } -@@ -397,6 +550,8 @@ +@@ -397,6 +548,8 @@ p_176319_1_.func_175685_c(blockpos2, Blocks.field_150332_K, false); } @@ -280,11 +295,29 @@ return true; } } -@@ -439,4 +594,9 @@ +@@ -439,4 +592,27 @@ p_193383_2_ = this.func_176221_a(p_193383_2_, p_193383_1_, p_193383_3_); return p_193383_2_.func_177229_b(field_176387_N) != p_193383_4_.func_176734_d() && ((Boolean)p_193383_2_.func_177229_b(field_176320_b)).booleanValue() ? BlockFaceShape.UNDEFINED : BlockFaceShape.SOLID; } + ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return func_176318_b(world, pos, state.func_177229_b(field_176387_N)); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176320_b); ++ } ++ + // Added method for checking if block is being pushed for duping fixes CARPET-XCOM + public static boolean isBeingPushed(BlockPos pos){ + return dupeFixLocations.contains(pos); diff --git a/patches/net/minecraft/block/BlockPistonMoving.java.patch b/patches/net/minecraft/block/BlockPistonMoving.java.patch deleted file mode 100644 index a6d32fcd..00000000 --- a/patches/net/minecraft/block/BlockPistonMoving.java.patch +++ /dev/null @@ -1,51 +0,0 @@ ---- ../src-base/minecraft/net/minecraft/block/BlockPistonMoving.java -+++ ../src-work/minecraft/net/minecraft/block/BlockPistonMoving.java -@@ -28,15 +28,21 @@ - import net.minecraft.world.IBlockAccess; - import net.minecraft.world.World; - -+import net.minecraft.block.properties.PropertyInteger; -+ - public class BlockPistonMoving extends BlockContainer - { - public static final PropertyDirection field_176426_a = BlockPistonExtension.field_176387_N; - public static final PropertyEnum field_176425_b = BlockPistonExtension.field_176325_b; - -+ // Getting propertys from other sources as its apparently laggy to create your own. CARPET-XCOM -+ public static final PropertyInteger OPACITY = BlockDaylightDetector.field_176436_a; -+ public static final PropertyInteger LIGHT = BlockLiquid.field_176367_b; -+ - public BlockPistonMoving() - { - super(Material.field_76233_E); -- this.func_180632_j(this.field_176227_L.func_177621_b().func_177226_a(field_176426_a, EnumFacing.NORTH).func_177226_a(field_176425_b, BlockPistonExtension.EnumPistonType.DEFAULT)); -+ this.func_180632_j(this.field_176227_L.func_177621_b().func_177226_a(field_176426_a, EnumFacing.NORTH).func_177226_a(field_176425_b, BlockPistonExtension.EnumPistonType.DEFAULT).func_177226_a(OPACITY, 0).func_177226_a(LIGHT, 0)); - this.func_149711_c(-1.0F); - } - -@@ -207,11 +213,24 @@ - - protected BlockStateContainer func_180661_e() - { -- return new BlockStateContainer(this, new IProperty[] {field_176426_a, field_176425_b}); -+ // Adding the propertys to the list of allowed propertys. CARPET-XCOM -+ return new BlockStateContainer(this, new IProperty[] {field_176426_a, field_176425_b, OPACITY, LIGHT}); - } - - public BlockFaceShape func_193383_a(IBlockAccess p_193383_1_, IBlockState p_193383_2_, BlockPos p_193383_3_, EnumFacing p_193383_4_) - { - return BlockFaceShape.UNDEFINED; - } -+ -+ // Grabbing the inherited properties from the parrent block that is moved and setting it to the moving block. CARPET-XCOM -+ @Override -+ public int func_149717_k(IBlockState state) -+ { -+ return state.func_177229_b(OPACITY); -+ } -+ @Override -+ public int func_149750_m(IBlockState state) -+ { -+ return state.func_177229_b(LIGHT); -+ } - } diff --git a/patches/net/minecraft/block/BlockPressurePlate.java.patch b/patches/net/minecraft/block/BlockPressurePlate.java.patch new file mode 100644 index 00000000..14cb2a5f --- /dev/null +++ b/patches/net/minecraft/block/BlockPressurePlate.java.patch @@ -0,0 +1,33 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockPressurePlate.java ++++ ../src-work/minecraft/net/minecraft/block/BlockPressurePlate.java +@@ -15,7 +15,10 @@ + import net.minecraft.util.math.BlockPos; + import net.minecraft.world.World; + +-public class BlockPressurePlate extends BlockBasePressurePlate ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockPressurePlate extends BlockBasePressurePlate implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyBool field_176580_a = PropertyBool.func_177716_a("powered"); + private final BlockPressurePlate.Sensitivity field_150069_a; +@@ -107,6 +110,18 @@ + return new BlockStateContainer(this, new IProperty[] {field_176580_a}); + } + ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176580_a); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176580_a) ? MAX_POWER : MIN_POWER; ++ } ++ + public static enum Sensitivity + { + EVERYTHING, diff --git a/patches/net/minecraft/block/BlockPressurePlateWeighted.java.patch b/patches/net/minecraft/block/BlockPressurePlateWeighted.java.patch new file mode 100644 index 00000000..8d970967 --- /dev/null +++ b/patches/net/minecraft/block/BlockPressurePlateWeighted.java.patch @@ -0,0 +1,31 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockPressurePlateWeighted.java ++++ ../src-work/minecraft/net/minecraft/block/BlockPressurePlateWeighted.java +@@ -14,7 +14,10 @@ + import net.minecraft.util.math.MathHelper; + import net.minecraft.world.World; + +-public class BlockPressurePlateWeighted extends BlockBasePressurePlate ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockPressurePlateWeighted extends BlockBasePressurePlate implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyInteger field_176579_a = PropertyInteger.func_177719_a("power", 0, 15); + private final int field_150068_a; +@@ -85,4 +88,16 @@ + { + return new BlockStateContainer(this, new IProperty[] {field_176579_a}); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176579_a) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176579_a); ++ } + } diff --git a/patches/net/minecraft/block/BlockRailDetector.java.patch b/patches/net/minecraft/block/BlockRailDetector.java.patch index 0b52e661..903a9fd7 100644 --- a/patches/net/minecraft/block/BlockRailDetector.java.patch +++ b/patches/net/minecraft/block/BlockRailDetector.java.patch @@ -1,6 +1,18 @@ --- ../src-base/minecraft/net/minecraft/block/BlockRailDetector.java +++ ../src-work/minecraft/net/minecraft/block/BlockRailDetector.java -@@ -220,6 +220,14 @@ +@@ -23,7 +23,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockRailDetector extends BlockRailBase ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockRailDetector extends BlockRailBase implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyEnum field_176573_b = PropertyEnum.func_177708_a("shape", BlockRailBase.EnumRailDirection.class, new Predicate() + { +@@ -220,6 +223,14 @@ switch ((BlockRailBase.EnumRailDirection)p_185499_1_.func_177229_b(field_176573_b)) { @@ -15,3 +27,20 @@ case ASCENDING_EAST: return p_185499_1_.func_177226_a(field_176573_b, BlockRailBase.EnumRailDirection.ASCENDING_WEST); case ASCENDING_WEST: +@@ -352,4 +363,16 @@ + { + return new BlockStateContainer(this, new IProperty[] {field_176573_b, field_176574_M}); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176574_M); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176574_M) ? MAX_POWER : MIN_POWER; ++ } + } diff --git a/patches/net/minecraft/block/BlockRailPowered.java.patch b/patches/net/minecraft/block/BlockRailPowered.java.patch index 244845d2..8f11ce59 100644 --- a/patches/net/minecraft/block/BlockRailPowered.java.patch +++ b/patches/net/minecraft/block/BlockRailPowered.java.patch @@ -1,15 +1,19 @@ --- ../src-base/minecraft/net/minecraft/block/BlockRailPowered.java +++ ../src-work/minecraft/net/minecraft/block/BlockRailPowered.java -@@ -12,6 +12,8 @@ +@@ -12,7 +12,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +-public class BlockRailPowered extends BlockRailBase ++import redstone.multimeter.block.MeterableBlock; ++ +import carpet.CarpetSettings; + - public class BlockRailPowered extends BlockRailBase ++public class BlockRailPowered extends BlockRailBase implements MeterableBlock /* RSMM */ { public static final PropertyEnum field_176568_b = PropertyEnum.func_177708_a("shape", BlockRailBase.EnumRailDirection.class, new Predicate() -@@ -32,7 +34,11 @@ + { +@@ -32,7 +36,11 @@ @SuppressWarnings("incomplete-switch") protected boolean func_176566_a(World p_176566_1_, BlockPos p_176566_2_, IBlockState p_176566_3_, boolean p_176566_4_, int p_176566_5_) { @@ -22,7 +26,16 @@ { return false; } -@@ -228,6 +234,14 @@ +@@ -184,6 +192,8 @@ + boolean flag = ((Boolean)p_189541_1_.func_177229_b(field_176569_M)).booleanValue(); + boolean flag1 = p_189541_2_.func_175640_z(p_189541_3_) || this.func_176566_a(p_189541_2_, p_189541_3_, p_189541_1_, true, 0) || this.func_176566_a(p_189541_2_, p_189541_3_, p_189541_1_, false, 0); + ++ rsmm$logPowered(p_189541_2_, p_189541_3_, flag1); // RSMM ++ + if (flag1 != flag) + { + p_189541_2_.func_180501_a(p_189541_3_, p_189541_1_.func_177226_a(field_176569_M, Boolean.valueOf(flag1)), 3); +@@ -228,6 +238,14 @@ switch ((BlockRailBase.EnumRailDirection)p_185499_1_.func_177229_b(field_176568_b)) { @@ -37,3 +50,26 @@ case ASCENDING_EAST: return p_185499_1_.func_177226_a(field_176568_b, BlockRailBase.EnumRailDirection.ASCENDING_WEST); case ASCENDING_WEST: +@@ -360,4 +378,22 @@ + { + return new BlockStateContainer(this, new IProperty[] {field_176568_b, field_176569_M}); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return world.func_175640_z(pos) || func_176566_a(world, pos, state, true, 0) || func_176566_a(world, pos, state, false, 0); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176569_M); ++ } + } diff --git a/patches/net/minecraft/block/BlockRedstoneComparator.java.patch b/patches/net/minecraft/block/BlockRedstoneComparator.java.patch index 254bfca4..d055f8b4 100644 --- a/patches/net/minecraft/block/BlockRedstoneComparator.java.patch +++ b/patches/net/minecraft/block/BlockRedstoneComparator.java.patch @@ -27,7 +27,21 @@ { return 2; } -@@ -206,8 +210,32 @@ +@@ -92,9 +96,12 @@ + return tileentity instanceof TileEntityComparator ? ((TileEntityComparator)tileentity).func_145996_a() : 0; + } + ++ // RSMM - capture return value + private int func_176460_j(World p_176460_1_, BlockPos p_176460_2_, IBlockState p_176460_3_) + { +- return p_176460_3_.func_177229_b(field_176463_b) == BlockRedstoneComparator.Mode.SUBTRACT ? Math.max(this.func_176397_f(p_176460_1_, p_176460_2_, p_176460_3_) - this.func_176407_c(p_176460_1_, p_176460_2_, p_176460_3_), 0) : this.func_176397_f(p_176460_1_, p_176460_2_, p_176460_3_); ++ int output = p_176460_3_.func_177229_b(field_176463_b) == BlockRedstoneComparator.Mode.SUBTRACT ? Math.max(this.func_176397_f(p_176460_1_, p_176460_2_, p_176460_3_) - this.func_176407_c(p_176460_1_, p_176460_2_, p_176460_3_), 0) : this.func_176397_f(p_176460_1_, p_176460_2_, p_176460_3_); ++ rsmm$logPowered(p_176460_1_, p_176460_2_, output > MIN_POWER); // RSMM ++ return output; + } + + protected boolean func_176404_e(World p_176404_1_, BlockPos p_176404_2_, IBlockState p_176404_3_) +@@ -206,8 +213,32 @@ { p_176398_1_.func_175654_a(p_176398_2_, this, 2, 0); } @@ -60,7 +74,7 @@ } private void func_176462_k(World p_176462_1_, BlockPos p_176462_2_, IBlockState p_176462_3_) -@@ -249,6 +277,22 @@ +@@ -249,6 +280,22 @@ } this.func_176462_k(p_180650_1_, p_180650_2_, p_180650_3_); @@ -83,3 +97,34 @@ } public void func_176213_c(World p_176213_1_, BlockPos p_176213_2_, IBlockState p_176213_3_) +@@ -319,6 +366,30 @@ + return this.func_176223_P().func_177226_a(field_185512_D, p_180642_8_.func_174811_aO().func_176734_d()).func_177226_a(field_176464_a, Boolean.valueOf(false)).func_177226_a(field_176463_b, BlockRedstoneComparator.Mode.COMPARE); + } + ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return rsmm$getPowerLevel(world, pos, state) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPowerChangeOnStateChange() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ TileEntity blockEntity = world.func_175625_s(pos); ++ ++ if (blockEntity instanceof TileEntityComparator) { ++ return ((TileEntityComparator)blockEntity).func_145996_a(); ++ } ++ ++ return MIN_POWER; ++ } ++ + public static enum Mode implements IStringSerializable + { + COMPARE("compare"), diff --git a/patches/net/minecraft/block/BlockRedstoneDiode.java.patch b/patches/net/minecraft/block/BlockRedstoneDiode.java.patch index fd443639..3dc9d445 100644 --- a/patches/net/minecraft/block/BlockRedstoneDiode.java.patch +++ b/patches/net/minecraft/block/BlockRedstoneDiode.java.patch @@ -1,6 +1,18 @@ --- ../src-base/minecraft/net/minecraft/block/BlockRedstoneDiode.java +++ ../src-work/minecraft/net/minecraft/block/BlockRedstoneDiode.java -@@ -64,7 +64,7 @@ +@@ -13,7 +13,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public abstract class BlockRedstoneDiode extends BlockHorizontal ++import redstone.multimeter.block.MeterableBlock; ++import redstone.multimeter.block.PowerSource; ++ ++public abstract class BlockRedstoneDiode extends BlockHorizontal implements MeterableBlock /* RSMM */, PowerSource /* RSMM */ + { + protected static final AxisAlignedBB field_185548_c = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.125D, 1.0D); + protected final boolean field_149914_a; +@@ -64,7 +67,7 @@ if (!flag) { @@ -9,7 +21,7 @@ } } } -@@ -129,7 +129,7 @@ +@@ -129,7 +132,7 @@ i = -2; } @@ -18,7 +30,21 @@ } } } -@@ -276,12 +276,12 @@ +@@ -139,9 +142,12 @@ + return false; + } + ++ // RSMM - capture return value + protected boolean func_176404_e(World p_176404_1_, BlockPos p_176404_2_, IBlockState p_176404_3_) + { +- return this.func_176397_f(p_176404_1_, p_176404_2_, p_176404_3_) > 0; ++ boolean powered = this.func_176397_f(p_176404_1_, p_176404_2_, p_176404_3_) > 0; ++ rsmm$logPowered(p_176404_1_, p_176404_2_, powered); // RSMM ++ return powered; + } + + protected int func_176397_f(World p_176397_1_, BlockPos p_176397_2_, IBlockState p_176397_3_) +@@ -276,12 +282,12 @@ } } @@ -34,3 +60,26 @@ protected abstract IBlockState func_180674_e(IBlockState p_180674_1_); +@@ -296,4 +302,22 @@ + { + return p_193383_4_ == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return func_176404_e(world, pos, state); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return field_149914_a; ++ } + } diff --git a/patches/net/minecraft/block/BlockRedstoneLight.java.patch b/patches/net/minecraft/block/BlockRedstoneLight.java.patch new file mode 100644 index 00000000..01e29055 --- /dev/null +++ b/patches/net/minecraft/block/BlockRedstoneLight.java.patch @@ -0,0 +1,33 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockRedstoneLight.java ++++ ../src-work/minecraft/net/minecraft/block/BlockRedstoneLight.java +@@ -9,7 +9,9 @@ + import net.minecraft.util.math.BlockPos; + import net.minecraft.world.World; + +-public class BlockRedstoneLight extends Block ++import redstone.multimeter.block.MeterableBlock; ++ ++public class BlockRedstoneLight extends Block implements MeterableBlock /* RSMM */ + { + private final boolean field_150171_a; + +@@ -58,6 +60,8 @@ + { + if (!p_180650_1_.field_72995_K) + { ++ rsmm$logPowered(p_180650_1_, p_180650_2_, p_180650_3_); // RSMM ++ + if (this.field_150171_a && !p_180650_1_.func_175640_z(p_180650_2_)) + { + p_180650_1_.func_180501_a(p_180650_2_, Blocks.field_150379_bu.func_176223_P(), 2); +@@ -79,4 +83,10 @@ + { + return new ItemStack(Blocks.field_150379_bu); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return field_150171_a; ++ } + } diff --git a/patches/net/minecraft/block/BlockRedstoneOre.java.patch b/patches/net/minecraft/block/BlockRedstoneOre.java.patch new file mode 100644 index 00000000..8482e251 --- /dev/null +++ b/patches/net/minecraft/block/BlockRedstoneOre.java.patch @@ -0,0 +1,24 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockRedstoneOre.java ++++ ../src-work/minecraft/net/minecraft/block/BlockRedstoneOre.java +@@ -15,7 +15,9 @@ + import net.minecraft.util.math.BlockPos; + import net.minecraft.world.World; + +-public class BlockRedstoneOre extends Block ++import redstone.multimeter.block.Meterable; ++ ++public class BlockRedstoneOre extends Block implements Meterable /* RSMM */ + { + private final boolean field_150187_a; + +@@ -155,4 +157,10 @@ + { + return new ItemStack(Item.func_150898_a(Blocks.field_150450_ax), 1, this.func_180651_a(p_185473_3_)); + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return field_150187_a; ++ } + } diff --git a/patches/net/minecraft/block/BlockRedstoneRepeater.java.patch b/patches/net/minecraft/block/BlockRedstoneRepeater.java.patch index bb7f8993..ed6a179a 100644 --- a/patches/net/minecraft/block/BlockRedstoneRepeater.java.patch +++ b/patches/net/minecraft/block/BlockRedstoneRepeater.java.patch @@ -1,15 +1,17 @@ --- ../src-base/minecraft/net/minecraft/block/BlockRedstoneRepeater.java +++ ../src-work/minecraft/net/minecraft/block/BlockRedstoneRepeater.java -@@ -20,6 +20,8 @@ +@@ -19,7 +19,10 @@ + import net.minecraft.util.text.translation.I18n; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; ++import net.minecraft.world.WorldServer; +import carpet.CarpetSettings; + public class BlockRedstoneRepeater extends BlockRedstoneDiode { public static final PropertyBool field_176411_a = PropertyBool.func_177716_a("locked"); -@@ -64,9 +66,20 @@ +@@ -64,9 +67,20 @@ } } @@ -32,3 +34,32 @@ } protected IBlockState func_180674_e(IBlockState p_180674_1_) +@@ -95,9 +109,16 @@ + return new ItemStack(Items.field_151107_aW); + } + ++ // RSMM - capture return value + public boolean func_176405_b(IBlockAccess p_176405_1_, BlockPos p_176405_2_, IBlockState p_176405_3_) + { +- return this.func_176407_c(p_176405_1_, p_176405_2_, p_176405_3_) > 0; ++ boolean locked = this.func_176407_c(p_176405_1_, p_176405_2_, p_176405_3_) > 0; ++ // RSMM start ++ if (locked && p_176405_1_ instanceof WorldServer) { ++ rsmm$logPowered((WorldServer)p_176405_1_, p_176405_2_, p_176405_3_); ++ } ++ // RSMM end ++ return locked; + } + + protected boolean func_185545_A(IBlockState p_185545_1_) +@@ -128,4 +149,10 @@ + { + return new BlockStateContainer(this, new IProperty[] {field_185512_D, field_176410_b, field_176411_a}); + } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return field_149914_a ? MAX_POWER : MIN_POWER; ++ } + } diff --git a/patches/net/minecraft/block/BlockRedstoneTorch.java.patch b/patches/net/minecraft/block/BlockRedstoneTorch.java.patch index e6af38eb..1dcf7ef4 100644 --- a/patches/net/minecraft/block/BlockRedstoneTorch.java.patch +++ b/patches/net/minecraft/block/BlockRedstoneTorch.java.patch @@ -1,15 +1,35 @@ --- ../src-base/minecraft/net/minecraft/block/BlockRedstoneTorch.java +++ ../src-work/minecraft/net/minecraft/block/BlockRedstoneTorch.java -@@ -19,6 +19,8 @@ +@@ -19,7 +19,12 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockRedstoneTorch extends BlockTorch ++import redstone.multimeter.block.MeterableBlock; ++import redstone.multimeter.block.PowerSource; ++ +import carpet.CarpetSettings; + - public class BlockRedstoneTorch extends BlockTorch ++public class BlockRedstoneTorch extends BlockTorch implements MeterableBlock /* RSMM */, PowerSource /* RSMM */ { private static final Map> field_150112_b = Maps.>newHashMap(); -@@ -149,7 +151,7 @@ + private final boolean field_150113_a; +@@ -97,10 +102,13 @@ + return this.field_150113_a && p_180656_1_.func_177229_b(field_176596_a) != p_180656_4_ ? 15 : 0; + } + ++ // RSMM - capture return value + private boolean func_176597_g(World p_176597_1_, BlockPos p_176597_2_, IBlockState p_176597_3_) + { + EnumFacing enumfacing = ((EnumFacing)p_176597_3_.func_177229_b(field_176596_a)).func_176734_d(); +- return p_176597_1_.func_175709_b(p_176597_2_.func_177972_a(enumfacing), enumfacing); ++ boolean powered = p_176597_1_.func_175709_b(p_176597_2_.func_177972_a(enumfacing), enumfacing); ++ rsmm$logPowered(p_176597_1_, p_176597_2_, powered); // RSMM ++ return powered; + } + + public void func_180645_a(World p_180645_1_, BlockPos p_180645_2_, IBlockState p_180645_3_, Random p_180645_4_) +@@ -149,7 +157,7 @@ { if (!this.func_176592_e(p_189540_2_, p_189540_3_, p_189540_1_)) { @@ -18,3 +38,34 @@ { p_189540_2_.func_175684_a(p_189540_3_, this, this.func_149738_a(p_189540_2_)); } +@@ -181,6 +189,30 @@ + return p_149667_1_ == Blocks.field_150437_az || p_149667_1_ == Blocks.field_150429_aA; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return func_176597_g(world, pos, state); ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return field_150113_a; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return field_150113_a ? MAX_POWER : MIN_POWER; ++ } ++ + static class Toggle + { + BlockPos field_180111_a; diff --git a/patches/net/minecraft/block/BlockRedstoneWire.java.patch b/patches/net/minecraft/block/BlockRedstoneWire.java.patch index 7c026b3e..e2b98743 100644 --- a/patches/net/minecraft/block/BlockRedstoneWire.java.patch +++ b/patches/net/minecraft/block/BlockRedstoneWire.java.patch @@ -7,18 +7,23 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.EnumSet; -@@ -27,6 +28,10 @@ +@@ -27,7 +28,14 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +-public class BlockRedstoneWire extends Block ++import redstone.multimeter.block.MeterableBlock; ++import redstone.multimeter.block.PowerSource; ++ +import carpet.CarpetSettings; +import carpet.helpers.RedstoneWireTurbo; +import java.util.Collections; + - public class BlockRedstoneWire extends Block ++public class BlockRedstoneWire extends Block implements MeterableBlock /* RSMM */, PowerSource /* RSMM */ { public static final PropertyEnum field_176348_a = PropertyEnum.func_177709_a("north", BlockRedstoneWire.EnumAttachPosition.class); -@@ -35,9 +40,11 @@ + public static final PropertyEnum field_176347_b = PropertyEnum.func_177709_a("east", BlockRedstoneWire.EnumAttachPosition.class); +@@ -35,9 +43,11 @@ public static final PropertyEnum field_176350_N = PropertyEnum.func_177709_a("west", BlockRedstoneWire.EnumAttachPosition.class); public static final PropertyInteger field_176351_O = PropertyInteger.func_177719_a("power", 0, 15); protected static final AxisAlignedBB[] field_185700_f = new AxisAlignedBB[] {new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.8125D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.1875D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.1875D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 0.8125D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D)}; @@ -31,7 +36,7 @@ public BlockRedstoneWire() { super(Material.field_151594_q); -@@ -142,21 +149,26 @@ +@@ -142,21 +152,26 @@ return p_176196_1_.func_180495_p(p_176196_2_.func_177977_b()).func_185896_q() || p_176196_1_.func_180495_p(p_176196_2_.func_177977_b()).func_177230_c() == Blocks.field_150426_aN; } @@ -63,7 +68,7 @@ { IBlockState iblockstate = p_176345_4_; int i = ((Integer)p_176345_4_.func_177229_b(field_176351_O)).intValue(); -@@ -166,54 +178,65 @@ +@@ -166,53 +181,66 @@ int k = p_176345_1_.func_175687_A(p_176345_2_); this.field_150181_a = true; @@ -157,11 +162,11 @@ - { - j = k; - } -- ++ rsmm$logPowered(p_176345_1_, p_176345_2_, j > MIN_POWER); // RSMM + if (i != j) { - p_176345_4_ = p_176345_4_.func_177226_a(field_176351_O, Integer.valueOf(j)); -@@ -223,11 +246,15 @@ +@@ -223,11 +251,15 @@ p_176345_1_.func_180501_a(p_176345_2_, p_176345_4_, 2); } @@ -181,7 +186,7 @@ } } -@@ -251,7 +278,7 @@ +@@ -251,7 +283,7 @@ { if (!p_176213_1_.field_72995_K) { @@ -190,7 +195,7 @@ for (EnumFacing enumfacing : EnumFacing.Plane.VERTICAL) { -@@ -290,7 +317,7 @@ +@@ -290,7 +322,7 @@ p_180663_1_.func_175685_c(p_180663_2_.func_177972_a(enumfacing), this, false); } @@ -199,7 +204,7 @@ for (EnumFacing enumfacing1 : EnumFacing.Plane.HORIZONTAL) { -@@ -332,7 +359,7 @@ +@@ -332,7 +364,7 @@ { if (this.func_176196_c(p_189540_2_, p_189540_3_)) { @@ -208,7 +213,7 @@ } else { -@@ -354,6 +381,12 @@ +@@ -354,6 +386,12 @@ public int func_180656_a(IBlockState p_180656_1_, IBlockAccess p_180656_2_, BlockPos p_180656_3_, EnumFacing p_180656_4_) { @@ -221,7 +226,7 @@ if (!this.field_150181_a) { return 0; -@@ -361,6 +394,8 @@ +@@ -361,6 +399,8 @@ else { int i = ((Integer)p_180656_1_.func_177229_b(field_176351_O)).intValue(); @@ -230,7 +235,7 @@ if (i == 0) { -@@ -398,7 +433,8 @@ +@@ -398,7 +438,8 @@ } } @@ -240,7 +245,7 @@ { BlockPos blockpos = p_176339_2_.func_177972_a(p_176339_3_); IBlockState iblockstate = p_176339_1_.func_180495_p(blockpos); -@@ -435,6 +471,12 @@ +@@ -435,6 +476,12 @@ protected static boolean func_176343_a(IBlockState p_176343_0_, @Nullable EnumFacing p_176343_1_) { @@ -253,3 +258,37 @@ Block block = p_176343_0_.func_177230_c(); if (block == Blocks.field_150488_af) +@@ -514,6 +561,33 @@ + return BlockFaceShape.UNDEFINED; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ // This method is only called on blocks where 'logPoweredOnBlockUpdate' ++ // returns 'true', so it does not really matter that a potentially ++ // incorrect value is returned. ++ @Override ++ public boolean rsmm$isPowered(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176351_O) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176351_O) > MIN_POWER; ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176351_O); ++ } ++ + static enum EnumAttachPosition implements IStringSerializable + { + UP("up"), diff --git a/patches/net/minecraft/block/BlockTrapDoor.java.patch b/patches/net/minecraft/block/BlockTrapDoor.java.patch new file mode 100644 index 00000000..36e82c6d --- /dev/null +++ b/patches/net/minecraft/block/BlockTrapDoor.java.patch @@ -0,0 +1,41 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockTrapDoor.java ++++ ../src-work/minecraft/net/minecraft/block/BlockTrapDoor.java +@@ -22,7 +22,9 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockTrapDoor extends Block ++import redstone.multimeter.block.MeterableBlock; ++ ++public class BlockTrapDoor extends Block implements MeterableBlock /* RSMM */ + { + public static final PropertyDirection field_176284_a = BlockHorizontal.field_185512_D; + public static final PropertyBool field_176283_b = PropertyBool.func_177716_a("open"); +@@ -125,6 +127,8 @@ + { + boolean flag = p_189540_2_.func_175640_z(p_189540_3_); + ++ rsmm$logPowered(p_189540_2_, p_189540_3_, flag); // RSMM ++ + if (flag || p_189540_4_.func_176223_P().func_185897_m()) + { + boolean flag1 = ((Boolean)p_189540_1_.func_177229_b(field_176283_b)).booleanValue(); +@@ -241,6 +245,18 @@ + return (p_193383_4_ == EnumFacing.UP && p_193383_2_.func_177229_b(field_176285_M) == BlockTrapDoor.DoorHalf.TOP || p_193383_4_ == EnumFacing.DOWN && p_193383_2_.func_177229_b(field_176285_M) == BlockTrapDoor.DoorHalf.BOTTOM) && !((Boolean)p_193383_2_.func_177229_b(field_176283_b)).booleanValue() ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; + } + ++ // RSMM ++ @Override ++ public boolean rsmm$logPoweredOnBlockUpdate() { ++ return false; ++ } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176283_b); ++ } ++ + public static enum DoorHalf implements IStringSerializable + { + TOP("top"), diff --git a/patches/net/minecraft/block/BlockTripWire.java.patch b/patches/net/minecraft/block/BlockTripWire.java.patch new file mode 100644 index 00000000..bb1d167a --- /dev/null +++ b/patches/net/minecraft/block/BlockTripWire.java.patch @@ -0,0 +1,24 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockTripWire.java ++++ ../src-work/minecraft/net/minecraft/block/BlockTripWire.java +@@ -23,7 +23,9 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockTripWire extends Block ++import redstone.multimeter.block.Meterable; ++ ++public class BlockTripWire extends Block implements Meterable /* RSMM */ + { + public static final PropertyBool field_176293_a = PropertyBool.func_177716_a("powered"); + public static final PropertyBool field_176294_M = PropertyBool.func_177716_a("attached"); +@@ -266,4 +268,10 @@ + { + return BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176293_a); ++ } + } diff --git a/patches/net/minecraft/block/BlockTripWireHook.java.patch b/patches/net/minecraft/block/BlockTripWireHook.java.patch new file mode 100644 index 00000000..f96acdac --- /dev/null +++ b/patches/net/minecraft/block/BlockTripWireHook.java.patch @@ -0,0 +1,31 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockTripWireHook.java ++++ ../src-work/minecraft/net/minecraft/block/BlockTripWireHook.java +@@ -25,7 +25,10 @@ + import net.minecraft.world.IBlockAccess; + import net.minecraft.world.World; + +-public class BlockTripWireHook extends Block ++import redstone.multimeter.block.Meterable; ++import redstone.multimeter.block.PowerSource; ++ ++public class BlockTripWireHook extends Block implements Meterable /* RSMM */, PowerSource /* RSMM */ + { + public static final PropertyDirection field_176264_a = BlockHorizontal.field_185512_D; + public static final PropertyBool field_176263_b = PropertyBool.func_177716_a("powered"); +@@ -353,4 +356,16 @@ + { + return BlockFaceShape.UNDEFINED; + } ++ ++ // RSMM ++ @Override ++ public boolean rsmm$isActive(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176263_b); ++ } ++ ++ // RSMM ++ @Override ++ public int rsmm$getPowerLevel(World world, BlockPos pos, IBlockState state) { ++ return state.func_177229_b(field_176263_b) ? MAX_POWER : MIN_POWER; ++ } + } diff --git a/patches/net/minecraft/command/CommandFill.java.patch b/patches/net/minecraft/command/CommandFill.java.patch index dcb35dc4..2881f671 100644 --- a/patches/net/minecraft/command/CommandFill.java.patch +++ b/patches/net/minecraft/command/CommandFill.java.patch @@ -49,14 +49,16 @@ } else if ("keep".equals(p_184881_3_[8])) { -@@ -137,6 +152,7 @@ +@@ -137,7 +152,8 @@ { if ("hollow".equals(p_184881_3_[8])) { +- world.func_180501_a(blockpos4, Blocks.field_150350_a.func_176223_P(), 2); + WorldEditBridge.recordBlockEdit(worldEditPlayer, world, blockpos4, Blocks.field_150350_a.func_176223_P(), worldEditTag); - world.func_180501_a(blockpos4, Blocks.field_150350_a.func_176223_P(), 2); ++ world.func_180501_a(blockpos4, Blocks.field_150350_a.func_176223_P(), 2 | (CarpetSettings.fillUpdates?0:128)); // CM list.add(blockpos4); } + @@ -145,6 +161,7 @@ } } diff --git a/patches/net/minecraft/command/CommandTP.java.patch b/patches/net/minecraft/command/CommandTP.java.patch index bd3825ad..e88950da 100644 --- a/patches/net/minecraft/command/CommandTP.java.patch +++ b/patches/net/minecraft/command/CommandTP.java.patch @@ -1,6 +1,15 @@ --- ../src-base/minecraft/net/minecraft/command/CommandTP.java +++ ../src-work/minecraft/net/minecraft/command/CommandTP.java -@@ -13,6 +13,10 @@ +@@ -5,6 +5,8 @@ + import java.util.List; + import java.util.Set; + import javax.annotation.Nullable; ++ ++import carpet.helpers.TeleportHelper; + import net.minecraft.entity.Entity; + import net.minecraft.entity.EntityLivingBase; + import net.minecraft.entity.player.EntityPlayerMP; +@@ -13,6 +15,10 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; @@ -11,7 +20,7 @@ public class CommandTP extends CommandBase { public String func_71517_b() -@@ -38,6 +42,17 @@ +@@ -38,6 +44,17 @@ } else { @@ -29,3 +38,18 @@ int i = 0; Entity entity; +@@ -73,7 +90,13 @@ + else + { + Entity entity1 = func_184885_b(p_184881_1_, p_184881_2_, p_184881_3_[p_184881_3_.length - 1]); +- ++ // CM ++ if(CarpetSettings.tpAcrossDimensions && (entity1.field_70170_p != entity.field_70170_p)){ ++ if(entity1 instanceof EntityPlayerMP && entity instanceof EntityPlayerMP){ ++ TeleportHelper.changeDimensions((EntityPlayerMP) entity, (EntityPlayerMP) entity1); ++ } ++ } ++ // CM END + if (entity1.field_70170_p != entity.field_70170_p) + { + throw new CommandException("commands.tp.notSameDimension", new Object[0]); diff --git a/patches/net/minecraft/entity/item/EntityTNTPrimed.java.patch b/patches/net/minecraft/entity/item/EntityTNTPrimed.java.patch index 998a627a..58ced6aa 100644 --- a/patches/net/minecraft/entity/item/EntityTNTPrimed.java.patch +++ b/patches/net/minecraft/entity/item/EntityTNTPrimed.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/entity/item/EntityTNTPrimed.java +++ ../src-work/minecraft/net/minecraft/entity/item/EntityTNTPrimed.java -@@ -11,17 +11,36 @@ +@@ -11,17 +11,43 @@ import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; @@ -32,13 +32,20 @@ { super(p_i1729_1_); - this.field_70516_a = 80; ++ ++ if (LoggerRegistry.__tnt && logHelper == null) ++ { ++ logHelper = new TNTLogHelper(); ++ logHelper.onPrimed(this.field_70165_t,this.field_70163_u,this.field_70161_v,0); ++ } ++ + this.field_70516_a = CarpetSettings.tntFuseLength; //CM Vanilla default is 80gt + mergedTNT = 1; + mergeBool = false; this.field_70156_m = true; this.field_70178_ae = true; this.func_70105_a(0.98F, 0.98F); -@@ -31,11 +50,27 @@ +@@ -31,11 +57,27 @@ { this(p_i1730_1_); this.func_70107_b(p_i1730_2_, p_i1730_4_, p_i1730_6_); @@ -71,7 +78,7 @@ this.field_70169_q = p_i1730_2_; this.field_70167_r = p_i1730_4_; this.field_70166_s = p_i1730_6_; -@@ -68,18 +103,73 @@ +@@ -68,18 +110,73 @@ this.field_70181_x -= 0.03999999910593033D; } @@ -146,7 +153,7 @@ --this.field_70516_a; if (this.field_70516_a <= 0) -@@ -100,8 +190,14 @@ +@@ -100,8 +197,14 @@ private void func_70515_d() { @@ -162,7 +169,7 @@ } protected void func_70014_b(NBTTagCompound p_70014_1_) -@@ -148,4 +244,12 @@ +@@ -148,4 +251,12 @@ { return this.field_70516_a; } diff --git a/patches/net/minecraft/init/Bootstrap.java.patch b/patches/net/minecraft/init/Bootstrap.java.patch index c0803902..0e1fa9e0 100644 --- a/patches/net/minecraft/init/Bootstrap.java.patch +++ b/patches/net/minecraft/init/Bootstrap.java.patch @@ -21,7 +21,15 @@ import net.minecraft.block.BlockLiquid; import net.minecraft.block.BlockPumpkin; import net.minecraft.block.BlockShulkerBox; -@@ -58,11 +64,7 @@ +@@ -16,6 +22,7 @@ + import net.minecraft.block.BlockTNT; + import net.minecraft.block.material.Material; + import net.minecraft.block.state.IBlockState; ++import net.minecraft.crash.CrashReport; + import net.minecraft.dispenser.BehaviorDefaultDispenseItem; + import net.minecraft.dispenser.BehaviorProjectileDispense; + import net.minecraft.dispenser.IBehaviorDispenseItem; +@@ -58,11 +65,7 @@ import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.tileentity.TileEntityShulkerBox; import net.minecraft.tileentity.TileEntitySkull; @@ -34,7 +42,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; -@@ -476,6 +478,9 @@ +@@ -476,6 +479,9 @@ } }); @@ -44,3 +52,14 @@ for (EnumDyeColor enumdyecolor : EnumDyeColor.values()) { BlockDispenser.field_149943_a.func_82595_a(Item.func_150898_a(BlockShulkerBox.func_190952_a(enumdyecolor)), new Bootstrap.BehaviorDispenseShulkerBox()); +@@ -486,6 +492,10 @@ + { + if (!field_151355_a) + { ++ // Fix the crash report without carpet rule. DON'T PUT A GOD-DAMN CARPET RULE FOR THIS OR I WILL GET MAD! ++ // Mojang even added this in 16. CARPET-XCOM ++ CrashReport.func_85055_a(new Exception(), "Dummy"); ++ + field_151355_a = true; + func_179868_d(); + SoundEvent.func_187504_b(); diff --git a/patches/net/minecraft/inventory/ItemStackHelper.java.patch b/patches/net/minecraft/inventory/ItemStackHelper.java.patch new file mode 100644 index 00000000..31bb7f67 --- /dev/null +++ b/patches/net/minecraft/inventory/ItemStackHelper.java.patch @@ -0,0 +1,25 @@ +--- ../src-base/minecraft/net/minecraft/inventory/ItemStackHelper.java ++++ ../src-work/minecraft/net/minecraft/inventory/ItemStackHelper.java +@@ -6,6 +6,9 @@ + import net.minecraft.nbt.NBTTagList; + import net.minecraft.util.NonNullList; + ++import carpet.CarpetSettings; ++import carpet.helpers.SaveSavestatesHelper; ++ + public class ItemStackHelper + { + public static ItemStack func_188382_a(List p_188382_0_, int p_188382_1_, int p_188382_2_) +@@ -25,6 +28,12 @@ + + public static NBTTagCompound func_191281_a(NBTTagCompound p_191281_0_, NonNullList p_191281_1_, boolean p_191281_2_) + { ++ if (CarpetSettings.saveSavestates) ++ { ++ SaveSavestatesHelper.trySaveItemsCompressed(p_191281_0_, p_191281_1_, p_191281_2_); ++ return p_191281_0_; ++ } ++ + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < p_191281_1_.size(); ++i) diff --git a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch index f9a06fc1..c8f9f3e1 100644 --- a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -15,7 +15,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.CommandBlockBaseLogic; import net.minecraft.tileentity.TileEntity; -@@ -121,15 +123,24 @@ +@@ -121,15 +123,26 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,6 +26,8 @@ +import net.minecraft.world.gen.structure.template.Template; +import net.minecraft.server.management.PlayerInteractionManager; + ++import redstone.multimeter.common.network.Packets; ++ +import static carpet.commands.CommandGMS.setPlayerToSurvival; + public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable @@ -48,7 +50,7 @@ private long field_194404_h; private int field_147374_l; private int field_147375_m; -@@ -257,9 +268,19 @@ +@@ -257,9 +270,19 @@ { this.func_194028_b(new TextComponentTranslation("multiplayer.disconnect.idling", new Object[0])); } @@ -69,7 +71,7 @@ { this.field_184349_l = this.field_147369_b.field_70165_t; this.field_184350_m = this.field_147369_b.field_70163_u; -@@ -297,6 +318,11 @@ +@@ -297,6 +320,11 @@ { PacketThreadUtil.func_180031_a(p_147358_1_, this, this.field_147369_b.func_71121_q()); this.field_147369_b.func_110430_a(p_147358_1_.func_149620_c(), p_147358_1_.func_192620_b(), p_147358_1_.func_149618_e(), p_147358_1_.func_149617_f()); @@ -81,7 +83,7 @@ } private static boolean func_183006_b(CPacketPlayer p_183006_0_) -@@ -500,6 +526,10 @@ +@@ -500,6 +528,10 @@ double d10 = this.field_147369_b.field_70159_w * this.field_147369_b.field_70159_w + this.field_147369_b.field_70181_x * this.field_147369_b.field_70181_x + this.field_147369_b.field_70179_y * this.field_147369_b.field_70179_y; double d11 = d7 * d7 + d8 * d8 + d9 * d9; @@ -92,7 +94,7 @@ if (this.field_147369_b.func_70608_bn()) { if (d11 > 1.0D) -@@ -518,7 +548,7 @@ +@@ -518,7 +550,7 @@ i = 1; } @@ -101,7 +103,7 @@ { float f2 = this.field_147369_b.func_184613_cA() ? 300.0F : 100.0F; -@@ -564,7 +594,9 @@ +@@ -564,7 +596,9 @@ this.field_147369_b.func_70080_a(d4, d5, d6, f, f1); this.field_147369_b.func_71000_j(this.field_147369_b.field_70165_t - d0, this.field_147369_b.field_70163_u - d1, this.field_147369_b.field_70161_v - d2); @@ -112,7 +114,7 @@ { boolean flag1 = worldserver.func_184144_a(this.field_147369_b, this.field_147369_b.func_174813_aQ().func_186664_h(0.0625D)).isEmpty(); -@@ -627,6 +659,8 @@ +@@ -627,6 +661,8 @@ public void func_147345_a(CPacketPlayerDigging p_147345_1_) { @@ -121,7 +123,7 @@ PacketThreadUtil.func_180031_a(p_147345_1_, this, this.field_147369_b.func_71121_q()); WorldServer worldserver = this.field_147367_d.func_71218_a(this.field_147369_b.field_71093_bK); BlockPos blockpos = p_147345_1_.func_179715_a(); -@@ -731,7 +765,10 @@ +@@ -731,7 +767,10 @@ { if (this.field_184362_y == null && this.field_147369_b.func_70092_e((double)blockpos.func_177958_n() + 0.5D, (double)blockpos.func_177956_o() + 0.5D, (double)blockpos.func_177952_p() + 0.5D) < 64.0D && !this.field_147367_d.func_175579_a(worldserver, blockpos, this.field_147369_b) && worldserver.func_175723_af().func_177746_a(blockpos)) { @@ -132,7 +134,7 @@ } } else -@@ -755,12 +792,16 @@ +@@ -755,12 +794,16 @@ if (!itemstack.func_190926_b()) { @@ -149,7 +151,7 @@ PacketThreadUtil.func_180031_a(p_175088_1_, this, this.field_147369_b.func_71121_q()); if (this.field_147369_b.func_175149_v()) -@@ -796,13 +837,13 @@ +@@ -796,13 +839,13 @@ this.field_147369_b.field_71093_bK = entity.field_71093_bK; this.func_147359_a(new SPacketRespawn(this.field_147369_b.field_71093_bK, worldserver1.func_175659_aa(), worldserver1.func_72912_H().func_76067_t(), this.field_147369_b.field_71134_c.func_73081_b())); this.field_147367_d.func_184103_al().func_187243_f(this.field_147369_b); @@ -165,7 +167,7 @@ worldserver2.func_72838_d(this.field_147369_b); worldserver2.func_72866_a(this.field_147369_b, false); } -@@ -841,6 +882,11 @@ +@@ -841,6 +884,11 @@ textcomponenttranslation.func_150256_b().func_150238_a(TextFormatting.YELLOW); this.field_147367_d.func_184103_al().func_148539_a(textcomponenttranslation); this.field_147369_b.func_71123_m(); @@ -177,7 +179,7 @@ this.field_147367_d.func_184103_al().func_72367_e(this.field_147369_b); if (this.field_147367_d.func_71264_H() && this.field_147369_b.func_70005_c_().equals(this.field_147367_d.func_71214_G())) -@@ -1019,13 +1065,15 @@ +@@ -1019,13 +1067,15 @@ break; case START_FALL_FLYING: @@ -198,7 +200,7 @@ } } else -@@ -1147,11 +1195,15 @@ +@@ -1147,11 +1197,15 @@ } else { @@ -214,7 +216,7 @@ this.field_147369_b.field_71137_h = true; this.field_147369_b.field_71070_bA.func_75142_b(); this.field_147369_b.func_71113_k(); -@@ -1355,7 +1407,27 @@ +@@ -1355,8 +1409,33 @@ PacketThreadUtil.func_180031_a(p_147349_1_, this, this.field_147369_b.func_71121_q()); String s = p_147349_1_.func_149559_c(); @@ -239,11 +241,17 @@ + } + PlayerInteractionManager.activateInstantMine = true; + } -+ else if ("MC|BEdit".equals(s)) ++ // RSMM packet handling ++ else if (Packets.getChannel().equals(s)) { ++ CarpetServer.rsmmServer.getPacketHandler().handlePacket(p_147349_1_.func_180760_b(), field_147369_b); ++ } ++ else if ("MC|BEdit".equals(s)) ++ { PacketBuffer packetbuffer = p_147349_1_.func_180760_b(); -@@ -1666,13 +1738,14 @@ + try +@@ -1666,13 +1745,14 @@ String s8 = packetbuffer5.func_150789_c(32); tileentitystructure.func_184405_a(TileEntityStructure.Mode.valueOf(s8)); tileentitystructure.func_184404_a(packetbuffer5.func_150789_c(64)); @@ -264,7 +272,7 @@ tileentitystructure.func_184409_c(new BlockPos(l2, i3, j)); String s2 = packetbuffer5.func_150789_c(32); tileentitystructure.func_184411_a(Mirror.valueOf(s2)); -@@ -1709,6 +1782,17 @@ +@@ -1709,6 +1789,17 @@ } else { @@ -282,7 +290,7 @@ this.field_147369_b.func_146105_b(new TextComponentTranslation("structure_block.load_prepare", new Object[] {s4}), false); } } -@@ -1750,5 +1834,9 @@ +@@ -1750,5 +1841,9 @@ field_147370_c.error("Couldn't pick item", (Throwable)exception); } } diff --git a/patches/net/minecraft/server/MinecraftServer.java.patch b/patches/net/minecraft/server/MinecraftServer.java.patch index 00660e02..5197bbd9 100644 --- a/patches/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/net/minecraft/server/MinecraftServer.java.patch @@ -9,7 +9,15 @@ import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.google.common.util.concurrent.Futures; -@@ -86,6 +89,15 @@ +@@ -82,10 +85,23 @@ + import net.minecraft.world.storage.ISaveFormat; + import net.minecraft.world.storage.ISaveHandler; + import net.minecraft.world.storage.WorldInfo; ++ ++import redstone.multimeter.common.TickTask; ++import redstone.multimeter.helper.WorldHelper; ++ + import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -25,7 +33,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable, IThreadListener, ISnooperInfo { private static final Logger field_147145_h = LogManager.getLogger(); -@@ -144,6 +156,7 @@ +@@ -144,6 +160,7 @@ public MinecraftServer(File p_i47054_1_, Proxy p_i47054_2_, DataFixer p_i47054_3_, YggdrasilAuthenticationService p_i47054_4_, MinecraftSessionService p_i47054_5_, GameProfileRepository p_i47054_6_, PlayerProfileCache p_i47054_7_) { @@ -33,7 +41,7 @@ this.field_110456_c = p_i47054_2_; this.field_152364_T = p_i47054_4_; this.field_147143_S = p_i47054_5_; -@@ -273,7 +286,9 @@ +@@ -273,7 +290,9 @@ this.field_71318_t.func_72364_a(this.field_71305_c); this.func_147139_a(this.func_147135_j()); @@ -43,7 +51,7 @@ } protected void func_71222_d() -@@ -285,25 +300,32 @@ +@@ -285,29 +304,38 @@ int i1 = 0; this.func_71192_d("menu.generatingTerrain"); int j1 = 0; @@ -91,7 +99,13 @@ } } -@@ -341,7 +363,7 @@ + this.func_71243_i(); ++ ++ CarpetServer.rsmmServer.worldLoaded(); // RSMM + } + + protected void func_175584_a(String p_175584_1_, ISaveHandler p_175584_2_) +@@ -341,7 +369,7 @@ public abstract boolean func_183002_r(); @@ -100,7 +114,7 @@ { this.field_71302_d = p_71216_1_; this.field_71303_e = p_71216_2_; -@@ -375,6 +397,7 @@ +@@ -375,6 +403,7 @@ } } } @@ -108,7 +122,7 @@ } protected void func_71260_j() -@@ -389,6 +412,8 @@ +@@ -389,6 +418,8 @@ if (this.field_71318_t != null) { field_147145_h.info("Saving players"); @@ -117,7 +131,7 @@ this.field_71318_t.func_72389_g(); this.field_71318_t.func_72392_r(); } -@@ -450,18 +475,33 @@ +@@ -450,18 +481,33 @@ { this.field_175591_ab = func_130071_aq(); long i = 0L; @@ -153,7 +167,7 @@ j = 2000L; this.field_71299_R = this.field_175591_ab; } -@@ -474,6 +514,7 @@ +@@ -474,6 +520,7 @@ i += j; this.field_175591_ab = k; @@ -161,7 +175,7 @@ if (this.field_71305_c[0].func_73056_e()) { -@@ -482,14 +523,33 @@ +@@ -482,14 +529,33 @@ } else { @@ -198,20 +212,28 @@ this.field_71296_Q = true; } } -@@ -594,6 +654,12 @@ +@@ -592,8 +658,19 @@ + protected void func_71217_p() + { long i = System.nanoTime(); - ++this.field_71315_w; +- ++this.field_71315_w; ++ if (TickSpeed.process_entities){ // CM ++ ++this.field_71315_w; ++ } + CarpetServer.tick(this); + if (CarpetProfiler.tick_health_requested != 0L) + { + CarpetProfiler.start_tick_profiling(); + } ++ ++ CarpetServer.rsmmServer.tickStart(); // RSMM ++ WorldHelper.startTickTask(TickTask.TICK); // RSMM + if (this.field_71295_T) { this.field_71295_T = false; -@@ -620,13 +686,21 @@ +@@ -620,13 +697,23 @@ this.field_147147_p.func_151318_b().func_151330_a(agameprofile); } @@ -220,6 +242,7 @@ { + CarpetProfiler.start_section(null, "Autosave"); this.field_71304_b.func_76320_a("save"); ++ WorldHelper.startTickTask(TickTask.AUTOSAVE); // RSMM + this.field_71318_t.storeFakePlayerData(); this.field_71318_t.func_72389_g(); + if(carpet.carpetclient.CarpetClientChunkLogger.logger.enabled) @@ -227,17 +250,21 @@ this.func_71267_a(true); + carpet.carpetclient.CarpetClientChunkLogger.resetReason(); this.field_71304_b.func_76319_b(); ++ WorldHelper.endTickTask(); // RSMM + CarpetProfiler.end_current_section(); } + LagSpikeHelper.processLagSpikes(null, LagSpikeHelper.TickPhase.AUTOSAVE, LagSpikeHelper.PrePostSubPhase.POST); this.field_71304_b.func_76320_a("tallying"); this.field_71311_j[this.field_71315_w % 100] = System.nanoTime() - i; -@@ -645,12 +719,30 @@ +@@ -645,12 +732,34 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76319_b(); + ++ WorldHelper.endTickTask(); // RSMM ++ CarpetServer.rsmmServer.tickEnd(); // RSMM ++ + // ChunkLogger - 0x-CARPET + if(CarpetClientChunkLogger.logger.enabled) { + CarpetClientChunkLogger.logger.sendAll(); @@ -259,20 +286,24 @@ { + LagSpikeHelper.processLagSpikes(null, LagSpikeHelper.TickPhase.TICK, LagSpikeHelper.PrePostSubPhase.PRE); this.field_71304_b.func_76320_a("jobs"); ++ WorldHelper.startTickTask(TickTask.PACKETS); // RSMM + LagSpikeHelper.processLagSpikes(null, LagSpikeHelper.TickPhase.PLAYER, LagSpikeHelper.PrePostSubPhase.PRE); synchronized (this.field_175589_i) { while (!this.field_175589_i.isEmpty()) -@@ -658,6 +750,7 @@ +@@ -658,8 +767,10 @@ Util.func_181617_a(this.field_175589_i.poll(), field_147145_h); } } + LagSpikeHelper.processLagSpikes(null, LagSpikeHelper.TickPhase.PLAYER, LagSpikeHelper.PrePostSubPhase.POST); this.field_71304_b.func_76318_c("levels"); ++ WorldHelper.swapTickTask(TickTask.LEVELS); // RSMM -@@ -672,6 +765,7 @@ + for (int j = 0; j < this.field_71305_c.length; ++j) + { +@@ -672,6 +783,7 @@ { return worldserver.func_72912_H().func_76065_j(); }); @@ -280,7 +311,7 @@ if (this.field_71315_w % 20 == 0) { -@@ -686,27 +780,44 @@ +@@ -686,27 +798,46 @@ { worldserver.func_72835_b(); } @@ -302,7 +333,9 @@ try { ++ WorldHelper.startTickTask(TickTask.ENTITIES); // RSMM worldserver.func_72939_s(); ++ WorldHelper.endTickTask(); // RSMM } + catch (ThrowableSuppression e) + { @@ -327,29 +360,37 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76319_b(); } -@@ -714,10 +825,12 @@ +@@ -714,13 +845,19 @@ this.field_71312_k[j][this.field_71315_w % 100] = System.nanoTime() - i; } + CarpetProfiler.start_section(null, "Network"); this.field_71304_b.func_76318_c("connection"); ++ WorldHelper.swapTickTask(TickTask.CONNECTIONS); // RSMM this.func_147137_ag().func_151269_c(); this.field_71304_b.func_76318_c("players"); ++ WorldHelper.swapTickTask(TickTask.PLAYER_PING); // RSMM this.field_71318_t.func_72374_b(); + CarpetProfiler.end_current_section(); this.field_71304_b.func_76318_c("commandFunctions"); ++ WorldHelper.swapTickTask(TickTask.COMMAND_FUNCTIONS); // RSMM this.func_193030_aL().func_73660_a(); this.field_71304_b.func_76318_c("tickables"); -@@ -728,6 +841,8 @@ ++ WorldHelper.swapTickTask(TickTask.SERVER_GUI); // RSMM + + for (int k = 0; k < this.field_71322_p.size(); ++k) + { +@@ -728,6 +865,9 @@ } this.field_71304_b.func_76319_b(); ++ WorldHelper.endTickTask(); // RSMM + + PistonFixes.onEndTick(); } public boolean func_71255_r() -@@ -939,7 +1054,7 @@ +@@ -939,7 +1079,7 @@ public String getServerModName() { @@ -358,3 +399,11 @@ } public CrashReport func_71230_b(CrashReport p_71230_1_) +@@ -1512,6 +1652,7 @@ + { + if (this.func_152345_ab()) + { ++ CarpetServer.rsmmServer.getMultimeter().reloadOptions(); // RSMM + this.func_184103_al().func_72389_g(); + this.field_71305_c[0].func_184146_ak().func_186522_a(); + this.func_191949_aK().func_192779_a(); diff --git a/patches/net/minecraft/server/management/PlayerChunkMap.java.patch b/patches/net/minecraft/server/management/PlayerChunkMap.java.patch index 18894b78..73f12699 100644 --- a/patches/net/minecraft/server/management/PlayerChunkMap.java.patch +++ b/patches/net/minecraft/server/management/PlayerChunkMap.java.patch @@ -11,7 +11,21 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -@@ -215,9 +217,17 @@ +@@ -129,6 +131,13 @@ + this.field_72697_d.clear(); + } + ++ // Fix for chunks not updating after async updates CARPET-PUNCHSTER ++ if(CarpetSettings.asyncPacketUpdatesFix) { ++ for(PlayerChunkMapEntry entry : field_111193_e){ ++ entry.field_187287_g = 0; ++ } ++ } ++ + if (this.field_187312_l && i % 4L == 0L) + { + this.field_187312_l = false; +@@ -215,9 +224,17 @@ if (!worldprovider.func_76567_e()) { @@ -29,7 +43,7 @@ } public boolean func_152621_a(int p_152621_1_, int p_152621_2_) -@@ -232,20 +242,22 @@ +@@ -232,20 +249,22 @@ return (PlayerChunkMapEntry)this.field_72700_c.get(func_187307_d(p_187301_1_, p_187301_2_)); } @@ -57,7 +71,7 @@ } if (!playerchunkmapentry.func_187272_b()) -@@ -271,8 +283,16 @@ +@@ -271,8 +290,16 @@ public void func_72683_a(EntityPlayerMP p_72683_1_) { @@ -76,7 +90,7 @@ p_72683_1_.field_71131_d = p_72683_1_.field_70165_t; p_72683_1_.field_71132_e = p_72683_1_.field_70161_v; -@@ -280,7 +300,7 @@ +@@ -280,7 +307,7 @@ { for (int l = j - this.field_72698_e; l <= j + this.field_72698_e; ++l) { @@ -85,7 +99,7 @@ } } -@@ -290,8 +310,16 @@ +@@ -290,8 +317,16 @@ public void func_72695_c(EntityPlayerMP p_72695_1_) { @@ -104,7 +118,7 @@ for (int k = i - this.field_72698_e; k <= i + this.field_72698_e; ++k) { -@@ -327,16 +355,32 @@ +@@ -327,16 +362,32 @@ public void func_72685_d(EntityPlayerMP p_72685_1_) { @@ -141,7 +155,7 @@ int i1 = this.field_72698_e; int j1 = i - k; int k1 = j - l; -@@ -349,7 +393,7 @@ +@@ -349,7 +400,7 @@ { if (!this.func_72684_a(l1, i2, k, l, i1)) { @@ -150,7 +164,7 @@ } if (!this.func_72684_a(l1 - j1, i2 - k1, i, j, i1)) -@@ -396,7 +440,7 @@ +@@ -396,7 +447,7 @@ { for (int k1 = k - p_152622_1_; k1 <= k + p_152622_1_; ++k1) { @@ -159,7 +173,7 @@ if (!playerchunkmapentry.func_187275_d(entityplayermp)) { -@@ -413,7 +457,7 @@ +@@ -413,7 +464,7 @@ { if (!this.func_72684_a(l, i1, j, k, p_152622_1_)) { @@ -168,7 +182,7 @@ } } } -@@ -460,7 +504,28 @@ +@@ -460,7 +511,28 @@ if (chunk != null) { diff --git a/patches/net/minecraft/server/management/PlayerChunkMapEntry.java.patch b/patches/net/minecraft/server/management/PlayerChunkMapEntry.java.patch index 68359010..b341f0eb 100644 --- a/patches/net/minecraft/server/management/PlayerChunkMapEntry.java.patch +++ b/patches/net/minecraft/server/management/PlayerChunkMapEntry.java.patch @@ -18,8 +18,9 @@ private final short[] field_187285_e = new short[64]; @Nullable - private Chunk field_187286_f; +- private int field_187287_g; + public Chunk field_187286_f; // CM: changed to public - private int field_187287_g; ++ public int field_187287_g; private int field_187288_h; private long field_187289_i; - private boolean field_187290_j; diff --git a/patches/net/minecraft/server/management/PlayerInteractionManager.java.patch b/patches/net/minecraft/server/management/PlayerInteractionManager.java.patch index 5be8a337..b7321feb 100644 --- a/patches/net/minecraft/server/management/PlayerInteractionManager.java.patch +++ b/patches/net/minecraft/server/management/PlayerInteractionManager.java.patch @@ -8,10 +8,12 @@ import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; -@@ -26,6 +27,10 @@ +@@ -26,6 +27,12 @@ import net.minecraft.world.World; import net.minecraft.world.WorldServer; ++import redstone.multimeter.helper.WorldHelper; ++ +import carpet.helpers.BlockRotator; +import carpet.CarpetSettings; +import carpet.worldedit.WorldEditBridge; @@ -19,7 +21,7 @@ public class PlayerInteractionManager { public World field_73092_a; -@@ -39,6 +44,8 @@ +@@ -39,6 +46,8 @@ private BlockPos field_180241_i = BlockPos.field_177992_a; private int field_73093_n; private int field_73094_o = -1; @@ -28,7 +30,7 @@ public PlayerInteractionManager(World p_i1524_1_) { -@@ -137,6 +144,12 @@ +@@ -137,6 +146,12 @@ public void func_180784_a(BlockPos p_180784_1_, EnumFacing p_180784_2_) { @@ -41,7 +43,7 @@ if (this.func_73083_d()) { if (!this.field_73092_a.func_175719_a((EntityPlayer)null, p_180784_1_, p_180784_2_)) -@@ -191,6 +204,11 @@ +@@ -191,6 +206,11 @@ this.field_73088_d = true; this.field_180240_f = p_180784_1_; int i = (int)(f * 10.0F); @@ -53,7 +55,7 @@ this.field_73092_a.func_175715_c(this.field_73090_b.func_145782_y(), p_180784_1_, i); this.field_73094_o = i; } -@@ -235,8 +253,10 @@ +@@ -235,8 +255,10 @@ { IBlockState iblockstate = this.field_73092_a.func_180495_p(p_180235_1_); iblockstate.func_177230_c().func_176208_a(this.field_73092_a, p_180235_1_, iblockstate, this.field_73090_b); @@ -65,7 +67,7 @@ if (flag) { iblockstate.func_177230_c().func_176206_d(this.field_73092_a, p_180235_1_, iblockstate); -@@ -288,7 +308,15 @@ +@@ -288,7 +310,15 @@ } this.field_73092_a.func_180498_a(this.field_73090_b, 2001, p_180237_1_, Block.func_176210_f(iblockstate)); @@ -82,7 +84,7 @@ if (this.func_73083_d()) { -@@ -307,10 +335,19 @@ +@@ -307,10 +337,19 @@ if (flag1 && flag) { @@ -102,7 +104,7 @@ return flag1; } } -@@ -402,10 +439,22 @@ +@@ -402,10 +441,23 @@ } else { @@ -122,6 +124,7 @@ + { + return EnumActionResult.PASS; + } ++ WorldHelper.getMultimeter().logInteractBlock(p_187251_2_, p_187251_5_); // RSMM if (iblockstate.func_177230_c().func_180639_a(p_187251_2_, p_187251_5_, iblockstate, p_187251_1_, p_187251_4_, p_187251_6_, p_187251_7_, p_187251_8_, p_187251_9_)) { return EnumActionResult.SUCCESS; diff --git a/patches/net/minecraft/server/management/PlayerList.java.patch b/patches/net/minecraft/server/management/PlayerList.java.patch index 20180fbd..0579cfff 100644 --- a/patches/net/minecraft/server/management/PlayerList.java.patch +++ b/patches/net/minecraft/server/management/PlayerList.java.patch @@ -58,16 +58,18 @@ } public void func_72358_d(EntityPlayerMP p_72358_1_) -@@ -352,6 +359,8 @@ +@@ -352,6 +359,10 @@ public void func_72367_e(EntityPlayerMP p_72367_1_) { ++ CarpetServer.rsmmServer.getPlayerList().remove(p_72367_1_); // RSMM ++ + //CM player logging off + CarpetServer.playerDisconnected(p_72367_1_); WorldServer worldserver = p_72367_1_.func_71121_q(); p_72367_1_.func_71029_a(StatList.field_75947_j); this.func_72391_b(p_72367_1_); -@@ -452,6 +461,11 @@ +@@ -452,6 +463,11 @@ for (EntityPlayerMP entityplayermp1 : list) { @@ -79,7 +81,7 @@ entityplayermp1.field_71135_a.func_194028_b(new TextComponentTranslation("multiplayer.disconnect.duplicate_login", new Object[0])); } -@@ -474,6 +488,7 @@ +@@ -474,6 +490,7 @@ p_72368_1_.func_71121_q().func_73039_n().func_72787_a(p_72368_1_); p_72368_1_.func_71121_q().func_73039_n().func_72790_b(p_72368_1_); p_72368_1_.func_71121_q().func_184164_w().func_72695_c(p_72368_1_); @@ -87,7 +89,7 @@ this.field_72404_b.remove(p_72368_1_); this.field_72400_f.func_71218_a(p_72368_1_.field_71093_bK).func_72973_f(p_72368_1_); BlockPos blockpos = p_72368_1_.func_180470_cg(); -@@ -496,6 +511,7 @@ +@@ -496,6 +513,7 @@ entityplayermp.func_145769_d(p_72368_1_.func_145782_y()); entityplayermp.func_174817_o(p_72368_1_); entityplayermp.func_184819_a(p_72368_1_.func_184591_cq()); @@ -95,7 +97,15 @@ for (String s : p_72368_1_.func_184216_O()) { -@@ -560,7 +576,11 @@ +@@ -540,6 +558,7 @@ + this.field_177454_f.put(entityplayermp.func_110124_au(), entityplayermp); + entityplayermp.func_71116_b(); + entityplayermp.func_70606_j(entityplayermp.func_110143_aJ()); ++ CarpetServer.rsmmServer.getPlayerList().respawn(entityplayermp); // RSMM + return entityplayermp; + } + +@@ -560,7 +579,11 @@ WorldServer worldserver1 = this.field_72400_f.func_71218_a(p_187242_1_.field_71093_bK); p_187242_1_.field_71135_a.func_147359_a(new SPacketRespawn(p_187242_1_.field_71093_bK, p_187242_1_.field_70170_p.func_175659_aa(), p_187242_1_.field_70170_p.func_72912_H().func_76067_t(), p_187242_1_.field_71134_c.func_73081_b())); this.func_187243_f(p_187242_1_); @@ -108,7 +118,7 @@ p_187242_1_.field_70128_L = false; this.func_82448_a(p_187242_1_, i, worldserver, worldserver1); this.func_72375_a(p_187242_1_, worldserver); -@@ -630,6 +650,12 @@ +@@ -630,6 +653,12 @@ } } @@ -121,7 +131,7 @@ p_82448_3_.field_72984_F.func_76319_b(); if (p_82448_2_ != 1) -@@ -1097,4 +1123,26 @@ +@@ -1097,4 +1126,26 @@ playeradvancements.func_193766_b(); } } diff --git a/patches/net/minecraft/tileentity/TileEntityChest.java.patch b/patches/net/minecraft/tileentity/TileEntityChest.java.patch index e9b7834e..591b2b89 100644 --- a/patches/net/minecraft/tileentity/TileEntityChest.java.patch +++ b/patches/net/minecraft/tileentity/TileEntityChest.java.patch @@ -1,13 +1,14 @@ --- ../src-base/minecraft/net/minecraft/tileentity/TileEntityChest.java +++ ../src-work/minecraft/net/minecraft/tileentity/TileEntityChest.java -@@ -23,7 +23,10 @@ +@@ -22,8 +22,11 @@ + import net.minecraft.util.datafix.walkers.ItemStackDataLists; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; - --public class TileEntityChest extends TileEntityLockableLoot implements ITickable ++import redstone.multimeter.helper.BlockChestHelper; +import carpet.CarpetSettings; +import carpet.helpers.TileEntityOptimizer.ILazyTileEntity; -+ + +-public class TileEntityChest extends TileEntityLockableLoot implements ITickable +public class TileEntityChest extends TileEntityLockableLoot implements ITickable, ILazyTileEntity { private NonNullList field_145985_p = NonNullList.func_191197_a(27, ItemStack.field_190927_a); @@ -74,7 +75,23 @@ if (p_145842_1_ == 1) { this.field_145987_o = p_145842_2_; -@@ -386,4 +408,14 @@ +@@ -324,6 +346,7 @@ + } + + ++this.field_145987_o; ++ BlockChestHelper.onInvOpenOrClosed(this, true); // RSMM + this.field_145850_b.func_175641_c(this.field_174879_c, this.func_145838_q(), 1, this.field_145987_o); + this.field_145850_b.func_175685_c(this.field_174879_c, this.func_145838_q(), false); + +@@ -339,6 +362,7 @@ + if (!p_174886_1_.func_175149_v() && this.func_145838_q() instanceof BlockChest) + { + --this.field_145987_o; ++ BlockChestHelper.onInvOpenOrClosed(this, false); // RSMM + this.field_145850_b.func_175641_c(this.field_174879_c, this.func_145838_q(), 1, this.field_145987_o); + this.field_145850_b.func_175685_c(this.field_174879_c, this.func_145838_q(), false); + +@@ -386,4 +410,14 @@ { return this.field_145985_p; } diff --git a/patches/net/minecraft/tileentity/TileEntityComparator.java.patch b/patches/net/minecraft/tileentity/TileEntityComparator.java.patch index 730a8d7b..75bc5f67 100644 --- a/patches/net/minecraft/tileentity/TileEntityComparator.java.patch +++ b/patches/net/minecraft/tileentity/TileEntityComparator.java.patch @@ -1,6 +1,14 @@ --- ../src-base/minecraft/net/minecraft/tileentity/TileEntityComparator.java +++ ../src-work/minecraft/net/minecraft/tileentity/TileEntityComparator.java -@@ -5,6 +5,10 @@ +@@ -1,10 +1,18 @@ + package net.minecraft.tileentity; + ++import carpet.CarpetSettings; ++ + import net.minecraft.nbt.NBTTagCompound; + ++import redstone.multimeter.helper.WorldHelper; ++ public class TileEntityComparator extends TileEntity { private int field_145997_a; @@ -11,3 +19,15 @@ public NBTTagCompound func_189515_b(NBTTagCompound p_189515_1_) { +@@ -26,6 +34,11 @@ + + public void func_145995_a(int p_145995_1_) + { ++ // RSMM start ++ if (CarpetSettings.redstoneMultimeter) { ++ WorldHelper.getMultimeter().logPowerChange(field_145850_b, field_174879_c, field_145997_a, p_145995_1_); ++ } ++ // RSMM end + this.field_145997_a = p_145995_1_; + } + } diff --git a/patches/net/minecraft/tileentity/TileEntityHopper.java.patch b/patches/net/minecraft/tileentity/TileEntityHopper.java.patch index 3d24dcc3..d31e1fc4 100644 --- a/patches/net/minecraft/tileentity/TileEntityHopper.java.patch +++ b/patches/net/minecraft/tileentity/TileEntityHopper.java.patch @@ -10,17 +10,18 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockChest; import net.minecraft.block.BlockHopper; -@@ -28,12 +31,21 @@ +@@ -27,13 +30,22 @@ + import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; - --public class TileEntityHopper extends TileEntityLockableLoot implements IHopper, ITickable ++import redstone.multimeter.helper.WorldHelper; +import net.minecraft.item.EnumDyeColor; +import carpet.helpers.TileEntityOptimizer.ILazyTileEntity; +import carpet.CarpetSettings; +import carpet.helpers.HopperCounter; +import carpet.utils.WoolTool; -+ + +-public class TileEntityHopper extends TileEntityLockableLoot implements IHopper, ITickable +public class TileEntityHopper extends TileEntityLockableLoot implements IHopper, ITickable, ILazyTileEntity { private NonNullList field_145900_a = NonNullList.func_191197_a(5, ItemStack.field_190927_a); @@ -33,7 +34,15 @@ public static void func_189683_a(DataFixer p_189683_0_) { p_189683_0_.func_188258_a(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityHopper.class, new String[] {"Items"})); -@@ -132,14 +144,44 @@ +@@ -114,6 +126,7 @@ + if (this.field_145850_b != null && !this.field_145850_b.field_72995_K) + { + --this.field_145901_j; ++ rsmm$logActive(); // RSMM + this.field_190578_g = this.field_145850_b.func_82737_E(); + + if (!this.func_145888_j()) +@@ -132,14 +145,44 @@ { boolean flag = false; @@ -83,7 +92,7 @@ } if (flag) -@@ -191,10 +233,42 @@ +@@ -191,10 +234,42 @@ private boolean func_145883_k() { @@ -126,7 +135,7 @@ return false; } else -@@ -203,6 +277,10 @@ +@@ -203,6 +278,10 @@ if (this.func_174919_a(iinventory, enumfacing)) { @@ -137,7 +146,7 @@ return false; } else -@@ -297,7 +375,10 @@ +@@ -297,7 +376,10 @@ public static boolean func_145891_a(IHopper p_145891_0_) { @@ -148,7 +157,7 @@ if (iinventory != null) { -@@ -305,6 +386,14 @@ +@@ -305,6 +387,14 @@ if (func_174917_b(iinventory, enumfacing)) { @@ -163,7 +172,7 @@ return false; } -@@ -333,6 +422,13 @@ +@@ -333,6 +423,13 @@ } } } @@ -177,7 +186,7 @@ } else { -@@ -352,6 +448,11 @@ +@@ -352,6 +449,11 @@ { ItemStack itemstack = p_174915_1_.func_70301_a(p_174915_2_); @@ -189,7 +198,7 @@ if (!itemstack.func_190926_b() && func_174921_b(p_174915_1_, itemstack, p_174915_2_, p_174915_3_)) { ItemStack itemstack1 = itemstack.func_77946_l(); -@@ -499,6 +600,14 @@ +@@ -499,6 +601,14 @@ return func_145893_b(this.func_145831_w(), this.func_96107_aA() + (double)enumfacing.func_82601_c(), this.func_96109_aB() + (double)enumfacing.func_96559_d(), this.func_96108_aC() + (double)enumfacing.func_82599_e()); } @@ -204,7 +213,7 @@ public static IInventory func_145884_b(IHopper p_145884_0_) { return func_145893_b(p_145884_0_.func_145831_w(), p_145884_0_.func_96107_aA(), p_145884_0_.func_96109_aB() + 1.0D, p_145884_0_.func_96108_aC()); -@@ -546,7 +655,7 @@ +@@ -546,7 +656,7 @@ return iinventory; } @@ -213,7 +222,20 @@ { if (p_145894_0_.func_77973_b() != p_145894_1_.func_77973_b()) { -@@ -611,4 +720,15 @@ +@@ -584,9 +694,11 @@ + private void func_145896_c(int p_145896_1_) + { + this.field_145901_j = p_145896_1_; ++ rsmm$logActive(); // RSMM + } + +- private boolean func_145888_j() ++ // RSMM - change access from private to public ++ public boolean func_145888_j() + { + return this.field_145901_j > 0; + } +@@ -611,4 +723,22 @@ { return this.field_145900_a; } @@ -227,5 +249,12 @@ + public void wakeUp(){ + this.pullSleeping = false; + this.pushSleeping = false; ++ } ++ ++ // RSMM ++ private void rsmm$logActive() { ++ if (CarpetSettings.redstoneMultimeter) { ++ WorldHelper.getMultimeter().logActive(field_145850_b, field_174879_c, !func_145888_j()); ++ } + } } diff --git a/patches/net/minecraft/util/BitArray.java.patch b/patches/net/minecraft/util/BitArray.java.patch new file mode 100644 index 00000000..7a33b744 --- /dev/null +++ b/patches/net/minecraft/util/BitArray.java.patch @@ -0,0 +1,14 @@ +--- ../src-base/minecraft/net/minecraft/util/BitArray.java ++++ ../src-work/minecraft/net/minecraft/util/BitArray.java +@@ -65,4 +65,11 @@ + { + return this.field_188148_d; + } ++ ++ public long getMaxEntryValue(){ ++ return field_188147_c; ++ } ++ public int getBitsPerEntry(){ ++ return field_188146_b; ++ } + } diff --git a/patches/net/minecraft/world/Explosion.java.patch b/patches/net/minecraft/world/Explosion.java.patch index 1747b682..0fcbfe8c 100644 --- a/patches/net/minecraft/world/Explosion.java.patch +++ b/patches/net/minecraft/world/Explosion.java.patch @@ -1,6 +1,14 @@ --- ../src-base/minecraft/net/minecraft/world/Explosion.java +++ ../src-work/minecraft/net/minecraft/world/Explosion.java -@@ -26,20 +26,26 @@ +@@ -1,5 +1,7 @@ + package net.minecraft.world; + ++import carpet.logging.LoggerRegistry; ++import carpet.logging.logHelpers.ExplosionLogHelper; + import com.google.common.collect.Lists; + import com.google.common.collect.Maps; + import com.google.common.collect.Sets; +@@ -26,20 +28,29 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -34,11 +42,22 @@ + // For disabling the explosion particles and sound CARPET-XCOM + public static int explosionSound = 0; ++ ++ // For explosion logger CARPET-SYLKOS ++ public ExplosionLogHelper logHelper = null; + public Explosion(World p_i45754_1_, Entity p_i45754_2_, double p_i45754_3_, double p_i45754_5_, double p_i45754_7_, float p_i45754_9_, boolean p_i45754_10_, boolean p_i45754_11_) { this.field_77287_j = p_i45754_1_; -@@ -54,6 +60,16 @@ +@@ -50,10 +61,24 @@ + this.field_77282_d = p_i45754_7_; + this.field_77286_a = p_i45754_10_; + this.field_82755_b = p_i45754_11_; ++ ++ if (LoggerRegistry.__explosions) { ++ this.logHelper = new ExplosionLogHelper(p_i45754_2_, p_i45754_3_, p_i45754_5_, p_i45754_7_, p_i45754_9_, p_i45754_10_); ++ } + } public void func_77278_a() { @@ -55,16 +74,22 @@ Set set = Sets.newHashSet(); int i = 16; -@@ -102,7 +118,7 @@ +@@ -102,7 +127,13 @@ } } - this.field_77281_g.addAll(set); + if(!CarpetSettings.explosionNoBlockDamage) this.field_77281_g.addAll(set); ++ ++ // CARPET-SYLKOS ++ // TNT shouldn't apply velocity to entities ++ // This also yeets all the calculations tnt does for applying velocity and damage to entities ++ if(CarpetSettings.removeTNTVelocity) return; ++ float f3 = this.field_77280_f * 2.0F; int k1 = MathHelper.func_76128_c(this.field_77284_b - (double)f3 - 1.0D); int l1 = MathHelper.func_76128_c(this.field_77284_b + (double)f3 + 1.0D); -@@ -164,6 +180,14 @@ +@@ -164,6 +195,14 @@ public void func_77279_a(boolean p_77279_1_) { @@ -79,3 +104,15 @@ this.field_77287_j.func_184148_a((EntityPlayer)null, this.field_77284_b, this.field_77285_c, this.field_77282_d, SoundEvents.field_187539_bB, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.field_77287_j.field_73012_v.nextFloat() - this.field_77287_j.field_73012_v.nextFloat()) * 0.2F) * 0.7F); if (this.field_77280_f >= 2.0F && this.field_82755_b) +@@ -226,6 +265,11 @@ + } + } + } ++ ++ // Logs explosion CARPET-SYLKOS ++ if(LoggerRegistry.__explosions) { ++ this.logHelper.onExplosionDone(this.field_77287_j.func_72820_D()); ++ } + } + + public Map func_77277_b() diff --git a/patches/net/minecraft/world/World.java.patch b/patches/net/minecraft/world/World.java.patch index af893c93..57b9beb9 100644 --- a/patches/net/minecraft/world/World.java.patch +++ b/patches/net/minecraft/world/World.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/world/World.java +++ ../src-work/minecraft/net/minecraft/world/World.java -@@ -4,13 +4,11 @@ +@@ -4,13 +4,10 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Predicate; import com.google.common.collect.Lists; @@ -12,17 +12,18 @@ -import java.util.UUID; -import java.util.function.Supplier; + -+import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.atomic.AtomicLong; + import javax.annotation.Nullable; import net.minecraft.advancements.AdvancementManager; import net.minecraft.advancements.FunctionManager; -@@ -60,10 +58,21 @@ +@@ -60,10 +57,23 @@ import net.minecraft.world.storage.WorldSavedData; import net.minecraft.world.storage.loot.LootTableManager; ++import redstone.multimeter.common.TickTask; ++import redstone.multimeter.helper.WorldHelper; +import carpet.utils.CarpetProfiler; +import carpet.utils.Messenger; +import carpet.CarpetSettings; @@ -42,7 +43,7 @@ public final List field_72996_f = Lists.newArrayList(); protected final List field_72997_g = Lists.newArrayList(); public final List field_147482_g = Lists.newArrayList(); -@@ -75,7 +84,7 @@ +@@ -75,7 +85,7 @@ protected final IntHashMap field_175729_l = new IntHashMap(); private final long field_73001_c = 16777215L; private int field_73008_k; @@ -51,7 +52,7 @@ protected final int field_73006_m = 1013904223; protected float field_73003_n; protected float field_73004_o; -@@ -105,6 +114,13 @@ +@@ -105,6 +115,13 @@ private final WorldBorder field_175728_M; int[] field_72994_J; @@ -65,7 +66,7 @@ protected World(ISaveHandler p_i45749_1_, WorldInfo p_i45749_2_, WorldProvider p_i45749_3_, Profiler p_i45749_4_, boolean p_i45749_5_) { this.field_73021_x = Lists.newArrayList(this.field_184152_t); -@@ -119,6 +135,7 @@ +@@ -119,6 +136,7 @@ this.field_73011_w = p_i45749_3_; this.field_72995_K = p_i45749_5_; this.field_175728_M = p_i45749_3_.func_177501_r(); @@ -73,7 +74,7 @@ } public World func_175643_b() -@@ -269,7 +286,7 @@ +@@ -269,7 +287,7 @@ } } @@ -82,7 +83,7 @@ public Chunk func_175726_f(BlockPos p_175726_1_) { -@@ -286,6 +303,16 @@ +@@ -286,6 +304,16 @@ return this.func_175680_a(p_190526_1_, p_190526_2_, false) ? true : this.field_73020_y.func_191062_e(p_190526_1_, p_190526_2_); } @@ -99,7 +100,7 @@ public boolean func_180501_a(BlockPos p_180501_1_, IBlockState p_180501_2_, int p_180501_3_) { if (this.func_189509_E(p_180501_1_)) -@@ -300,7 +327,8 @@ +@@ -300,7 +328,8 @@ { Chunk chunk = this.func_175726_f(p_180501_1_); Block block = p_180501_2_.func_177230_c(); @@ -109,7 +110,7 @@ if (iblockstate == null) { -@@ -329,7 +357,8 @@ +@@ -329,7 +358,8 @@ this.func_175666_e(p_180501_1_, block); } } @@ -119,7 +120,7 @@ { this.func_190522_c(p_180501_1_, block); } -@@ -430,8 +459,36 @@ +@@ -430,8 +460,36 @@ this.func_190529_b(p_190522_1_.func_177968_d(), p_190522_2_, p_190522_1_); } @@ -156,7 +157,7 @@ this.func_190524_a(p_175685_1_.func_177976_e(), p_175685_2_, p_175685_1_); this.func_190524_a(p_175685_1_.func_177974_f(), p_175685_2_, p_175685_1_); this.func_190524_a(p_175685_1_.func_177977_b(), p_175685_2_, p_175685_1_); -@@ -447,6 +504,44 @@ +@@ -447,6 +505,44 @@ public void func_175695_a(BlockPos p_175695_1_, Block p_175695_2_, EnumFacing p_175695_3_) { @@ -201,7 +202,7 @@ if (p_175695_3_ != EnumFacing.WEST) { this.func_190524_a(p_175695_1_.func_177976_e(), p_175695_2_, p_175695_1_); -@@ -480,6 +575,11 @@ +@@ -480,12 +576,18 @@ public void func_190524_a(BlockPos p_190524_1_, final Block p_190524_2_, BlockPos p_190524_3_) { @@ -213,12 +214,19 @@ if (!this.field_72995_K) { IBlockState iblockstate = this.func_180495_p(p_190524_1_); -@@ -509,11 +609,21 @@ + + try + { ++ WorldHelper.onBlockUpdate(this, p_190524_1_, iblockstate); // RSMM + iblockstate.func_189546_a(this, p_190524_1_, p_190524_2_, p_190524_3_); + } + catch (Throwable throwable) +@@ -509,11 +611,21 @@ CrashReportCategory.func_175750_a(crashreportcategory, p_190524_1_, iblockstate); throw new ReportedException(crashreport); } + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + StateChangeEventDispatcher.dispatchEvent(this, p_190524_1_); + } + // ----- RSMM End ----- // @@ -235,19 +243,27 @@ if (!this.field_72995_K) { IBlockState iblockstate = this.func_180495_p(p_190529_1_); -@@ -546,6 +656,11 @@ +@@ -522,6 +634,7 @@ + { + try + { ++ WorldHelper.onObserverUpdate(this, p_190529_1_); // RSMM + ((BlockObserver)iblockstate.func_177230_c()).func_190962_b(iblockstate, this, p_190529_1_, p_190529_2_, p_190529_3_); + } + catch (Throwable throwable) +@@ -546,6 +659,11 @@ throw new ReportedException(crashreport); } } + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + StateChangeEventDispatcher.dispatchEvent(this, p_190529_1_); + } + // ----- RSMM End ----- // } } -@@ -1076,6 +1191,18 @@ +@@ -1076,6 +1194,18 @@ public void func_72900_e(Entity p_72900_1_) { @@ -266,7 +282,7 @@ if (p_72900_1_.func_184207_aI()) { p_72900_1_.func_184226_ay(); -@@ -1098,6 +1225,18 @@ +@@ -1098,6 +1228,18 @@ public void func_72973_f(Entity p_72973_1_) { @@ -285,7 +301,7 @@ p_72973_1_.func_184174_b(false); p_72973_1_.func_70106_y(); -@@ -1126,6 +1265,9 @@ +@@ -1126,6 +1268,9 @@ private boolean func_191504_a(@Nullable Entity p_191504_1_, AxisAlignedBB p_191504_2_, boolean p_191504_3_, @Nullable List p_191504_4_) { @@ -295,15 +311,27 @@ int i = MathHelper.func_76128_c(p_191504_2_.field_72340_a) - 1; int j = MathHelper.func_76143_f(p_191504_2_.field_72336_d) + 1; int k = MathHelper.func_76128_c(p_191504_2_.field_72338_b) - 1; -@@ -1339,6 +1481,7 @@ +@@ -1337,8 +1482,11 @@ + public void func_72939_s() + { this.field_72984_F.func_76320_a("entities"); ++ WorldHelper.startTickTask(TickTask.ENTITIES); // RSMM this.field_72984_F.func_76320_a("global"); ++ WorldHelper.startTickTask(TickTask.GLOBAL_ENTITIES); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.ENTITY, LagSpikeHelper.EntitySubPhase.PRE); for (int i = 0; i < this.field_73007_j.size(); ++i) { Entity entity = this.field_73007_j.get(i); -@@ -1370,6 +1513,9 @@ +@@ -1346,6 +1494,7 @@ + try + { + ++entity.field_70173_aa; ++ WorldHelper.onEntityTick(this, entity); // RSMM + entity.func_70071_h_(); + } + catch (Throwable throwable2) +@@ -1370,6 +1519,9 @@ this.field_73007_j.remove(i--); } } @@ -313,12 +341,13 @@ this.field_72984_F.func_76318_c("remove"); this.field_72996_f.removeAll(this.field_72997_g); -@@ -1393,11 +1539,13 @@ +@@ -1393,11 +1545,14 @@ this.field_72997_g.clear(); this.func_184147_l(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.ENTITY, LagSpikeHelper.EntitySubPhase.POST_PLAYERS); this.field_72984_F.func_76318_c("regular"); ++ WorldHelper.swapTickTask(TickTask.REGULAR_ENTITIES); // RSMM for (int i1 = 0; i1 < this.field_72996_f.size(); ++i1) { @@ -327,7 +356,7 @@ Entity entity3 = entity2.func_184187_bx(); if (entity3 != null) -@@ -1416,7 +1564,10 @@ +@@ -1416,7 +1571,10 @@ { try { @@ -339,7 +368,7 @@ } catch (Throwable throwable1) { -@@ -1437,31 +1588,50 @@ +@@ -1437,31 +1595,51 @@ if (entity2.field_70175_ag && this.func_175680_a(l1, i2, true)) { @@ -361,6 +390,7 @@ + CarpetProfiler.start_section(world_name, "tileentities"); this.field_72984_F.func_76318_c("blockEntities"); ++ WorldHelper.swapTickTask(TickTask.BLOCK_ENTITIES); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.TILE_ENTITY, LagSpikeHelper.PrePostSubPhase.PRE); if (!this.field_147483_b.isEmpty()) @@ -392,7 +422,7 @@ if (!tileentity.func_145837_r() && tileentity.func_145830_o()) { -@@ -1471,12 +1641,14 @@ +@@ -1471,12 +1649,15 @@ { try { @@ -407,13 +437,14 @@ + { + return String.valueOf((Object) TileEntity.func_190559_a(tileentity.getClass())); + }); ++ WorldHelper.onBlockEntityTick(this, tileentity); // RSMM + ((ITickable) tileentity).func_73660_a(); + this.field_72984_F.func_76319_b(); + } } catch (Throwable throwable) { -@@ -1490,16 +1662,26 @@ +@@ -1490,16 +1671,26 @@ if (tileentity.func_145837_r()) { @@ -440,7 +471,7 @@ this.field_147481_N = false; this.field_72984_F.func_76318_c("pendingBlockEntities"); -@@ -1528,6 +1710,8 @@ +@@ -1528,9 +1719,13 @@ this.field_147484_a.clear(); } @@ -448,8 +479,13 @@ + CarpetProfiler.end_current_section(); this.field_72984_F.func_76319_b(); ++ WorldHelper.endTickTask(); // RSMM this.field_72984_F.func_76319_b(); -@@ -1602,11 +1786,15 @@ ++ WorldHelper.endTickTask(); // RSMM + } + + protected void func_184147_l() +@@ -1602,11 +1797,16 @@ if (p_72866_1_.func_184218_aH()) { @@ -462,12 +498,13 @@ { - p_72866_1_.func_70071_h_(); + if(!CarpetSettings.commandLazyChunkBehavior || LazyChunkBehaviorHelper.shouldUpdate(p_72866_1_)) { ++ WorldHelper.onEntityTick(this, p_72866_1_); // RSMM + p_72866_1_.func_70071_h_(); + } } } -@@ -1648,7 +1836,8 @@ +@@ -1648,7 +1848,8 @@ this.func_72964_e(p_72866_1_.field_70176_ah, p_72866_1_.field_70164_aj).func_76608_a(p_72866_1_, p_72866_1_.field_70162_ai); } @@ -477,7 +514,7 @@ { p_72866_1_.field_70175_ag = false; } -@@ -1670,7 +1859,11 @@ +@@ -1670,7 +1871,11 @@ } else { @@ -490,7 +527,7 @@ } } } -@@ -1689,7 +1882,7 @@ +@@ -1689,7 +1894,7 @@ { Entity entity4 = list.get(j2); @@ -499,7 +536,7 @@ { return false; } -@@ -2153,6 +2346,16 @@ +@@ -2153,6 +2358,16 @@ { this.field_72986_A.func_76090_f(this.field_73012_v.nextInt(168000) + 12000); } @@ -516,7 +553,7 @@ } else { -@@ -2177,6 +2380,16 @@ +@@ -2177,6 +2392,16 @@ { this.field_72986_A.func_76080_g(this.field_73012_v.nextInt(168000) + 12000); } @@ -533,7 +570,7 @@ } else { -@@ -2387,6 +2600,11 @@ +@@ -2387,6 +2612,11 @@ public boolean func_180500_c(EnumSkyBlock p_180500_1_, BlockPos p_180500_2_) { @@ -545,7 +582,7 @@ if (!this.func_175648_a(p_180500_2_, 17, false)) { return false; -@@ -2699,7 +2917,8 @@ +@@ -2699,7 +2929,8 @@ IBlockState iblockstate1 = this.func_180495_p(p_190527_2_); AxisAlignedBB axisalignedbb = p_190527_3_ ? null : p_190527_1_.func_176223_P().func_185890_d(this, p_190527_2_); @@ -555,7 +592,7 @@ { return false; } -@@ -3267,30 +3486,41 @@ +@@ -3267,30 +3498,43 @@ public void func_175666_e(BlockPos p_175666_1_, Block p_175666_2_) { @@ -591,12 +628,14 @@ - if (Blocks.field_150441_bU.func_185547_C(iblockstate1)) - { + if (Blocks.field_150441_bU.func_185547_C(iblockstate1)) { ++ WorldHelper.onComparatorUpdate(this, blockpos1); // RSMM iblockstate1.func_189546_a(this, blockpos1, p_175666_2_, p_175666_1_); + } else if (iblockstate1.func_185915_l()) { + blockpos1 = blockpos1.func_177972_a(enumfacing); + iblockstate1 = this.func_180495_p(blockpos1); + + if (Blocks.field_150441_bU.func_185547_C(iblockstate1)) { ++ WorldHelper.onComparatorUpdate(this, blockpos1); // RSMM + iblockstate1.func_189546_a(this, blockpos1, p_175666_2_, p_175666_1_); + } } @@ -605,32 +644,22 @@ } + carpet.carpetclient.CarpetClientChunkLogger.resetReason(); + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + StateChangeEventDispatcher.dispatchEvent(this, p_175666_1_); + } + // ----- RSMM End ----- // } public DifficultyInstance func_175649_E(BlockPos p_175649_1_) -@@ -3361,4 +3591,128 @@ +@@ -3361,4 +3605,120 @@ { return null; } + -+ AtomicLong scrambledSeed; ++ private static final carpet.utils.JavaVersionUtil.FieldAccessor SEED_ACCESSOR = ++ carpet.utils.JavaVersionUtil.objectFieldAccessor(Random.class, "seed", AtomicLong.class); + public long getRandSeed(){ -+ try -+ { -+ if(scrambledSeed == null) { -+ Field field = Random.class.getDeclaredField("seed"); -+ field.setAccessible(true); -+ scrambledSeed = (AtomicLong) field.get(field_73012_v); //this needs to be XOR'd with 0x5DEECE66DL -+ } -+ return scrambledSeed.get(); -+ // Minecraft.getMinecraft().player.sendChatMessage(chunk.x + ", " + chunk.z + ", seed " + theSeed); -+ } catch (Exception e) {} -+ -+ return 0; ++ return SEED_ACCESSOR.get(this.field_73012_v).get(); + } + + // Update Suppression crash fixes CARPET-XCOM @@ -642,6 +671,7 @@ + + try + { ++ WorldHelper.onBlockUpdate(this, pos, iblockstate); // RSMM + iblockstate.func_189546_a(this, pos, blockIn, fromPos); + } + catch (ThrowableSuppression e) @@ -674,7 +704,7 @@ + throw new ReportedException(crashreport); + } + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + StateChangeEventDispatcher.dispatchEvent(this, pos); + } + // ----- RSMM End ----- // @@ -692,6 +722,7 @@ + { + try + { ++ WorldHelper.onObserverUpdate(this, pos); // RSMM + ((BlockObserver)iblockstate.func_177230_c()).func_190962_b(iblockstate, this, pos, changedBlock, changedBlockPos); + } + catch (StackOverflowError e) @@ -721,7 +752,7 @@ + } + } + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { ++ if (CarpetSettings.redstoneMultimeterLegacy) { + StateChangeEventDispatcher.dispatchEvent(this, pos); + } + // ----- RSMM End ----- // diff --git a/patches/net/minecraft/world/WorldServer.java.patch b/patches/net/minecraft/world/WorldServer.java.patch index f784eba2..4a3a2e18 100644 --- a/patches/net/minecraft/world/WorldServer.java.patch +++ b/patches/net/minecraft/world/WorldServer.java.patch @@ -1,14 +1,15 @@ --- ../src-base/minecraft/net/minecraft/world/WorldServer.java +++ ../src-work/minecraft/net/minecraft/world/WorldServer.java -@@ -1,5 +1,7 @@ +@@ -1,5 +1,8 @@ package net.minecraft.world; +import carpet.helpers.NextTickListEntryFix; +import carpet.helpers.ScheduledBlockEventSerializer; ++import carpet.logging.logHelpers.ExplosionLogHelper; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -@@ -14,7 +16,6 @@ +@@ -14,7 +17,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.UUID; @@ -16,7 +17,15 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import net.minecraft.advancements.AdvancementManager; -@@ -60,6 +61,7 @@ +@@ -50,6 +52,7 @@ + import net.minecraft.scoreboard.ServerScoreboard; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.management.PlayerChunkMap; ++import net.minecraft.tileentity.TileEntity; + import net.minecraft.util.EnumParticleTypes; + import net.minecraft.util.IProgressUpdate; + import net.minecraft.util.IThreadListener; +@@ -60,6 +63,7 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -24,11 +33,19 @@ import net.minecraft.village.VillageCollection; import net.minecraft.village.VillageSiege; import net.minecraft.world.biome.Biome; -@@ -80,14 +82,23 @@ +@@ -77,17 +81,31 @@ + import net.minecraft.world.storage.WorldInfo; + import net.minecraft.world.storage.WorldSavedDataCallableSave; + import net.minecraft.world.storage.loot.LootTableManager; ++ ++import redstone.multimeter.common.TickTask; ++import redstone.multimeter.helper.WorldHelper; ++ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import carpet.CarpetSettings; ++import carpet.CarpetServer; +import carpet.helpers.LagSpikeHelper; +import carpet.helpers.RandomTickOptimization; +import carpet.helpers.TickSpeed; @@ -51,7 +68,7 @@ private final Map field_175741_N = Maps.newHashMap(); public boolean field_73058_d; private boolean field_73068_P; -@@ -99,6 +110,13 @@ +@@ -99,6 +117,14 @@ private int field_147489_T; private final List field_94579_S = Lists.newArrayList(); @@ -61,11 +78,20 @@ + public boolean blockActionsProcessed; + public ScheduledBlockEventSerializer blockEventSerializer; + public static boolean loginMinecartFix = false; ++ private final String dimensionName; // RSMM + public WorldServer(MinecraftServer p_i45921_1_, ISaveHandler p_i45921_2_, WorldInfo p_i45921_3_, int p_i45921_4_, Profiler p_i45921_5_) { super(p_i45921_2_, p_i45921_3_, DimensionType.func_186069_a(p_i45921_4_).func_186070_d(), p_i45921_5_, false); -@@ -159,11 +177,24 @@ +@@ -111,6 +137,7 @@ + this.func_72966_v(); + this.func_72947_a(); + this.func_175723_af().func_177725_a(p_i45921_1_.func_175580_aG()); ++ this.dimensionName = this.field_73011_w.func_186058_p().func_186065_b(); + } + + public World func_175643_b() +@@ -159,11 +186,30 @@ this.func_175723_af().func_177750_a(this.field_72986_A.func_176137_E()); } @@ -86,11 +112,17 @@ { + // [CM] Piston ghost blocks fix + this.blockActionsProcessed = false; -+ ++ // [CM] ITT crash fix reset ++ if(CarpetSettings.limitITTupdates > 0 && field_73061_a.func_152345_ab()) { ++ CarpetServer.limitITTCounter = 0; ++ } ++ ++ WorldHelper.startTickTask(TickTask.TICK_LEVEL, dimensionName); // RSMM ++ super.func_72835_b(); if (this.func_72912_H().func_76093_s() && this.func_175659_aa() != EnumDifficulty.HARD) -@@ -184,15 +215,26 @@ +@@ -184,15 +230,30 @@ this.func_73053_d(); } @@ -99,6 +131,7 @@ + {// extra indent + this.field_72984_F.func_76320_a("mobSpawner"); ++ WorldHelper.startTickTask(TickTask.MOB_SPAWNING); // RSMM + CarpetProfiler.start_section(world_name, "spawning"); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.MOB_SPAWNING, LagSpikeHelper.PrePostSubPhase.PRE); @@ -108,23 +141,41 @@ } + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.MOB_SPAWNING, LagSpikeHelper.PrePostSubPhase.POST); + CarpetProfiler.end_current_section(); ++ WorldHelper.endTickTask(); // RSMM + }//end indent this.field_72984_F.func_76318_c("chunkSource"); ++ WorldHelper.startTickTask(TickTask.CHUNK_SOURCE); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.CHUNK_UNLOADING, LagSpikeHelper.PrePostSubPhase.PRE); this.field_73020_y.func_73156_b(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.CHUNK_UNLOADING, LagSpikeHelper.PrePostSubPhase.POST); ++ WorldHelper.endTickTask(); // RSMM int j = this.func_72967_a(1.0F); if (j != this.func_175657_ab()) -@@ -200,26 +242,76 @@ +@@ -200,26 +261,109 @@ this.func_175692_b(j); } + if (TickSpeed.process_entities) + { // CM extra indent ++ // RSMM start ++ boolean tickTime = field_73011_w.func_186058_p() == DimensionType.OVERWORLD; ++ ++ if (tickTime) { ++ WorldHelper.startTickTask(TickTask.TICK_TIME); ++ } ++ // RSMM end ++ this.field_72986_A.func_82572_b(this.field_72986_A.func_82573_f() + 1L); ++ // RSMM start ++ if (tickTime) { ++ WorldHelper.getMultimeterServer().tickTime(this); ++ WorldHelper.endTickTask(); ++ } ++ // RSMM ++ if (this.func_82736_K().func_82766_b("doDaylightCycle")) { this.field_72986_A.func_76068_b(this.field_72986_A.func_76073_f() + 1L); @@ -132,6 +183,7 @@ - this.field_72984_F.func_76318_c("tickPending"); - this.func_72955_a(false); ++ WorldHelper.startTickTask(TickTask.SCHEDULED_TICKS); // RSMM + + CarpetProfiler.start_section(world_name, "blocks"); + @@ -149,29 +201,36 @@ + } + + CarpetProfiler.end_current_section(); ++ WorldHelper.endTickTask(); // RSMM + -+ } ++ } //end indent + CarpetProfiler.start_section(world_name, "blocks"); this.field_72984_F.func_76318_c("tickBlocks"); ++ WorldHelper.startTickTask(TickTask.TICK_CHUNKS); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.RANDOM_TICK, LagSpikeHelper.PrePostSubPhase.PRE); this.func_147456_g(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.RANDOM_TICK, LagSpikeHelper.PrePostSubPhase.POST); + CarpetProfiler.end_current_section(); this.field_72984_F.func_76318_c("chunkMap"); ++ WorldHelper.swapTickTask(TickTask.CHUNK_MAP); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.PLAYER_CHUNK_MAP, LagSpikeHelper.PrePostSubPhase.PRE); this.field_73063_M.func_72693_b(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.PLAYER_CHUNK_MAP, LagSpikeHelper.PrePostSubPhase.POST); ++ WorldHelper.endTickTask(); // RSMM + + if (TickSpeed.process_entities) + { // CM indent this.field_72984_F.func_76318_c("village"); ++ WorldHelper.startTickTask(TickTask.VILLAGES); // RSMM + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.VILLAGE, LagSpikeHelper.PrePostSubPhase.PRE); this.field_72982_D.func_75544_a(); this.field_175740_d.func_75528_a(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.VILLAGE, LagSpikeHelper.PrePostSubPhase.POST); this.field_72984_F.func_76318_c("portalForcer"); ++ WorldHelper.swapTickTask(TickTask.PORTALS); // RSMM this.field_85177_Q.func_85189_a(this.func_82737_E()); -+ } ++ WorldHelper.endTickTask(); // RSMM ++ } //end indent + + // NewLight PHIPRO-CARPET + if (CarpetSettings.newLight) @@ -181,9 +240,14 @@ + } this.field_72984_F.func_76319_b(); + ++ if (TickSpeed.process_entities) ++ { // CM indent + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.BLOCK_EVENT, LagSpikeHelper.PrePostSubPhase.PRE); this.func_147488_Z(); + LagSpikeHelper.processLagSpikes(this, LagSpikeHelper.TickPhase.BLOCK_EVENT, LagSpikeHelper.PrePostSubPhase.POST); ++ } //end indent ++ ++ WorldHelper.endTickTask(); // RSMM + + if(LoggerRegistry.__rng){ + LoggerRegistry.getLogger("rng").log(()-> new ITextComponent[]{ @@ -192,11 +256,16 @@ + } + if(CarpetSettings.setSeed != 0){ + this.field_73012_v.setSeed(CarpetSettings.setSeed ^ 0x5DEECE66DL); ++ } ++ ++ // Solution for final explosion check -- not a great solution - CARPET-SYLKOS ++ if(LoggerRegistry.__explosions) { ++ ExplosionLogHelper.logLastExplosion(); + } } @Nullable -@@ -255,8 +347,15 @@ +@@ -255,13 +399,22 @@ ++j; } } @@ -214,7 +283,23 @@ } } -@@ -287,6 +386,28 @@ + protected void func_73053_d() + { ++ WorldHelper.startTickTask(TickTask.WAKE_SLEEPING_PLAYERS); // RSMM ++ + this.field_73068_P = false; + + for (EntityPlayer entityplayer : this.field_73010_i.stream().filter(EntityPlayer::func_70608_bn).collect(Collectors.toList())) +@@ -273,6 +426,8 @@ + { + this.func_73051_P(); + } ++ ++ WorldHelper.endTickTask(); // RSMM + } + + private void func_73051_P() +@@ -287,6 +442,28 @@ { if (this.field_73068_P && !this.field_72995_K) { @@ -243,7 +328,7 @@ for (EntityPlayer entityplayer : this.field_73010_i) { if (!entityplayer.func_175149_v() && !entityplayer.func_71026_bH()) -@@ -303,7 +424,7 @@ +@@ -303,7 +480,7 @@ } } @@ -252,40 +337,97 @@ { return this.func_72863_F().func_73149_a(p_175680_1_, p_175680_2_); } -@@ -344,6 +465,7 @@ +@@ -331,12 +508,14 @@ + + if (this.field_72986_A.func_76067_t() == WorldType.field_180272_g) + { ++ WorldHelper.startTickTask(TickTask.TICK_CHUNKS); // RSMM + Iterator iterator1 = this.field_73063_M.func_187300_b(); + + while (iterator1.hasNext()) + { + ((Chunk)iterator1.next()).func_150804_b(false); + } ++ WorldHelper.endTickTask(); // RSMM + } + else + { +@@ -344,7 +523,9 @@ boolean flag = this.func_72896_J(); boolean flag1 = this.func_72911_I(); this.field_72984_F.func_76320_a("pollingChunks"); + boolean overworldIceOnly = !CarpetSettings.enableStableLCGNetherEnd || field_73011_w.func_186058_p().func_186068_a() == 0; // Rule to disable nether and end ice snow and lightning Carpet-XCOM ++ WorldHelper.startTickTask(TickTask.TICK_CHUNKS); // RSMM for (Iterator iterator = this.field_73063_M.func_187300_b(); iterator.hasNext(); this.field_72984_F.func_76319_b()) { -@@ -355,9 +477,14 @@ + this.field_72984_F.func_76320_a("getChunk"); +@@ -354,10 +535,18 @@ + this.field_72984_F.func_76318_c("checkNextLight"); chunk.func_76594_o(); this.field_72984_F.func_76318_c("tickChunk"); ++ WorldHelper.startTickTask(TickTask.TICK_CHUNK); // RSMM chunk.func_150804_b(false); + if (!TickSpeed.process_entities) + { // skipping the rest of the block processing + this.field_72984_F.func_76319_b(); ++ WorldHelper.endTickTask(); // RSMM + continue; + } this.field_72984_F.func_76318_c("thunder"); ++ WorldHelper.swapTickTask(TickTask.THUNDER); // RSMM - if (flag && flag1 && this.field_73012_v.nextInt(100000) == 0) + if (overworldIceOnly && flag && flag1 && this.field_73012_v.nextInt(100000) == 0) { this.field_73005_l = this.field_73005_l * 3 + 1013904223; int l = this.field_73005_l >> 2; -@@ -385,7 +512,7 @@ +@@ -384,8 +573,9 @@ + } this.field_72984_F.func_76318_c("iceandsnow"); ++ WorldHelper.swapTickTask(TickTask.PRECIPITATION); // RSMM - if (this.field_73012_v.nextInt(16) == 0) + if (overworldIceOnly && this.field_73012_v.nextInt(16) == 0) { this.field_73005_l = this.field_73005_l * 3 + 1013904223; int j2 = this.field_73005_l >> 2; -@@ -443,7 +570,7 @@ +@@ -409,6 +599,7 @@ + } + + this.field_72984_F.func_76318_c("tickBlocks"); ++ WorldHelper.swapTickTask(TickTask.RANDOM_TICKS); // RSMM + + if (i > 0) + { +@@ -429,7 +620,15 @@ + + if (block.func_149653_t()) + { +- block.func_180645_a(this, new BlockPos(k1 + j, i2 + extendedblockstorage.func_76662_d(), l1 + k), iblockstate, this.field_73012_v); ++ // RSMM start - capture position of random tick ++ int x = k1 + j; ++ int z = l1 + k; ++ int y = i2 + extendedblockstorage.func_76662_d(); ++ BlockPos pos = new BlockPos(x, y, z); ++ WorldHelper.onRandomTick(this, pos); ++ // RSMM end ++ ++ block.func_180645_a(this, pos, iblockstate, this.field_73012_v); + } + + this.field_72984_F.func_76319_b(); +@@ -437,13 +636,16 @@ + } + } + } ++ ++ WorldHelper.endTickTask(); // RSMM + } + + this.field_72984_F.func_76319_b(); ++ WorldHelper.endTickTask(); // RSMM } } @@ -294,7 +436,7 @@ { BlockPos blockpos = this.func_175725_q(p_175736_1_); AxisAlignedBB axisalignedbb = (new AxisAlignedBB(blockpos, new BlockPos(blockpos.func_177958_n(), this.func_72800_K(), blockpos.func_177952_p()))).func_186662_g(3.0D); -@@ -472,13 +599,25 @@ +@@ -472,13 +674,25 @@ public boolean func_175691_a(BlockPos p_175691_1_, Block p_175691_2_) { @@ -322,8 +464,15 @@ return this.field_73064_N.contains(nextticklistentry); } -@@ -503,15 +642,22 @@ +@@ -501,17 +715,29 @@ + + if (iblockstate.func_185904_a() != Material.field_151579_a && iblockstate.func_177230_c() == p_175654_2_) { ++ // Limiter for instant tile ticks to prevent crashes CARPET-XCOM ++ if(CarpetSettings.limitITTupdates > 0 && field_73061_a.func_152345_ab()){ ++ CarpetServer.limitITTCounter++; ++ if(CarpetServer.limitITTCounter > CarpetSettings.limitITTupdates) return; ++ } iblockstate.func_177230_c().func_180650_b(this, p_175654_1_, iblockstate, this.field_73012_v); } + if(RandomTickOptimization.needsWorldGenFix) return; @@ -347,7 +496,14 @@ if (this.func_175667_e(p_175654_1_)) { -@@ -531,7 +677,13 @@ +@@ -525,13 +751,20 @@ + { + this.field_73064_N.add(nextticklistentry); + this.field_73065_O.add(nextticklistentry); ++ WorldHelper.onScheduledTick(this, p_175654_1_, p_175654_4_, true); // RSMM + } + } + } public void func_180497_b(BlockPos p_180497_1_, Block p_180497_2_, int p_180497_3_, int p_180497_4_) { @@ -362,7 +518,13 @@ nextticklistentry.func_82753_a(p_180497_4_); Material material = p_180497_2_.func_176223_P().func_185904_a(); -@@ -549,7 +701,8 @@ +@@ -544,12 +777,14 @@ + { + this.field_73064_N.add(nextticklistentry); + this.field_73065_O.add(nextticklistentry); ++ WorldHelper.onScheduledTick(this, p_180497_1_, p_180497_4_, true); // RSMM + } + } public void func_72939_s() { @@ -372,7 +534,25 @@ { if (this.field_80004_Q++ >= 300) { -@@ -644,9 +797,18 @@ +@@ -567,6 +802,8 @@ + + protected void func_184147_l() + { ++ WorldHelper.startTickTask(TickTask.PLAYERS); // RSMM ++ + super.func_184147_l(); + this.field_72984_F.func_76318_c("players"); + +@@ -621,6 +858,8 @@ + + this.field_72984_F.func_76319_b(); + } ++ ++ WorldHelper.endTickTask(); // RSMM + } + + public void func_82742_i() +@@ -644,9 +883,18 @@ } else { @@ -393,7 +573,7 @@ } this.field_72984_F.func_76320_a("cleaning"); -@@ -677,6 +839,8 @@ +@@ -677,12 +925,15 @@ if (this.func_175707_a(nextticklistentry1.field_180282_a.func_177982_a(0, 0, 0), nextticklistentry1.field_180282_a.func_177982_a(0, 0, 0))) { @@ -402,7 +582,14 @@ IBlockState iblockstate = this.func_180495_p(nextticklistentry1.field_180282_a); if (iblockstate.func_185904_a() != Material.field_151579_a && Block.func_149680_a(iblockstate.func_177230_c(), nextticklistentry1.func_151351_a())) -@@ -699,6 +863,7 @@ + { + try + { ++ WorldHelper.onScheduledTick(this, nextticklistentry1.field_180282_a, nextticklistentry1.field_82754_f, false); // RSMM + iblockstate.func_177230_c().func_180650_b(this, nextticklistentry1.field_180282_a, iblockstate, this.field_73012_v); + } + catch (Throwable throwable) +@@ -699,6 +950,7 @@ this.func_175684_a(nextticklistentry1.field_180282_a, nextticklistentry1.func_151351_a(), 0); } } @@ -410,7 +597,7 @@ this.field_72984_F.func_76319_b(); this.field_94579_S.clear(); -@@ -950,11 +1115,18 @@ +@@ -950,11 +1202,18 @@ chunkproviderserver.func_186027_a(p_73044_1_); @@ -430,7 +617,7 @@ } } } -@@ -1033,9 +1205,15 @@ +@@ -1033,9 +1292,15 @@ } else { @@ -446,7 +633,7 @@ return false; } -@@ -1055,6 +1233,7 @@ +@@ -1055,6 +1320,7 @@ this.field_175729_l.func_76038_a(p_72923_1_.func_145782_y(), p_72923_1_); this.field_175741_N.put(p_72923_1_.func_110124_au(), p_72923_1_); Entity[] aentity = p_72923_1_.func_70021_al(); @@ -454,15 +641,24 @@ if (aentity != null) { -@@ -1139,6 +1318,7 @@ +@@ -1139,10 +1405,16 @@ } this.field_147490_S[this.field_147489_T].add(blockeventdata); + if(CarpetSettings.blockEventSerializer) blockEventSerializer.func_76185_a(); ++ WorldHelper.onBlockEvent(this, p_175641_1_, p_175641_3_, true); // RSMM } private void func_147488_Z() -@@ -1150,14 +1330,19 @@ + { ++ WorldHelper.startTickTask(TickTask.BLOCK_EVENTS); // RSMM ++ ++ WorldHelper.currentBlockEventDepth = 0; // RSMM ++ + while (!this.field_147490_S[this.field_147489_T].isEmpty()) + { + int i = this.field_147489_T; +@@ -1150,19 +1422,33 @@ for (BlockEventData blockeventdata : this.field_147490_S[i]) { @@ -476,13 +672,45 @@ + carpet.carpetclient.CarpetClientChunkLogger.resetReason(); this.field_147490_S[i].clear(); ++ ++ WorldHelper.currentBlockEventDepth++; // RSMM } + // [CM] Piston ghost blocks fix + this.blockActionsProcessed = true; ++ ++ WorldHelper.endTickTask(); // RSMM } private boolean func_147485_a(BlockEventData p_147485_1_) -@@ -1299,4 +1484,19 @@ + { + IBlockState iblockstate = this.func_180495_p(p_147485_1_.func_180328_a()); ++ // RSMM start ++ if (iblockstate.func_177230_c() == p_147485_1_.func_151337_f()) { ++ WorldHelper.onBlockEvent(this, p_147485_1_.func_180328_a(), p_147485_1_.func_151339_d(), false); ++ } ++ // RSMM end + return iblockstate.func_177230_c() == p_147485_1_.func_151337_f() ? iblockstate.func_189547_a(this, p_147485_1_.func_180328_a(), p_147485_1_.func_151339_d(), p_147485_1_.func_151338_e()) : false; + } + +@@ -1173,6 +1459,8 @@ + + protected void func_72979_l() + { ++ WorldHelper.startTickTask(TickTask.WEATHER); // RSMM ++ + boolean flag = this.func_72896_J(); + super.func_72979_l(); + +@@ -1200,6 +1488,8 @@ + this.field_73061_a.func_184103_al().func_148540_a(new SPacketChangeGameState(7, this.field_73004_o)); + this.field_73061_a.func_184103_al().func_148540_a(new SPacketChangeGameState(8, this.field_73017_q)); + } ++ ++ WorldHelper.endTickTask(); // RSMM + } + + @Nullable +@@ -1299,4 +1589,19 @@ { } } diff --git a/patches/net/minecraft/world/chunk/BlockStateContainer.java.patch b/patches/net/minecraft/world/chunk/BlockStateContainer.java.patch new file mode 100644 index 00000000..85847045 --- /dev/null +++ b/patches/net/minecraft/world/chunk/BlockStateContainer.java.patch @@ -0,0 +1,17 @@ +--- ../src-base/minecraft/net/minecraft/world/chunk/BlockStateContainer.java ++++ ../src-work/minecraft/net/minecraft/world/chunk/BlockStateContainer.java +@@ -146,4 +146,14 @@ + { + return 1 + this.field_186022_c.func_186040_a() + PacketBuffer.func_150790_a(this.field_186021_b.func_188144_b()) + this.field_186021_b.func_188143_a().length * 8; + } ++ ++ public BitArray getStorage(){ ++ return field_186021_b; ++ } ++ public IBlockStatePalette getPalette(){ ++ return field_186022_c; ++ } ++ public int getBits(){ ++ return field_186024_e; ++ } + } diff --git a/patches/net/minecraft/world/chunk/BlockStatePaletteHashMap.java.patch b/patches/net/minecraft/world/chunk/BlockStatePaletteHashMap.java.patch new file mode 100644 index 00000000..b802c78f --- /dev/null +++ b/patches/net/minecraft/world/chunk/BlockStatePaletteHashMap.java.patch @@ -0,0 +1,11 @@ +--- ../src-base/minecraft/net/minecraft/world/chunk/BlockStatePaletteHashMap.java ++++ ../src-work/minecraft/net/minecraft/world/chunk/BlockStatePaletteHashMap.java +@@ -64,4 +64,8 @@ + + return i; + } ++ ++ public int paletteSize(){ ++ return field_186046_a.func_186810_b(); ++ } + } diff --git a/patches/net/minecraft/world/chunk/BlockStatePaletteLinear.java.patch b/patches/net/minecraft/world/chunk/BlockStatePaletteLinear.java.patch new file mode 100644 index 00000000..39621154 --- /dev/null +++ b/patches/net/minecraft/world/chunk/BlockStatePaletteLinear.java.patch @@ -0,0 +1,11 @@ +--- ../src-base/minecraft/net/minecraft/world/chunk/BlockStatePaletteLinear.java ++++ ../src-work/minecraft/net/minecraft/world/chunk/BlockStatePaletteLinear.java +@@ -70,4 +70,8 @@ + + return i; + } ++ ++ public int paletteSize(){ ++ return field_186045_d; ++ } + } diff --git a/patches/net/minecraft/world/chunk/Chunk.java.patch b/patches/net/minecraft/world/chunk/Chunk.java.patch index 79a64567..deb4b685 100644 --- a/patches/net/minecraft/world/chunk/Chunk.java.patch +++ b/patches/net/minecraft/world/chunk/Chunk.java.patch @@ -1,9 +1,6 @@ --- ../src-base/minecraft/net/minecraft/world/chunk/Chunk.java +++ ../src-work/minecraft/net/minecraft/world/chunk/Chunk.java -@@ -1,12 +1,11 @@ - package net.minecraft.world.chunk; - -+import carpet.CarpetServer; +@@ -3,10 +3,8 @@ import com.google.common.base.Predicate; import com.google.common.collect.Maps; import com.google.common.collect.Queues; @@ -16,7 +13,13 @@ import java.util.concurrent.ConcurrentLinkedQueue; import javax.annotation.Nullable; import net.minecraft.block.Block; -@@ -38,6 +37,11 @@ +@@ -35,9 +33,17 @@ + import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + import net.minecraft.world.gen.ChunkGeneratorDebug; + import net.minecraft.world.gen.IChunkGenerator; ++ ++import redstone.multimeter.helper.WorldHelper; ++ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -28,7 +31,7 @@ public class Chunk { private static final Logger field_150817_t = LogManager.getLogger(); -@@ -66,13 +70,17 @@ +@@ -66,13 +72,17 @@ private final ConcurrentLinkedQueue field_177447_w; public boolean field_189550_d; @@ -47,7 +50,7 @@ this.field_76649_t = 4096; this.field_177447_w = Queues.newConcurrentLinkedQueue(); this.field_76645_j = (ClassInheritanceMultiMap[])(new ClassInheritanceMultiMap[16]); -@@ -188,38 +196,43 @@ +@@ -188,38 +198,43 @@ if (this.field_76637_e.field_73011_w.func_191066_m()) { @@ -116,7 +119,7 @@ } } } -@@ -307,7 +320,13 @@ +@@ -307,7 +322,13 @@ private void func_76615_h(int p_76615_1_, int p_76615_2_, int p_76615_3_) { @@ -131,7 +134,7 @@ int j = i; if (p_76615_2_ > i) -@@ -322,66 +341,72 @@ +@@ -322,66 +343,72 @@ if (j != i) { @@ -249,7 +252,7 @@ } int l1 = this.field_76634_f[p_76615_3_ << 4 | p_76615_1_]; -@@ -399,6 +424,12 @@ +@@ -399,6 +426,12 @@ this.field_82912_p = l1; } @@ -262,7 +265,7 @@ if (this.field_76637_e.field_73011_w.func_191066_m()) { for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) -@@ -478,12 +509,19 @@ +@@ -478,12 +511,19 @@ } } @@ -285,7 +288,7 @@ int l = k << 4 | i; if (j >= this.field_76638_b[l] - 1) -@@ -492,15 +530,15 @@ +@@ -492,15 +532,15 @@ } int i1 = this.field_76634_f[l]; @@ -304,7 +307,7 @@ Block block1 = iblockstate.func_177230_c(); ExtendedBlockStorage extendedblockstorage = this.field_76652_q[j >> 4]; boolean flag = false; -@@ -515,19 +553,23 @@ +@@ -515,19 +555,29 @@ extendedblockstorage = new ExtendedBlockStorage(j >> 4 << 4, this.field_76637_e.field_73011_w.func_191066_m()); this.field_76652_q[j >> 4] = extendedblockstorage; flag = j >= i1; @@ -317,6 +320,12 @@ - extendedblockstorage.func_177484_a(i, j & 15, k, p_177436_2_); + extendedblockstorage.func_177484_a(i, j & 15, k, state); ++ // RSMM start ++ if (CarpetSettings.redstoneMultimeter && !field_76637_e.field_72995_K) { ++ WorldHelper.getMultimeter().onBlockChange(field_76637_e, pos, iblockstate, state); ++ } ++ // RSMM end ++ if (block1 != block) { - if (!this.field_76637_e.field_72995_K) @@ -332,7 +341,7 @@ } } -@@ -537,13 +579,13 @@ +@@ -537,13 +587,13 @@ } else { @@ -348,7 +357,7 @@ int k1 = iblockstate.func_185891_c(); if (j1 > 0) -@@ -558,15 +600,17 @@ +@@ -558,15 +608,17 @@ this.func_76615_h(i, j, k); } @@ -371,7 +380,7 @@ if (tileentity != null) { -@@ -574,19 +618,30 @@ +@@ -574,19 +626,30 @@ } } @@ -407,17 +416,17 @@ } if (tileentity1 != null) -@@ -596,6 +651,9 @@ +@@ -596,6 +659,9 @@ } this.field_76643_l = true; + // ----- RSMM Start ----- // -+ if (CarpetSettings.redstoneMultimeter) { StateChangeEventDispatcher.dispatchEvent(this.func_177412_p(), pos); } ++ if (CarpetSettings.redstoneMultimeterLegacy) { StateChangeEventDispatcher.dispatchEvent(this.func_177412_p(), pos); } + // ----- RSMM End ----- // return iblockstate; } } -@@ -603,6 +661,7 @@ +@@ -603,6 +669,7 @@ public int func_177413_a(EnumSkyBlock p_177413_1_, BlockPos p_177413_2_) { @@ -425,7 +434,7 @@ int i = p_177413_2_.func_177958_n() & 15; int j = p_177413_2_.func_177956_o(); int k = p_177413_2_.func_177952_p() & 15; -@@ -633,7 +692,12 @@ +@@ -633,7 +700,12 @@ { extendedblockstorage = new ExtendedBlockStorage(j >> 4 << 4, this.field_76637_e.field_73011_w.func_191066_m()); this.field_76652_q[j >> 4] = extendedblockstorage; @@ -439,7 +448,7 @@ } this.field_76643_l = true; -@@ -653,6 +717,7 @@ +@@ -653,6 +725,7 @@ public int func_177443_a(BlockPos p_177443_1_, int p_177443_2_) { @@ -447,7 +456,7 @@ int i = p_177443_1_.func_177958_n() & 15; int j = p_177443_1_.func_177956_o(); int k = p_177443_1_.func_177952_p() & 15; -@@ -819,6 +884,10 @@ +@@ -819,6 +892,10 @@ { this.field_76637_e.func_175650_b(classinheritancemultimap); } @@ -458,7 +467,7 @@ } public void func_76623_d() -@@ -964,13 +1033,40 @@ +@@ -964,13 +1041,40 @@ { if (p_186034_1_.func_185933_a(this, this.field_76635_g, this.field_76647_h)) { @@ -500,7 +509,7 @@ this.func_76630_e(); } } -@@ -1018,10 +1114,13 @@ +@@ -1018,10 +1122,13 @@ this.field_150815_m = true; @@ -518,7 +527,7 @@ while (!this.field_177447_w.isEmpty()) { -@@ -1041,6 +1140,11 @@ +@@ -1041,6 +1148,11 @@ return this.field_150815_m && this.field_76646_k && this.field_150814_l; } @@ -530,7 +539,7 @@ public boolean func_186035_j() { return this.field_150815_m; -@@ -1389,4 +1493,67 @@ +@@ -1389,4 +1501,67 @@ QUEUED, CHECK; } diff --git a/patches/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java.patch b/patches/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java.patch index f66168e3..b7b3d3ee 100644 --- a/patches/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java.patch +++ b/patches/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java.patch @@ -23,3 +23,12 @@ } public boolean func_76675_b() +@@ -147,4 +154,8 @@ + { + this.field_76685_h = p_76666_1_; + } ++ ++ public BlockStateContainer getBlockStateContainer() { ++ return field_177488_d; ++ } + } diff --git a/patches/net/minecraft/world/end/DragonFightManager.java.patch b/patches/net/minecraft/world/end/DragonFightManager.java.patch index b8b1bdaf..8c2595c9 100644 --- a/patches/net/minecraft/world/end/DragonFightManager.java.patch +++ b/patches/net/minecraft/world/end/DragonFightManager.java.patch @@ -1,6 +1,13 @@ --- ../src-base/minecraft/net/minecraft/world/end/DragonFightManager.java +++ ../src-work/minecraft/net/minecraft/world/end/DragonFightManager.java -@@ -48,6 +48,8 @@ +@@ -45,9 +45,15 @@ + import net.minecraft.world.gen.feature.WorldGenEndGateway; + import net.minecraft.world.gen.feature.WorldGenEndPodium; + import net.minecraft.world.gen.feature.WorldGenSpikes; ++ ++import redstone.multimeter.common.TickTask; ++import redstone.multimeter.helper.WorldHelper; ++ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -9,7 +16,25 @@ public class DragonFightManager { private static final Logger field_186107_a = LogManager.getLogger(); -@@ -437,6 +439,8 @@ +@@ -149,6 +155,8 @@ + + public void func_186105_b() + { ++ WorldHelper.startTickTask(TickTask.DRAGON_FIGHT); // RSMM ++ + this.field_186109_c.func_186758_d(!this.field_186117_k); + + if (++this.field_186116_j >= 20) +@@ -244,6 +252,8 @@ + } + } + } ++ ++ WorldHelper.endTickTask(); // RSMM + } + + protected void func_186095_a(DragonSpawnManager p_186095_1_) +@@ -437,6 +447,8 @@ } } diff --git a/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch b/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch index b8e5c73e..9115bcc8 100644 --- a/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch +++ b/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch @@ -71,7 +71,7 @@ chunk.field_189550_d = false; } -@@ -93,9 +120,17 @@ +@@ -93,9 +120,26 @@ if (chunk != null) { @@ -79,6 +79,15 @@ + if(CarpetClientChunkLogger.logger.enabled) { + CarpetClientChunkLogger.logger.log(this.field_73251_h,p_186028_1_,p_186028_2_,CarpetClientChunkLogger.Event.LOADING); + } ++ ++ // Fix for chunks not updating after async updates CARPET-PUNCHSTER ++ if(CarpetSettings.asyncPacketUpdatesFix) { ++ PlayerChunkMapEntry entry = field_73251_h.field_73063_M.func_187301_b(p_186028_1_, p_186028_2_); ++ if (entry != null && entry.field_187286_f != null) { ++ entry.field_187286_f = chunk; ++ entry.func_187272_b(); ++ } ++ } + this.field_73244_f.put(ChunkPos.func_77272_a(p_186028_1_, p_186028_2_), chunk); chunk.func_76631_c(); @@ -89,7 +98,7 @@ } } -@@ -113,6 +148,11 @@ +@@ -113,6 +157,11 @@ try { chunk = this.field_186029_c.func_185932_a(p_186025_1_, p_186025_2_); @@ -101,7 +110,7 @@ } catch (Throwable throwable) { -@@ -123,7 +163,7 @@ +@@ -123,7 +172,7 @@ crashreportcategory.func_71507_a("Generator", this.field_186029_c); throw new ReportedException(crashreport); } @@ -110,7 +119,7 @@ this.field_73244_f.put(i, chunk); chunk.func_76631_c(); chunk.func_186030_a(this, this.field_186029_c); -@@ -185,6 +225,8 @@ +@@ -185,6 +234,8 @@ public boolean func_186027_a(boolean p_186027_1_) { @@ -119,7 +128,7 @@ int i = 0; List list = Lists.newArrayList(this.field_73244_f.values()); -@@ -222,8 +264,12 @@ +@@ -222,8 +273,12 @@ { if (!this.field_73251_h.field_73058_d) { @@ -133,7 +142,7 @@ Iterator iterator = this.field_73248_b.iterator(); for (int i = 0; i < 100 && iterator.hasNext(); iterator.remove()) -@@ -231,16 +277,47 @@ +@@ -231,16 +286,47 @@ Long olong = iterator.next(); Chunk chunk = (Chunk)this.field_73244_f.get(olong); @@ -182,7 +191,7 @@ this.field_73247_e.func_75817_a(); } -@@ -283,9 +360,17 @@ +@@ -283,9 +369,17 @@ { return this.field_73244_f.containsKey(ChunkPos.func_77272_a(p_73149_1_, p_73149_2_)); }