Store entity data for dormant chunks using NBT (#4162)

This commit is contained in:
Ben Staddon 2017-10-02 23:17:37 +01:00 committed by LexManos
parent 3511e9ef2e
commit f3273ca0c9
4 changed files with 79 additions and 32 deletions

View File

@ -155,7 +155,7 @@
}
public boolean func_174816_a(Explosion p_174816_1_, World p_174816_2_, BlockPos p_174816_3_, IBlockState p_174816_4_, float p_174816_5_)
@@ -2901,6 +2928,184 @@
@@ -2901,6 +2928,185 @@
EnchantmentHelper.func_151385_b(p_174815_1_, p_174815_2_);
}
@ -248,6 +248,7 @@
+ /**
+ * Reset the entity ID to a new value. Not to be used from Mod code
+ */
+ @Deprecated // TODO: remove (1.13?)
+ public final void resetEntityId()
+ {
+ this.field_145783_c = field_70152_a++;

View File

@ -90,11 +90,12 @@
nbttagcompound.func_74768_a("DataVersion", 1343);
+ net.minecraftforge.fml.common.FMLCommonHandler.instance().getDataFixer().writeVersionData(nbttagcompound);
this.func_75820_a(p_75816_2_, p_75816_1_, nbttagcompound1);
+ net.minecraftforge.common.ForgeChunkManager.storeChunkNBT(p_75816_2_, nbttagcompound1);
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkDataEvent.Save(p_75816_2_, nbttagcompound));
this.func_75824_a(p_75816_2_.func_76632_l(), nbttagcompound);
}
catch (Exception exception)
@@ -305,11 +353,19 @@
@@ -305,11 +354,19 @@
{
NBTTagCompound nbttagcompound2 = new NBTTagCompound();
@ -114,7 +115,7 @@
}
}
@@ -318,8 +374,16 @@
@@ -318,8 +375,16 @@
for (TileEntity tileentity : p_75820_1_.func_177434_r().values())
{
@ -131,7 +132,7 @@
}
p_75820_3_.func_74782_a("TileEntities", nbttaglist2);
@@ -388,6 +452,12 @@
@@ -388,6 +453,12 @@
chunk.func_76616_a(p_75823_2_.func_74770_j("Biomes"));
}
@ -144,7 +145,7 @@
NBTTagList nbttaglist1 = p_75823_2_.func_150295_c("Entities", 10);
for (int j1 = 0; j1 < nbttaglist1.func_74745_c(); ++j1)
@@ -431,8 +501,6 @@
@@ -431,8 +502,6 @@
p_75823_1_.func_180497_b(new BlockPos(nbttagcompound3.func_74762_e("x"), nbttagcompound3.func_74762_e("y"), nbttagcompound3.func_74762_e("z")), block, nbttagcompound3.func_74762_e("t"), nbttagcompound3.func_74762_e("p"));
}
}

View File

