From 8fe333ed86042fae09a9417c33a503f61d499712 Mon Sep 17 00:00:00 2001 From: Johann Bernhardt Date: Sat, 20 Nov 2021 14:05:10 +0100 Subject: [PATCH] Fix gitignore --- .gitignore | 1 - .../codechicken/lib/world/ChunkExtension.java | 85 ++++++++ .../codechicken/lib/world/IChunkLoadTile.java | 12 ++ .../lib/world/TileChunkLoadHook.java | 28 +++ .../codechicken/lib/world/WorldExtension.java | 99 +++++++++ .../lib/world/WorldExtensionInstantiator.java | 17 ++ .../lib/world/WorldExtensionManager.java | 201 ++++++++++++++++++ 7 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 src/main/java/codechicken/lib/world/ChunkExtension.java create mode 100644 src/main/java/codechicken/lib/world/IChunkLoadTile.java create mode 100644 src/main/java/codechicken/lib/world/TileChunkLoadHook.java create mode 100644 src/main/java/codechicken/lib/world/WorldExtension.java create mode 100644 src/main/java/codechicken/lib/world/WorldExtensionInstantiator.java create mode 100644 src/main/java/codechicken/lib/world/WorldExtensionManager.java diff --git a/.gitignore b/.gitignore index 4a0ea1e..558ad12 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ server.properties servers.dat usercache.json whitelist.json -world/ /out/ *.iml *.ipr diff --git a/src/main/java/codechicken/lib/world/ChunkExtension.java b/src/main/java/codechicken/lib/world/ChunkExtension.java new file mode 100644 index 0000000..c3f17b7 --- /dev/null +++ b/src/main/java/codechicken/lib/world/ChunkExtension.java @@ -0,0 +1,85 @@ +package codechicken.lib.world; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.chunk.Chunk; + +import java.util.HashSet; + +public abstract class ChunkExtension +{ + public final Chunk chunk; + public final ChunkCoordIntPair coord; + public final WorldExtension world; + public HashSet watchedPlayers; + + public ChunkExtension(Chunk chunk, WorldExtension world) + { + this.chunk = chunk; + coord = chunk.getChunkCoordIntPair(); + this.world = world; + watchedPlayers = new HashSet(); + } + + public void loadData(NBTTagCompound tag) + { + } + + public void saveData(NBTTagCompound tag) + { + } + + public void load() + { + } + + public void unload() + { + } + + public final void sendPacketToPlayers(Packet packet) + { + for(EntityPlayerMP player : watchedPlayers) + player.playerNetServerHandler.sendPacket(packet); + } + + public final void watchPlayer(EntityPlayerMP player) + { + watchedPlayers.add(player); + onWatchPlayer(player); + } + + public void onWatchPlayer(EntityPlayerMP player) + { + } + + public final void unwatchPlayer(EntityPlayerMP player) + { + watchedPlayers.remove(player); + onUnWatchPlayer(player); + } + + public void onUnWatchPlayer(EntityPlayerMP player) + { + } + + public void sendUpdatePackets() + { + } + + @Override + public int hashCode() + { + return coord.chunkXPos ^ coord.chunkZPos; + } + + @Override + public boolean equals(Object o) + { + return (o instanceof ChunkExtension && ((ChunkExtension)o).coord.equals(coord)) || + (o instanceof ChunkCoordIntPair && coord.equals(o)) || + (o instanceof Long && (Long)o == (((long)coord.chunkXPos)<<32 | coord.chunkZPos)); + } +} diff --git a/src/main/java/codechicken/lib/world/IChunkLoadTile.java b/src/main/java/codechicken/lib/world/IChunkLoadTile.java new file mode 100644 index 0000000..5739102 --- /dev/null +++ b/src/main/java/codechicken/lib/world/IChunkLoadTile.java @@ -0,0 +1,12 @@ +package codechicken.lib.world; + +/** + * Provides a callback for tile entities when a chunk is loaded, as an alternative to validate when the chunk hasn't been added to the world. + * To hook all world join/seperate events. Use this, TileEntity.validate with a worldObj.blockExists check, TileEntity.onChunkUnload and TileEntity.invalidate + * Be sure to call TileChunkLoadHook.init() from your mod during initialisation + * You could easily implement this in your own mod, but providing it here reduces the number of times the chunkTileEntityMap needs to be iterated + */ +public interface IChunkLoadTile +{ + public void onChunkLoad(); +} diff --git a/src/main/java/codechicken/lib/world/TileChunkLoadHook.java b/src/main/java/codechicken/lib/world/TileChunkLoadHook.java new file mode 100644 index 0000000..e080c2e --- /dev/null +++ b/src/main/java/codechicken/lib/world/TileChunkLoadHook.java @@ -0,0 +1,28 @@ +package codechicken.lib.world; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.ChunkEvent; + +import java.util.ArrayList; +import java.util.List; + +public class TileChunkLoadHook +{ + private static boolean init; + public static void init() { + if(init) return; + init = true; + + MinecraftForge.EVENT_BUS.register(new TileChunkLoadHook()); + } + + @SubscribeEvent + public void onChunkLoad(ChunkEvent.Load event) { + List list = new ArrayList(event.getChunk().chunkTileEntityMap.values()); + for(TileEntity t : list) + if(t instanceof IChunkLoadTile) + ((IChunkLoadTile)t).onChunkLoad(); + } +} diff --git a/src/main/java/codechicken/lib/world/WorldExtension.java b/src/main/java/codechicken/lib/world/WorldExtension.java new file mode 100644 index 0000000..3015f93 --- /dev/null +++ b/src/main/java/codechicken/lib/world/WorldExtension.java @@ -0,0 +1,99 @@ +package codechicken.lib.world; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +import java.util.HashMap; + +public abstract class WorldExtension +{ + public final World world; + public HashMap chunkMap = new HashMap(); + + public WorldExtension(World world) + { + this.world = world; + } + + public void load() + { + } + + public void unload() + { + } + + public void save() + { + } + + public void preTick() + { + } + + public void postTick() + { + } + + protected final void addChunk(ChunkExtension extension) + { + chunkMap.put(extension.chunk, extension); + } + + protected final void loadChunk(Chunk chunk) + { + chunkMap.get(chunk).load(); + } + + protected final void unloadChunk(Chunk chunk) + { + chunkMap.get(chunk).unload(); + } + + protected final void loadChunkData(Chunk chunk, NBTTagCompound tag) + { + chunkMap.get(chunk).loadData(tag); + } + + protected final void saveChunkData(Chunk chunk, NBTTagCompound tag) + { + chunkMap.get(chunk).saveData(tag); + } + + protected final void remChunk(Chunk chunk) + { + chunkMap.remove(chunk); + } + + protected final void watchChunk(Chunk chunk, EntityPlayerMP player) + { + chunkMap.get(chunk).watchPlayer(player); + } + + protected final void unwatchChunk(Chunk chunk, EntityPlayerMP player) + { + ChunkExtension extension = chunkMap.get(chunk); + if(extension != null) + extension.unwatchPlayer(player); + } + + protected final void sendChunkUpdates(Chunk chunk) + { + chunkMap.get(chunk).sendUpdatePackets(); + } + + public boolean containsChunk(Chunk chunk) + { + return chunkMap.containsKey(chunk); + } + + public ChunkExtension getChunkExtension(int chunkXPos, int chunkZPos) + { + if(!world.blockExists(chunkXPos<<4, 128, chunkZPos<<4)) + return null; + + return chunkMap.get(world.getChunkFromChunkCoords(chunkXPos, chunkZPos)); + } +} diff --git a/src/main/java/codechicken/lib/world/WorldExtensionInstantiator.java b/src/main/java/codechicken/lib/world/WorldExtensionInstantiator.java new file mode 100644 index 0000000..23431b0 --- /dev/null +++ b/src/main/java/codechicken/lib/world/WorldExtensionInstantiator.java @@ -0,0 +1,17 @@ +package codechicken.lib.world; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +public abstract class WorldExtensionInstantiator +{ + public int instantiatorID; + + public abstract WorldExtension createWorldExtension(World world); + public abstract ChunkExtension createChunkExtension(Chunk chunk, WorldExtension world); + + public WorldExtension getExtension(World world) + { + return WorldExtensionManager.getWorldExtension(world, instantiatorID); + } +} diff --git a/src/main/java/codechicken/lib/world/WorldExtensionManager.java b/src/main/java/codechicken/lib/world/WorldExtensionManager.java new file mode 100644 index 0000000..b8ec2b4 --- /dev/null +++ b/src/main/java/codechicken/lib/world/WorldExtensionManager.java @@ -0,0 +1,201 @@ +package codechicken.lib.world; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.EmptyChunk; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.ChunkDataEvent; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.ChunkWatchEvent.UnWatch; +import net.minecraftforge.event.world.ChunkWatchEvent.Watch; +import net.minecraftforge.event.world.WorldEvent; + +import java.util.ArrayList; +import java.util.HashMap; + +public class WorldExtensionManager +{ + public static class WorldExtensionEventHandler + { + @SubscribeEvent + public void onChunkDataLoad(ChunkDataEvent.Load event) + { + if(!worldMap.containsKey(event.world)) + WorldExtensionManager.onWorldLoad(event.world); + + createChunkExtension(event.world, event.getChunk()); + + for(WorldExtension extension : worldMap.get(event.world)) + extension.loadChunkData(event.getChunk(), event.getData()); + } + + @SubscribeEvent + public void onChunkDataSave(ChunkDataEvent.Save event) + { + for(WorldExtension extension : worldMap.get(event.world)) + extension.saveChunkData(event.getChunk(), event.getData()); + + if(!event.getChunk().isChunkLoaded) + removeChunk(event.world, event.getChunk()); + } + + @SubscribeEvent + public void onChunkLoad(ChunkEvent.Load event) + { + if(!worldMap.containsKey(event.world)) + WorldExtensionManager.onWorldLoad(event.world); + + createChunkExtension(event.world, event.getChunk()); + + for(WorldExtension extension : worldMap.get(event.world)) + extension.loadChunk(event.getChunk()); + } + + @SubscribeEvent + public void onChunkUnLoad(ChunkEvent.Unload event) + { + if(event.getChunk() instanceof EmptyChunk) + return; + + for(WorldExtension extension : worldMap.get(event.world)) + extension.unloadChunk(event.getChunk()); + + if(event.world.isRemote) + removeChunk(event.world, event.getChunk()); + } + + @SubscribeEvent + public void onWorldSave(WorldEvent.Save event) + { + if(worldMap.containsKey(event.world)) + for(WorldExtension extension : worldMap.get(event.world)) + extension.save(); + } + + @SubscribeEvent + public void onWorldLoad(WorldEvent.Load event) + { + if(!worldMap.containsKey(event.world)) + WorldExtensionManager.onWorldLoad(event.world); + } + + @SubscribeEvent + public void onWorldUnLoad(WorldEvent.Unload event) + { + if(worldMap.containsKey(event.world))//because force closing unloads a world twice + for(WorldExtension extension : worldMap.remove(event.world)) + extension.unload(); + } + + @SubscribeEvent + public void onChunkWatch(Watch event) + { + Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos); + for(WorldExtension extension : worldMap.get(event.player.worldObj)) + extension.watchChunk(chunk, event.player); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void onChunkUnWatch(UnWatch event) + { + Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos); + for(WorldExtension extension : worldMap.get(event.player.worldObj)) + extension.unwatchChunk(chunk, event.player); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void clientTick(TickEvent.ClientTickEvent event) + { + World world = Minecraft.getMinecraft().theWorld; + if (worldMap.containsKey(world)) + if (event.phase == TickEvent.Phase.START) + preTick(world); + else + postTick(world); + } + + @SubscribeEvent + public void serverTick(TickEvent.WorldTickEvent event) + { + if(!worldMap.containsKey(event.world)) + WorldExtensionManager.onWorldLoad(event.world); + + if(event.phase == TickEvent.Phase.START) + preTick(event.world); + else + postTick(event.world); + } + } + + private static boolean initialised; + private static ArrayList extensionIntialisers = new ArrayList(); + + public static void registerWorldExtension(WorldExtensionInstantiator init) + { + if(!initialised) + init(); + + init.instantiatorID = extensionIntialisers.size(); + extensionIntialisers.add(init); + } + + private static void init() + { + initialised = true; + MinecraftForge.EVENT_BUS.register(new WorldExtensionEventHandler()); + FMLCommonHandler.instance().bus().register(new WorldExtensionEventHandler()); + } + + private static HashMap worldMap = new HashMap(); + + private static void onWorldLoad(World world) + { + WorldExtension[] extensions = new WorldExtension[extensionIntialisers.size()]; + for(int i = 0; i < extensions.length; i++) + extensions[i] = extensionIntialisers.get(i).createWorldExtension(world); + + worldMap.put(world, extensions); + + for(WorldExtension extension : extensions) + extension.load(); + } + + private static void createChunkExtension(World world, Chunk chunk) + { + WorldExtension[] extensions = worldMap.get(world); + for(int i = 0; i < extensionIntialisers.size(); i++) + if(!extensions[i].containsChunk(chunk)) + extensions[i].addChunk(extensionIntialisers.get(i).createChunkExtension(chunk, extensions[i])); + } + + private static void removeChunk(World world, Chunk chunk) + { + for(WorldExtension extension : worldMap.get(world)) + extension.remChunk(chunk); + } + + private static void preTick(World world) + { + for(WorldExtension extension : worldMap.get(world)) + extension.preTick(); + } + + private static void postTick(World world) + { + for(WorldExtension extension : worldMap.get(world)) + extension.postTick(); + } + + public static WorldExtension getWorldExtension(World world, int instantiatorID) + { + return worldMap.get(world)[instantiatorID]; + } +}