A lot of tweaks to the chunkloading for entity behaviour. Entities are now bound by a new

persistent id they *all* have, on the server side.
This commit is contained in:
Christian 2012-09-22 12:27:14 -04:00
parent c684360f51
commit 9640c5dcf9
3 changed files with 99 additions and 56 deletions

View file

@ -9,9 +9,14 @@ import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
@ -27,6 +32,7 @@ import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.ModContainer;
import net.minecraft.src.Chunk;
import net.minecraft.src.ChunkCoordIntPair; import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.CompressedStreamTools; import net.minecraft.src.CompressedStreamTools;
import net.minecraft.src.Entity; import net.minecraft.src.Entity;
@ -68,6 +74,7 @@ public class ForgeChunkManager
private static Map<String, LoadingCallback> callbacks = Maps.newHashMap(); private static Map<String, LoadingCallback> callbacks = Maps.newHashMap();
private static Map<World, SetMultimap<ChunkCoordIntPair,Ticket>> forcedChunks = Maps.newHashMap(); private static Map<World, SetMultimap<ChunkCoordIntPair,Ticket>> forcedChunks = Maps.newHashMap();
private static BiMap<UUID,Ticket> pendingEntities = HashBiMap.create();
/** /**
* All mods requiring chunkloading need to implement this to handle the * All mods requiring chunkloading need to implement this to handle the
@ -108,9 +115,8 @@ public class ForgeChunkManager
private World world; private World world;
private int maxDepth; private int maxDepth;
private String entityClazz; private String entityClazz;
private int entityX; private int entityChunkX;
private int entityY; private int entityChunkZ;
private int entityZ;
private Entity entity; private Entity entity;
Ticket(String modId, Type type, World world) Ticket(String modId, Type type, World world)
@ -122,14 +128,6 @@ public class ForgeChunkManager
this.requestedChunks = Sets.newLinkedHashSet(); this.requestedChunks = Sets.newLinkedHashSet();
} }
void bindEntityData(int x, int y, int z, String clazz)
{
this.entityX = x;
this.entityY = y;
this.entityZ = z;
this.entityClazz = clazz;
}
/** /**
* The chunk list depth can be manipulated up to the maximal grant allowed for the mod. This value is configurable. Once the maximum is reached, * The chunk list depth can be manipulated up to the maximal grant allowed for the mod. This value is configurable. Once the maximum is reached,
* the least recently forced chunk, by original registration time, is removed from the forced chunk list. * the least recently forced chunk, by original registration time, is removed from the forced chunk list.
@ -189,37 +187,12 @@ public class ForgeChunkManager
} }
/** /**
* Get the entity class associated with this ticket. Only valid for callbacks. * Get the entity associated with this {@link Type#ENTITY} type ticket
* @return * @return
*/ */
public String getEntityClass() public Entity getEntity()
{ {
return this.entityClazz; return entity;
}
/**
* Get the last known entity X coordinate for this ticket. Only valid for callbacks.
* @return
*/
public int getEntityX()
{
return entityX;
}
/**
* Get the last known entity Y coordinate for this ticket. Only valid for callbacks.
* @return
*/
public int getEntityY()
{
return entityY;
}
/**
* Get the last known entity Z coordinate for this ticket. Only valid for callbacks.
* @return
*/
public int getEntityZ()
{
return entityZ;
} }
} }
@ -287,16 +260,35 @@ public class ForgeChunkManager
tick.modData = modData; tick.modData = modData;
if (type == Type.ENTITY) if (type == Type.ENTITY)
{ {
int entX = ticket.getInteger("entityX"); tick.entityChunkX = ticket.getInteger("chunkX");
int entY = ticket.getInteger("entityY"); tick.entityChunkZ = ticket.getInteger("chunkZ");
int entZ = ticket.getInteger("entityZ"); UUID uuid = new UUID(ticket.getLong("PersistentIDMSB"), ticket.getLong("PersistentIDLSB"));
String entClass = ticket.getString("entityClass"); // add the ticket to the "pending entity" list
tick.bindEntityData(entX, entY, entZ, entClass); pendingEntities.put(uuid, tick);
} }
loadedTickets.put(modId, tick); loadedTickets.put(modId, tick);
} }
} }
for (Ticket tick : ImmutableSet.copyOf(pendingEntities.values()))
{
if (tick.ticketType == Type.ENTITY && tick.entity == null)
{
// force the world to load the entity's chunk
// the load will come back through the loadEntity method and attach the entity
// to the ticket
world.getChunkFromChunkCoords(tick.entityChunkX, tick.entityChunkZ);
}
}
for (Ticket tick : ImmutableSet.copyOf(pendingEntities.values()))
{
if (tick.ticketType == Type.ENTITY && tick.entity == null)
{
FMLLog.warning("Failed to load persistent chunkloading entity %s from store.", pendingEntities.inverse().get(tick));
loadedTickets.remove(tick.modId, tick);
}
}
pendingEntities.clear();
// send callbacks // send callbacks
for (String modId : loadedTickets.keySet()) for (String modId : loadedTickets.keySet())
{ {
@ -537,10 +529,10 @@ public class ForgeChunkManager
ticket.setCompoundTag("ModData", tick.modData); ticket.setCompoundTag("ModData", tick.modData);
if (tick.ticketType == Type.ENTITY) if (tick.ticketType == Type.ENTITY)
{ {
ticket.setInteger("entityX", MathHelper.floor_double(tick.entity.posX)); ticket.setInteger("chunkX", MathHelper.floor_double(tick.entity.chunkCoordX));
ticket.setInteger("entityY", MathHelper.floor_double(tick.entity.posY)); ticket.setInteger("chunkZ", MathHelper.floor_double(tick.entity.chunkCoordZ));
ticket.setInteger("entityZ", MathHelper.floor_double(tick.entity.posZ)); ticket.setLong("persistentIDMSB", tick.entity.getPersistentID().getMostSignificantBits());
ticket.setString("entityClass", tick.entity.getClass().getName()); ticket.setLong("persistentIDLSB", tick.entity.getPersistentID().getLeastSignificantBits());
} }
} }
} }
@ -554,4 +546,15 @@ public class ForgeChunkManager
return; return;
} }
} }
static void loadEntity(Entity entity)
{
UUID id = entity.getPersistentID();
Ticket tick = pendingEntities.get(id);
if (tick != null)
{
tick.bindEntity(entity);
pendingEntities.remove(id);
}
}
} }