@ -72,11 +72,15 @@
Iterator<Long> iterator = this.field_73248_b.iterator();
for (int i = 0; i < 100 && iterator.hasNext(); iterator.remove())
@@ -238,6 +271,11 @@
@@ -234,10 +267,15 @@
if (chunk != null && chunk.field_189550_d)
{
chunk.func_76623_d();
+ net.minecraftforge.common.ForgeChunkManager.putDormantChunk(ChunkPos.func_77272_a(chunk.field_76635_g, chunk.field_76647_h), chunk);
this.func_73242_b(chunk);
this.func_73243_a(chunk);
this.field_73244_f.remove(olong);
++i;
+ net.minecraftforge.common.ForgeChunkManager.putDormantChunk(ChunkPos.func_77272_a(chunk.field_76635_g, chunk.field_76647_h), chunk);
+ if (field_73244_f.size() == 0 && net.minecraftforge.common.ForgeChunkManager.getPersistentChunksFor(this.field_73251_h).size() == 0 && !this.field_73251_h.field_73011_w.func_186058_p().shouldLoadSpawn()){
+ net.minecraftforge.common.DimensionManager.unloadWorld(this.field_73251_h.field_73011_w.getDimension());
+ break;

View File

@ -36,12 +36,14 @@ import net.minecraft.entity.Entity;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
@ -52,9 +54,6 @@ import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.eventhandler.Event;
import org.apache.logging.log4j.Level;
import java.util.function.Function;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ArrayListMultimap;
@ -65,7 +64,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterators;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MapMaker;
@ -108,7 +106,7 @@ public class ForgeChunkManager
private static Map<World, ImmutableSetMultimap<ChunkPos,Ticket>> forcedChunks = new MapMaker().weakKeys().makeMap();
private static BiMap<UUID,Ticket> pendingEntities = HashBiMap.create();
private static Map<World,Cache<Long, Chunk>> dormantChunkCache = new MapMaker().weakKeys().makeMap();
private static Map<World,Cache<Long, ChunkEntry>> dormantChunkCache = new MapMaker().weakKeys().makeMap();
private static File cfgFile;
private static Configuration config;
@ -125,6 +123,18 @@ public class ForgeChunkManager
MOD_PROP_ORDER.add("maximumChunksPerTicket");
}
private static class ChunkEntry
{
public final Chunk chunk;
public final NBTTagCompound nbt;
public ChunkEntry(Chunk chunk)
{
this.chunk = chunk;
this.nbt = new NBTTagCompound();
}
}
public static Iterator<Chunk> getPersistentChunksIterableFor(final World world, Iterator<Chunk> chunkIterator)
{
final ImmutableSetMultimap<ChunkPos, Ticket> persistentChunksFor = getPersistentChunksFor(world);
@ -452,7 +462,7 @@ public class ForgeChunkManager
ArrayListMultimap<String, Ticket> newTickets = ArrayListMultimap.create();
tickets.put(world, newTickets);
forcedChunks.put(world, ImmutableSetMultimap.<ChunkPos,Ticket>of());
forcedChunks.put(world, ImmutableSetMultimap.of());
if (!(world instanceof WorldServer))
{
@ -461,7 +471,7 @@ public class ForgeChunkManager
if (dormantChunkCacheSize != 0)
{ // only put into cache if we're using dormant chunk caching
dormantChunkCache.put(world, CacheBuilder.newBuilder().maximumSize(dormantChunkCacheSize).<Long, Chunk>build());
dormantChunkCache.put(world, CacheBuilder.newBuilder().maximumSize(dormantChunkCacheSize).build());
}
WorldServer worldServer = (WorldServer) world;
File chunkDir = worldServer.getChunkSaveLocation();
@ -517,7 +527,7 @@ public class ForgeChunkManager
tick.player = ticket.getString("Player");
if (!playerLoadedTickets.containsKey(tick.modId))
{
playerLoadedTickets.put(modId, ArrayListMultimap.<String,Ticket>create());
playerLoadedTickets.put(modId, ArrayListMultimap.create());
}
playerLoadedTickets.get(tick.modId).put(tick.player, tick);
}
@ -875,7 +885,7 @@ public class ForgeChunkManager
*/
public static ImmutableSetMultimap<ChunkPos, Ticket> getPersistentChunksFor(World world)
{
return forcedChunks.containsKey(world) ? forcedChunks.get(world) : ImmutableSetMultimap.<ChunkPos,Ticket>of();
return forcedChunks.containsKey(world) ? forcedChunks.get(world) : ImmutableSetMultimap.of();
}
static void saveWorld(World world)
@ -957,10 +967,32 @@ public class ForgeChunkManager
public static void putDormantChunk(long coords, Chunk chunk)
{
if (dormantChunkCacheSize == 0) return; // Skip if we're not dormant caching chunks
Cache<Long, Chunk> cache = dormantChunkCache.get(chunk.getWorld());
Cache<Long, ChunkEntry> cache = dormantChunkCache.get(chunk.getWorld());
if (cache != null)
{
cache.put(coords, chunk);
cache.put(coords, new ChunkEntry(chunk));
}
}
public static void storeChunkNBT(Chunk chunk, NBTTagCompound nbt)
{
if (dormantChunkCacheSize == 0) return;
Cache<Long, ChunkEntry> cache = dormantChunkCache.get(chunk.getWorld());
if (cache == null) return;
ChunkEntry entry = cache.getIfPresent(ChunkPos.asLong(chunk.x, chunk.z));
if (entry != null)
{
entry.nbt.setTag("Entities", nbt.getTagList("Entities", Constants.NBT.TAG_COMPOUND));
entry.nbt.setTag("TileEntities", nbt.getTagList("TileEntities", Constants.NBT.TAG_COMPOUND));
ClassInheritanceMultiMap<Entity>[] entityLists = chunk.getEntityLists();
for (int i = 0; i < entityLists.length; ++i)
{
entityLists[i] = new ClassInheritanceMultiMap<>(Entity.class);
}
chunk.getTileEntityMap().clear();
}
}
@ -968,24 +1000,33 @@ public class ForgeChunkManager
public static Chunk fetchDormantChunk(long coords, World world)
{
if (dormantChunkCacheSize == 0) return null; // Don't bother with maps at all if its never gonna get a response
Cache<Long, Chunk> cache = dormantChunkCache.get(world);
if (cache == null)
Cache<Long, ChunkEntry> cache = dormantChunkCache.get(world);
if (cache == null) return null;
ChunkEntry entry = cache.getIfPresent(coords);
if (entry == null) return null;
loadChunkEntities(entry.chunk, entry.nbt, world);
return entry.chunk;
}
private static void loadChunkEntities(Chunk chunk, NBTTagCompound nbt, World world)
{
NBTTagList entities = nbt.getTagList("Entities", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < entities.tagCount(); ++i)
{
return null;
AnvilChunkLoader.readChunkEntity(entities.getCompoundTagAt(i), world, chunk);
chunk.setHasEntities(true);
}
Chunk chunk = cache.getIfPresent(coords);
if (chunk != null)
NBTTagList tileEntities = nbt.getTagList("TileEntities", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < tileEntities.tagCount(); ++i)
{
for (ClassInheritanceMultiMap<Entity> eList : chunk.getEntityLists())
{
Iterator<Entity> itr = eList.iterator();
while (itr.hasNext())
{
(itr.next()).resetEntityId();
}
}
TileEntity tileEntity = TileEntity.create(world, tileEntities.getCompoundTagAt(i));
if (tileEntity != null) chunk.addTileEntity(tileEntity);
}
return chunk;
}
static void captureConfig(File configDir)