From 770fbd6aaace182975cd8dee13e89ac40bf0d3d7 Mon Sep 17 00:00:00 2001 From: Zelophed Date: Fri, 4 Sep 2020 18:04:00 +0200 Subject: [PATCH] crude dev tool for chunk unloading - add a dev utility that allows us to force-unload chunks - move mechanical arm scrollbox - fix oxidizing blocks trying to access a blockstate from unloaded chunks when on the border --- src/main/java/com/simibubi/create/Create.java | 7 ++ .../block/mechanicalArm/ArmTileEntity.java | 19 +++- .../foundation/command/AllCommands.java | 14 ++- .../create/foundation/command/ChunkUtil.java | 103 ++++++++++++++++++ .../foundation/command/ChunkUtilCommand.java | 66 +++++++++++ .../foundation/worldgen/OxidizingBlock.java | 11 +- .../resources/META-INF/accesstransformer.cfg | 14 ++- 7 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/simibubi/create/foundation/command/ChunkUtil.java create mode 100644 src/main/java/com/simibubi/create/foundation/command/ChunkUtilCommand.java diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 76208a472..413289fc7 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -1,5 +1,7 @@ package com.simibubi.create; +import com.simibubi.create.foundation.command.ChunkUtil; +import net.minecraftforge.common.MinecraftForge; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -59,6 +61,7 @@ public class Create { public static RedstoneLinkNetworkHandler redstoneLinkNetworkHandler; public static TorquePropagator torquePropagator; public static ServerLagger lagger; + public static ChunkUtil chunkUtil; private static final NonNullLazyValue registrate = CreateRegistrate.lazy(ID); @@ -94,6 +97,10 @@ public class Create { torquePropagator = new TorquePropagator(); lagger = new ServerLagger(); + chunkUtil = new ChunkUtil(); + chunkUtil.init(); + MinecraftForge.EVENT_BUS.register(chunkUtil); + AllPackets.registerPackets(); AllTriggers.register(); AllWorldFeatures.reload(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 524dc133b..9d5784e50 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -13,6 +13,7 @@ import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOpt import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.block.JukeboxBlock; import net.minecraft.item.ItemStack; @@ -22,6 +23,7 @@ import net.minecraft.nbt.ListNBT; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraftforge.common.util.Constants.NBT; import javax.annotation.Nullable; @@ -81,9 +83,20 @@ public class ArmTileEntity extends KineticTileEntity { super.addBehaviours(behaviours); selectionMode = new ScrollOptionBehaviour<>(SelectionMode.class, Lang.translate("mechanical_arm.selection_mode"), this, - new CenteredSideValueBoxTransform((blockState, direction) -> { - return direction != Direction.DOWN && direction != Direction.UP; - })); + new CenteredSideValueBoxTransform((blockState, direction) -> direction != Direction.DOWN && direction != Direction.UP) { + @Override + protected Vec3d getLocalOffset(BlockState state) { + int yPos = state.get(ArmBlock.CEILING) ? 16 - 3 : 3; + Vec3d location = VecHelper.voxelSpace(8, yPos, 14.5); + location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Direction.Axis.Y); + return location; + } + + @Override + protected float getScale() { + return .3f; + } + }); selectionMode.requiresWrench(); behaviours.add(selectionMode); } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index ec5f2fca8..e726181f4 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -1,7 +1,6 @@ package com.simibubi.create.foundation.command; import com.mojang.brigadier.CommandDispatcher; - import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; @@ -9,10 +8,15 @@ public class AllCommands { public static void register(CommandDispatcher dispatcher) { dispatcher.register(Commands.literal("create") - .then(ToggleDebugCommand.register()) - .then(OverlayConfigCommand.register()) - .then(ClearBufferCacheCommand.register()) - // .then(KillTPSCommand.register()) //Commented out for release + //general purpose + .then(ToggleDebugCommand.register()) + .then(OverlayConfigCommand.register()) + + //dev-util + //Comment out for release + .then(ClearBufferCacheCommand.register()) + .then(ChunkUtilCommand.register()) + // .then(KillTPSCommand.register()) ); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ChunkUtil.java b/src/main/java/com/simibubi/create/foundation/command/ChunkUtil.java new file mode 100644 index 000000000..f88e9ab3d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ChunkUtil.java @@ -0,0 +1,103 @@ +package com.simibubi.create.foundation.command; + +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.server.ChunkHolder; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.EnumSet; +import java.util.LinkedList; +import java.util.List; + +public class ChunkUtil { + private static final Logger LOGGER = LogManager.getLogger("Create/ChunkUtil"); + final EnumSet POST_FEATURES = EnumSet.of(Heightmap.Type.OCEAN_FLOOR, Heightmap.Type.WORLD_SURFACE, Heightmap.Type.MOTION_BLOCKING, Heightmap.Type.MOTION_BLOCKING_NO_LEAVES); + + private final List markedChunks; + private final List interestingChunks; + + public ChunkUtil() { + LOGGER.debug("Chunk Util constructed"); + markedChunks = new LinkedList<>(); + interestingChunks = new LinkedList<>(); + } + + public void init() { + ChunkStatus.FULL = new ChunkStatus("full", ChunkStatus.HEIGHTMAPS, 0, POST_FEATURES, ChunkStatus.Type.LEVELCHUNK, + (_0, _1, _2, _3, _4, future, _6, chunk) -> future.apply(chunk), + (_0, _1, _2, _3, future, chunk) -> { + if (markedChunks.contains(chunk.getPos().asLong())) { + LOGGER.debug("trying to load unforced chunk " + chunk.getPos().toString() + ", returning chunk loading error"); + //this.reloadChunk(world.getChunkProvider(), chunk.getPos()); + return ChunkHolder.MISSING_CHUNK_FUTURE; + } else { + //LOGGER.debug("regular, chunkStatus: " + chunk.getStatus().toString()); + return future.apply(chunk); + } + }); + + } + + public boolean reloadChunk(ServerChunkProvider provider, ChunkPos pos) { + ChunkHolder holder = provider.chunkManager.loadedChunks.remove(pos.asLong()); + provider.chunkManager.immutableLoadedChunksDirty = true; + if (holder != null) { + provider.chunkManager.chunksToUnload.put(pos.asLong(), holder); + provider.chunkManager.scheduleSave(pos.asLong(), holder); + return true; + } else { + return false; + } + } + + public boolean unloadChunk(ServerChunkProvider provider, ChunkPos pos) { + this.interestingChunks.add(pos.asLong()); + this.markedChunks.add(pos.asLong()); + + return this.reloadChunk(provider, pos); + } + + public int clear(ServerChunkProvider provider) { + LinkedList copy = new LinkedList<>(this.markedChunks); + + int size = this.markedChunks.size(); + this.markedChunks.clear(); + + copy.forEach(l -> reForce(provider, new ChunkPos(l))); + + return size; + } + + public void reForce(ServerChunkProvider provider, ChunkPos pos) { + provider.forceChunk(pos, true); + provider.forceChunk(pos, false); + } + + @SubscribeEvent + public void chunkUnload(ChunkEvent.Unload event) { + //LOGGER.debug("Chunk Unload: " + event.getChunk().getPos().toString()); + if (interestingChunks.contains(event.getChunk().getPos().asLong())) { + LOGGER.info("Interesting Chunk Unload: " + event.getChunk().getPos().toString()); + } + } + + @SubscribeEvent + public void chunkLoad(ChunkEvent.Load event) { + //LOGGER.debug("Chunk Load: " + event.getChunk().getPos().toString()); + + ChunkPos pos = event.getChunk().getPos(); + if (interestingChunks.contains(pos.asLong())) { + LOGGER.info("Interesting Chunk Load: " + pos.toString()); + if (!markedChunks.contains(pos.asLong())) + interestingChunks.remove(pos.asLong()); + } + + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/ChunkUtilCommand.java b/src/main/java/com/simibubi/create/foundation/command/ChunkUtilCommand.java new file mode 100644 index 000000000..48272f723 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ChunkUtilCommand.java @@ -0,0 +1,66 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.simibubi.create.Create; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.ColumnPosArgument; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.ColumnPos; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.server.ServerChunkProvider; + +public class ChunkUtilCommand { + + public static ArgumentBuilder register() { + return Commands.literal("chunk") + .requires(cs -> cs.hasPermissionLevel(2)) + .then(Commands.literal("reload").then(Commands.argument("pos", ColumnPosArgument.columnPos()) + .executes(ctx -> { + //chunk reload + ColumnPos columnPos = ColumnPosArgument.fromBlockPos(ctx, "pos"); + ChunkPos chunkPos = new ChunkPos(columnPos.x >> 4, columnPos.z >> 4); + ServerChunkProvider chunkProvider = ctx.getSource().getWorld().getChunkProvider(); + + boolean success = Create.chunkUtil.reloadChunk(chunkProvider, chunkPos); + + if (success) { + ctx.getSource().sendFeedback(new StringTextComponent("scheduled unload for chunk " + chunkPos.toString() + ", might need to repeat command"), true); + return 1; + } else { + ctx.getSource().sendFeedback(new StringTextComponent("unable to schedule unload, is chunk " + chunkPos.toString() + " loaded?"), true); + return 0; + } + }) + )) + .then(Commands.literal("unload").then(Commands.argument("pos", ColumnPosArgument.columnPos()) + .executes(ctx -> { + //chunk unload + ColumnPos columnPos = ColumnPosArgument.fromBlockPos(ctx, "pos"); + ChunkPos chunkPos = new ChunkPos(columnPos.x >> 4, columnPos.z >> 4); + ServerChunkProvider chunkProvider = ctx.getSource().getWorld().getChunkProvider(); + + boolean success = Create.chunkUtil.unloadChunk(chunkProvider, chunkPos); + ctx.getSource().sendFeedback(new StringTextComponent("added chunk " + chunkPos.toString() + " to unload list"), true); + + if (success) { + ctx.getSource().sendFeedback(new StringTextComponent("scheduled unload for chunk " + chunkPos.toString() + ", might need to repeat command"), true); + return 1; + } else { + ctx.getSource().sendFeedback(new StringTextComponent("unable to schedule unload, is chunk " + chunkPos.toString() + " loaded?"), true); + return 0; + } + }) + )) + .then(Commands.literal("clear") + .executes(ctx -> { + //chunk clear + int count = Create.chunkUtil.clear(ctx.getSource().getWorld().getChunkProvider()); + ctx.getSource().sendFeedback(new StringTextComponent("removed " + count + " entries from unload list"), false); + + return 1; + }) + ); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/worldgen/OxidizingBlock.java b/src/main/java/com/simibubi/create/foundation/worldgen/OxidizingBlock.java index 101edd2c2..0d3104747 100644 --- a/src/main/java/com/simibubi/create/foundation/worldgen/OxidizingBlock.java +++ b/src/main/java/com/simibubi/create/foundation/worldgen/OxidizingBlock.java @@ -1,12 +1,7 @@ package com.simibubi.create.foundation.worldgen; -import java.util.LinkedList; -import java.util.OptionalDouble; -import java.util.Random; - import com.simibubi.create.content.curiosities.tools.SandPaperItem; import com.simibubi.create.content.palettes.MetalBlock; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -21,6 +16,10 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; +import java.util.LinkedList; +import java.util.OptionalDouble; +import java.util.Random; + public class OxidizingBlock extends MetalBlock { public static final IntegerProperty OXIDIZATION = IntegerProperty.create("oxidization", 0, 7); @@ -56,6 +55,8 @@ public class OxidizingBlock extends MetalBlock { LinkedList neighbors = new LinkedList<>(); for (Direction facing : Direction.values()) { BlockPos neighbourPos = pos.offset(facing); + if (!worldIn.isAreaLoaded(neighbourPos, 0)) + continue; if (!worldIn.isBlockPresent(neighbourPos)) continue; BlockState neighborState = worldIn.getBlockState(neighbourPos); diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 5af4e7e17..549553b12 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,4 +1,16 @@ public net.minecraft.network.play.ServerPlayNetHandler field_147365_f # floatingTickCount # CubeParticle -protected net.minecraft.client.particle.Particle field_228343_B_ # collidedY \ No newline at end of file +protected net.minecraft.client.particle.Particle field_228343_B_ # collidedY + +# Needed for ChunkUtil, maybe remove these for releases +# ChunkManager +public net.minecraft.world.server.ChunkManager func_219212_a(JLnet/minecraft/world/server/ChunkHolder;)V #scheduleSave +public net.minecraft.world.server.ChunkManager field_219251_e #loadedChunks +public net.minecraft.world.server.ChunkManager field_219262_p #immutableLoadedChunksDirty +public net.minecraft.world.server.ChunkManager field_219253_g #chunksToUnload + +# ChunkStatus +public-f net.minecraft.world.chunk.ChunkStatus field_222617_m #FULL +public net.minecraft.world.chunk.ChunkStatus$IGenerationWorker +public net.minecraft.world.chunk.ChunkStatus$ILoadingWorker \ No newline at end of file