View file

@ -1,5 +1,7 @@
package net.minecraftforge.common; package net.minecraftforge.common;
import java.util.UUID;
import net.minecraft.src.*; import net.minecraft.src.*;
import net.minecraftforge.event.*; import net.minecraftforge.event.*;
import net.minecraftforge.event.entity.*; import net.minecraftforge.event.entity.*;
@ -10,6 +12,17 @@ public class ForgeInternalHandler
@ForgeSubscribe(priority = EventPriority.HIGHEST) @ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onEntityJoinWorld(EntityJoinWorldEvent event) public void onEntityJoinWorld(EntityJoinWorldEvent event)
{ {
if (!event.world.isRemote)
{
if (event.entity.getPersistentID() == null)
{
event.entity.generatePersistentID();
}
else
{
ForgeChunkManager.loadEntity(event.entity);
}
}
Entity entity = event.entity; Entity entity = event.entity;
if (entity instanceof EntityItem) if (entity instanceof EntityItem)
{ {

View file

@ -1,6 +1,6 @@
--- ../src_base/common/net/minecraft/src/Entity.java --- ../src_base/common/net/minecraft/src/Entity.java
+++ ../src_work/common/net/minecraft/src/Entity.java +++ ../src_work/common/net/minecraft/src/Entity.java
@@ -2,6 +2,8 @@ @@ -2,9 +2,12 @@
import cpw.mods.fml.common.Side; import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly; import cpw.mods.fml.common.asm.SideOnly;
@ -9,7 +9,11 @@
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@@ -186,6 +188,10 @@ +import java.util.UUID;
public abstract class Entity
{
@@ -186,6 +189,11 @@
public boolean ignoreFrustumCheck; public boolean ignoreFrustumCheck;
public boolean isAirBorne; public boolean isAirBorne;
public EnumEntitySize myEntitySize; public EnumEntitySize myEntitySize;
@ -17,13 +21,19 @@
+ private NBTTagCompound customEntityData; + private NBTTagCompound customEntityData;
+ public boolean captureDrops = false; + public boolean captureDrops = false;
+ public ArrayList<EntityItem> capturedDrops = new ArrayList<EntityItem>(); + public ArrayList<EntityItem> capturedDrops = new ArrayList<EntityItem>();
+ private UUID persistentID;
public Entity(World par1World) public Entity(World par1World)
{ {
@@ -1382,6 +1388,10 @@ @@ -1382,6 +1390,15 @@
par1NBTTagCompound.setShort("Fire", (short)this.fire); par1NBTTagCompound.setShort("Fire", (short)this.fire);
par1NBTTagCompound.setShort("Air", (short)this.getAir()); par1NBTTagCompound.setShort("Air", (short)this.getAir());
par1NBTTagCompound.setBoolean("OnGround", this.onGround); par1NBTTagCompound.setBoolean("OnGround", this.onGround);
+ if (persistentID != null)
+ {
+ par1NBTTagCompound.setLong("PersistentIDMSB", persistentID.getMostSignificantBits());
+ par1NBTTagCompound.setLong("PersistentIDLSB", persistentID.getLeastSignificantBits());
+ }
+ if (customEntityData != null) + if (customEntityData != null)
+ { + {
+ par1NBTTagCompound.setCompoundTag("ForgeData", customEntityData); + par1NBTTagCompound.setCompoundTag("ForgeData", customEntityData);
@ -31,18 +41,22 @@
this.writeEntityToNBT(par1NBTTagCompound); this.writeEntityToNBT(par1NBTTagCompound);
} }
@@ -1423,6 +1433,10 @@ @@ -1423,6 +1440,14 @@
this.onGround = par1NBTTagCompound.getBoolean("OnGround"); this.onGround = par1NBTTagCompound.getBoolean("OnGround");
this.setPosition(this.posX, this.posY, this.posZ); this.setPosition(this.posX, this.posY, this.posZ);
this.setRotation(this.rotationYaw, this.rotationPitch); this.setRotation(this.rotationYaw, this.rotationPitch);
+ if (par1NBTTagCompound.hasKey("ForgeData")) + if (par1NBTTagCompound.hasKey("ForgeData"))
+ { + {
+ customEntityData = par1NBTTagCompound.getCompoundTag("ForgeData"); + customEntityData = par1NBTTagCompound.getCompoundTag("ForgeData");
+ }
+ if (par1NBTTagCompound.hasKey("PersistentIDMSB") && par1NBTTagCompound.hasKey("PersistentIDLSB"))
+ {
+ persistentID = new UUID(par1NBTTagCompound.getLong("PersistentIDMSB"), par1NBTTagCompound.getLong("PersistentIDLSB"));
+ } + }
this.readEntityFromNBT(par1NBTTagCompound); this.readEntityFromNBT(par1NBTTagCompound);
} }
@@ -1509,7 +1523,14 @@ @@ -1509,7 +1534,14 @@
{ {
EntityItem var3 = new EntityItem(this.worldObj, this.posX, this.posY + (double)par2, this.posZ, par1ItemStack); EntityItem var3 = new EntityItem(this.worldObj, this.posX, this.posY + (double)par2, this.posZ, par1ItemStack);
var3.delayBeforeCanPickup = 10; var3.delayBeforeCanPickup = 10;
@ -58,7 +72,7 @@
return var3; return var3;
} }
@@ -1843,7 +1864,7 @@ @@ -1843,7 +1875,7 @@
*/ */
public boolean isRiding() public boolean isRiding()
{ {
@ -67,7 +81,7 @@
} }
/** /**
@@ -2107,4 +2128,59 @@ @@ -2107,4 +2139,72 @@
{ {
return String.format("%s[\'%s\'/%d, l=\'%s\', x=%.2f, y=%.2f, z=%.2f]", new Object[] {this.getClass().getSimpleName(), this.getEntityName(), Integer.valueOf(this.entityId), this.worldObj == null ? "~NULL~" : this.worldObj.getWorldInfo().getWorldName(), Double.valueOf(this.posX), Double.valueOf(this.posY), Double.valueOf(this.posZ)}); return String.format("%s[\'%s\'/%d, l=\'%s\', x=%.2f, y=%.2f, z=%.2f]", new Object[] {this.getClass().getSimpleName(), this.getEntityName(), Integer.valueOf(this.entityId), this.worldObj == null ? "~NULL~" : this.worldObj.getWorldInfo().getWorldName(), Double.valueOf(this.posX), Double.valueOf(this.posY), Double.valueOf(this.posZ)});
} }
@ -98,7 +112,7 @@
+ +
+ /** + /**
+ * Called when a user uses the creative pick block button on this entity. + * Called when a user uses the creative pick block button on this entity.
+ * + *
+ * @param target The full target the player is looking at + * @param target The full target the player is looking at
+ * @return A ItemStack to add to the player's inventory, Null if nothing should be added. + * @return A ItemStack to add to the player's inventory, Null if nothing should be added.
+ */ + */
@ -125,5 +139,18 @@
+ } + }
+ } + }
+ return null; + return null;
+ }
+
+ public UUID getPersistentID()
+ {
+ return persistentID;
+ }
+
+ public synchronized void generatePersistentID()
+ {
+ if (persistentID == null)
+ {
+ persistentID = UUID.randomUUID();
+ }
+ } + }
} }