diff --git a/src/main/java/com/colen/postea/Postea.java b/src/main/java/com/colen/postea/Postea.java index 40db775..18f90b8 100644 --- a/src/main/java/com/colen/postea/Postea.java +++ b/src/main/java/com/colen/postea/Postea.java @@ -1,9 +1,7 @@ package com.colen.postea; -import com.colen.postea.checker.PosteaProcessedChunksWorldSavedData; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.common.MinecraftForge; @Mod(modid = Tags.MODID, version = Tags.VERSION, name = Tags.MODNAME, acceptedMinecraftVersions = "[1.7.10]") @SuppressWarnings("unused") @@ -11,7 +9,6 @@ public class Postea { @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { - MinecraftForge.EVENT_BUS.register(new PosteaProcessedChunksWorldSavedData("")); } } diff --git a/src/main/java/com/colen/postea/Utility/ChunkFixerUtility.java b/src/main/java/com/colen/postea/Utility/ChunkFixerUtility.java index 8a9f94f..a98e096 100644 --- a/src/main/java/com/colen/postea/Utility/ChunkFixerUtility.java +++ b/src/main/java/com/colen/postea/Utility/ChunkFixerUtility.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; -import com.colen.postea.checker.PosteaProcessedChunksWorldSavedData; import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -17,19 +16,36 @@ import com.colen.postea.API.TileEntityReplacementManager; import akka.japi.Pair; import cpw.mods.fml.common.registry.GameRegistry; +import static com.colen.postea.Utility.PosteaUtilities.getModListHash; + public class ChunkFixerUtility { public static void processChunkNBT(NBTTagCompound compound, World world) { - NBTTagCompound level = compound.getCompoundTag("Level"); - int x = level.getInteger("xPos"); - int z = level.getInteger("zPos"); - - if (PosteaProcessedChunksWorldSavedData.addChunk(x, z)) { + if (processChunk(compound)) { transformTileEntities(compound, world); transformNormalBlocks(compound, world); + compound.setInteger("POSTEA", POSTEA_UPDATE_CODE); + +// NBTTagCompound level = compound.getCompoundTag("Level"); +// int x = level.getInteger("xPos"); +// int z = level.getInteger("zPos"); +// +// PosteaUtilities.markChunkAsDirty(world, x, z); } } + // This will not change between runs. + private static final int POSTEA_UPDATE_CODE = getModListHash(); + + // If a chunk has the same postea code, then do not update it. Return false. + private static boolean processChunk(NBTTagCompound compound) { + // I'm minimising the string length here since this + // will be on every single chunk in every world... Rather not duplicate too much. + if (compound.hasKey("POSTEA")) { + return compound.getInteger("POSTEA") != POSTEA_UPDATE_CODE; + } + return true; + } private static void transformNormalBlocks(NBTTagCompound compound, World world) { NBTTagCompound level = compound.getCompoundTag("Level"); @@ -85,7 +101,7 @@ public class ChunkFixerUtility { } } - public static void transformTileEntities(NBTTagCompound chunkNBT, World world) { + private static void transformTileEntities(NBTTagCompound chunkNBT, World world) { NBTTagCompound level = chunkNBT.getCompoundTag("Level"); Pair, NBTTagList> output = adjustTileEntities(level.getTagList("TileEntities", 10), world); @@ -187,7 +203,7 @@ public class ChunkFixerUtility { return new Pair<>(conversionInfo, tileEntitiesCopy); } - public static class ConversionInfo { + private static class ConversionInfo { public final int x; public final int y; diff --git a/src/main/java/com/colen/postea/Utility/PosteaUtilities.java b/src/main/java/com/colen/postea/Utility/PosteaUtilities.java index 77c86b2..815b3fa 100644 --- a/src/main/java/com/colen/postea/Utility/PosteaUtilities.java +++ b/src/main/java/com/colen/postea/Utility/PosteaUtilities.java @@ -3,6 +3,8 @@ package com.colen.postea.Utility; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; import java.util.ArrayList; import java.util.Collections; @@ -44,12 +46,24 @@ public abstract class PosteaUtilities { Collections.sort(modList); // Step 2: Append all elements into one string - StringBuilder combinedModStringSorted = new StringBuilder(); + StringBuilder combinedModStringSortedBuilder = new StringBuilder(); for (String element : modList) { - combinedModStringSorted.append(element); + combinedModStringSortedBuilder.append(element); } - return Objects.hash(combinedModStringSorted); + String combinedModStringSorted = combinedModStringSortedBuilder.toString(); + + return combinedModStringSorted.hashCode(); } + public static void markChunkAsDirty(World world, int chunkX, int chunkZ) { + if (!world.isRemote) { // Check to make sure we're on the server side. + Chunk chunk = world.getChunkFromChunkCoords(chunkX, chunkZ); + if (chunk == null) return; + + chunk.setChunkModified(); + } + } + + } diff --git a/src/main/java/com/colen/postea/checker/PosteaProcessedChunksWorldSavedData.java b/src/main/java/com/colen/postea/checker/PosteaProcessedChunksWorldSavedData.java deleted file mode 100644 index f6ac7f5..0000000 --- a/src/main/java/com/colen/postea/checker/PosteaProcessedChunksWorldSavedData.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.colen.postea.checker; - -import akka.japi.Pair; -import cpw.mods.fml.common.eventhandler.EventPriority; -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.World; -import net.minecraft.world.WorldSavedData; -import net.minecraft.world.storage.MapStorage; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.world.WorldEvent; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.HashSet; - -public class PosteaProcessedChunksWorldSavedData extends WorldSavedData { - - private static final String DATA_NAME = "GregTech_GlobalIntValue"; - public static HashSet> chunkCoordinates = new HashSet<>(); - public static PosteaProcessedChunksWorldSavedData INSTANCE; - - // True if chunk has not been processed, else false. - public static boolean addChunk(int x, int z) { - boolean updateChunk = chunkCoordinates.add(new Pair<>(x, z)); - - if (updateChunk) { - // Only mark the world NBT as dirty if we actually process a new chunk, since we will need to save that info. - INSTANCE.markDirty(); - } - - return updateChunk; - } - - public PosteaProcessedChunksWorldSavedData() { - super(DATA_NAME); - } - - public PosteaProcessedChunksWorldSavedData(String name) { - super(name); - } - - @Override - public void readFromNBT(NBTTagCompound nbtTagCompound) { - try { - byte[] ba = nbtTagCompound.getByteArray(DATA_NAME); - InputStream byteArrayInputStream = new ByteArrayInputStream(ba); - ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); - Object data = objectInputStream.readObject(); - chunkCoordinates = (HashSet>) data; - } catch (IOException | ClassNotFoundException exception) { - System.out.println(DATA_NAME + " FAILED"); - exception.printStackTrace(); - } - - } - - @Override - public void writeToNBT(NBTTagCompound nbtTagCompound) { - // Write the integer value to NBT - try { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); - objectOutputStream.writeObject(chunkCoordinates); - objectOutputStream.flush(); - byte[] data = byteArrayOutputStream.toByteArray(); - nbtTagCompound.setByteArray(DATA_NAME, data); - } catch (IOException exception) { - System.out.println(DATA_NAME + " SAVE FAILED"); - exception.printStackTrace(); - } - } - - - public static void get(World world) { - - chunkCoordinates.clear(); - - MapStorage storage = world.mapStorage; - INSTANCE = (PosteaProcessedChunksWorldSavedData) storage.loadData(PosteaProcessedChunksWorldSavedData.class, DATA_NAME); - - if (INSTANCE == null) { - INSTANCE = new PosteaProcessedChunksWorldSavedData(); - storage.setData(DATA_NAME, INSTANCE); - } - - } - - // Register event in a static block to ensure it's done as early as possible - static { - MinecraftForge.EVENT_BUS.register(new PosteaProcessedChunksWorldSavedData()); - } - - @SubscribeEvent(priority = EventPriority.HIGHEST) - public void onWorldLoad(WorldEvent.Load event) { - if (!event.world.isRemote && event.world.provider.dimensionId == 0) { - get(event.world); - } - } -} diff --git a/src/main/java/com/colen/postea/mixins/PosteaLoadingPlugin.java b/src/main/java/com/colen/postea/mixins/PosteaLoadingPlugin.java index 766ac42..7500b65 100644 --- a/src/main/java/com/colen/postea/mixins/PosteaLoadingPlugin.java +++ b/src/main/java/com/colen/postea/mixins/PosteaLoadingPlugin.java @@ -44,6 +44,7 @@ public final class PosteaLoadingPlugin implements IEarlyMixinLoader, IFMLLoading public List getMixins(Set loadedCoreMods) { final List mixins = new ArrayList<>(); mixins.add("MixinItemStack"); + mixins.add("MixinChunk"); mixins.add("MixinAnvilChunkLoader"); return mixins; } diff --git a/src/main/java/com/colen/postea/mixins/early/MixinAnvilChunkLoader.java b/src/main/java/com/colen/postea/mixins/early/MixinAnvilChunkLoader.java index 09ea0c4..f104648 100644 --- a/src/main/java/com/colen/postea/mixins/early/MixinAnvilChunkLoader.java +++ b/src/main/java/com/colen/postea/mixins/early/MixinAnvilChunkLoader.java @@ -2,17 +2,19 @@ package com.colen.postea.mixins.early; import static com.colen.postea.Utility.ChunkFixerUtility.processChunkNBT; +import com.colen.postea.mixins.interfaces.IChunkMixin; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.AnvilChunkLoader; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(AnvilChunkLoader.class) -@SuppressWarnings("unused") public abstract class MixinAnvilChunkLoader { @Inject(method = "checkedReadChunkFromNBT__Async", at = @At("HEAD"), remap = false) @@ -21,4 +23,27 @@ public abstract class MixinAnvilChunkLoader { processChunkNBT(compound, world); } + @Inject(method = "readChunkFromNBT", at = @At("RETURN")) + private Chunk onReadChunkFromNBT(World world, NBTTagCompound nbtTagCompound, CallbackInfoReturnable cir) { + Chunk chunk = cir.getReturnValue(); + if (chunk instanceof IChunkMixin iChunkMixin) { + + if (nbtTagCompound.hasKey("POSTEA")) { + iChunkMixin.Postea$setPosteaCode(nbtTagCompound.getLong("POSTEA")); + System.out.println("On loading this chunk from NBT, it had a code of " + nbtTagCompound.getLong("POSTEA") + " at coordinates (" + chunk.xPosition + ", " + chunk.zPosition + ")."); + } + + } + + return chunk; + } + + @Inject(method = "writeChunkToNBT", at = @At("HEAD")) + private void onWriteChunkToNBT(Chunk chunk, World world, NBTTagCompound nbtTagCompound, CallbackInfo ci) { + if (chunk instanceof IChunkMixin iChunkMixin) { + System.out.println("On saving this chunk to NBT, it had a code of " + iChunkMixin.Postea$getPosteaCode() + " at coordinates (" + chunk.xPosition + ", " + chunk.zPosition + ")."); + nbtTagCompound.setLong("POSTEA", iChunkMixin.Postea$getPosteaCode()); + } + } + } diff --git a/src/main/java/com/colen/postea/mixins/early/MixinChunk.java b/src/main/java/com/colen/postea/mixins/early/MixinChunk.java new file mode 100644 index 0000000..54a03c9 --- /dev/null +++ b/src/main/java/com/colen/postea/mixins/early/MixinChunk.java @@ -0,0 +1,25 @@ +package com.colen.postea.mixins.early; + +import com.colen.postea.mixins.interfaces.IChunkMixin; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(Chunk.class) +public class MixinChunk implements IChunkMixin { + + // This new field will store the hash of mod name + versions. We use this to check + // if we need to reprocess this chunk. + @Unique + private long postea_GTNH$posteaID; + + @Unique + public long Postea$getPosteaCode() { + return postea_GTNH$posteaID; + } + + @Unique + public void Postea$setPosteaCode(long POSTEA_ID) { + this.postea_GTNH$posteaID = POSTEA_ID; + } +} diff --git a/src/main/java/com/colen/postea/mixins/interfaces/IChunkMixin.java b/src/main/java/com/colen/postea/mixins/interfaces/IChunkMixin.java new file mode 100644 index 0000000..8add7c5 --- /dev/null +++ b/src/main/java/com/colen/postea/mixins/interfaces/IChunkMixin.java @@ -0,0 +1,6 @@ +package com.colen.postea.mixins.interfaces; + +public interface IChunkMixin { + long Postea$getPosteaCode(); + void Postea$setPosteaCode(long posteaID); +} diff --git a/src/main/resources/mixins.postea.early.json b/src/main/resources/mixins.postea.early.json index 48840ac..4b7d10e 100644 --- a/src/main/resources/mixins.postea.early.json +++ b/src/main/resources/mixins.postea.early.json @@ -7,6 +7,7 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "MixinAnvilChunkLoader", + "MixinChunk", "MixinItemStack" ], "client": [],