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:
parent
c684360f51
commit
9640c5dcf9
3 changed files with 99 additions and 56 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue