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
This commit is contained in:
Zelophed 2020-09-04 18:04:00 +02:00
parent 5a7c09aa25
commit 770fbd6aaa
7 changed files with 220 additions and 14 deletions

View file

@ -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<CreateRegistrate> 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();

View file

@ -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);
}

View file

@ -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<CommandSource> dispatcher) {
dispatcher.register(Commands.literal("create")
//general purpose
.then(ToggleDebugCommand.register())
.then(OverlayConfigCommand.register())
//dev-util
//Comment out for release
.then(ClearBufferCacheCommand.register())
// .then(KillTPSCommand.register()) //Commented out for release
.then(ChunkUtilCommand.register())
// .then(KillTPSCommand.register())
);
}
}

View file

@ -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<Heightmap.Type> 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<Long> markedChunks;
private final List<Long> 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<Long> 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());
}
}
}

View file

@ -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<CommandSource, ?> register() {
return Commands.literal("chunk")
.requires(cs -> cs.hasPermissionLevel(2))
.then(Commands.literal("reload").then(Commands.argument("pos", ColumnPosArgument.columnPos())
.executes(ctx -> {
//chunk reload <pos>
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 <pos>
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;
})
);
}
}

View file

@ -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<Integer> 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);

View file

@ -2,3 +2,15 @@ public net.minecraft.network.play.ServerPlayNetHandler field_147365_f # floating
# CubeParticle
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