package micdoodle8.mods.galacticraft.core.entities;
import io.netty.buffer.ByteBuf;
import micdoodle8.mods.galacticraft.core.GalacticraftCore;
import micdoodle8.mods.galacticraft.core.network.IPacketReceiver;
import micdoodle8.mods.galacticraft.core.network.NetworkUtil;
import micdoodle8.mods.galacticraft.core.network.PacketDynamic;
import micdoodle8.mods.galacticraft.core.util.GCCoreUtil;
import micdoodle8.mods.miccore.Annotations.NetworkedField;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint;
import net.minecraftforge.fml.relauncher.Side;
import java.lang.reflect.Field;
import java.util.*;
public abstract class EntityAdvanced extends Entity implements IPacketReceiver
{
protected long ticks = 0;
private LinkedHashSet<Field> fieldCacheClient;
private LinkedHashSet<Field> fieldCacheServer;
private Map<Field, Object> lastSentData = new HashMap<Field, Object>();
private boolean networkDataChanged = false;
public EntityAdvanced(World world)
{
super(world);
if (world != null && world.isRemote)
{
//Empty packet client->server just to kickstart the server into sending this client an initial packet
this.fieldCacheServer = new LinkedHashSet<Field>();
GalacticraftCore.packetPipeline.sendToServer(new PacketDynamic(this));
}
}
/**
* Whether or not this entity should be sending packets to/from server
*
* @return If the entity needs network capabilities
*/
public abstract boolean isNetworkedEntity();
/**
* Get the amount of ticks between each packet send
*
* @param side The target side.
* @return The amount of ticks to wait before sending another packet to this
* target
*/
public abstract int getPacketCooldown(Side side);
/**
* Add any additional data to the stream
* (only effective if there are both CLIENT and SERVER targeted
* regular networked fields ... currently nothing in GC uses this)
*
* @param networkedList List of additional data
*/
// public void addExtraNetworkedData(List<Object> networkedList)
// {
//
// }
/**
* Read any additional data from the stream
*
* @param stream The ByteBuf stream to read data from
*/
// public void readExtraNetworkedData(ByteBuf stream)
// {
//
// }
/**
* Called after a packet is read, only on client side.
*
* @param player The player associated with the received packet
*/
public abstract void onPacketClient(EntityPlayer player);
/**
* Called after a packet is read, only on server side.
*
* @param player The player associated with the received packet
*/
public abstract void onPacketServer(EntityPlayer player);
/**
* Packets will be sent to all (client-side) players within this range
*
* @return Maximum distance to send packets to client players
*/
public abstract double getPacketRange();
@Override
public void onUpdate()
{
super.onUpdate();
this.ticks++;
if (this.isNetworkedEntity())
{
if (!this.worldObj.isRemote && this.ticks % this.getPacketCooldown(Side.CLIENT) == 0)
{
if (this.fieldCacheClient == null)
{
try
{
this.initFieldCache();
}
catch (Exception e)
{
e.printStackTrace();
}
}
PacketDynamic packet = new PacketDynamic(this);
if (networkDataChanged)
{
GalacticraftCore.packetPipeline.sendToAllAround(packet, new TargetPoint(GCCoreUtil.getDimensionID(this.worldObj), this.posX, this.posY, this.posZ, this.getPacketRange()));
}
}
if (this.worldObj.isRemote && this.ticks % this.getPacketCooldown(Side.SERVER) == 0)
{
if (this.fieldCacheClient == null) //The target server cache may have been initialised to an empty set
{
try
{
this.initFieldCache();
}
catch (Exception e)
{
e.printStackTrace();
}
}
PacketDynamic packet = new PacketDynamic(this);
if (networkDataChanged)
{
GalacticraftCore.packetPipeline.sendToServer(packet);
}
}
}
}
private void initFieldCache() throws IllegalArgumentException, IllegalAccessException
{
this.fieldCacheClient = new LinkedHashSet<Field>();
this.fieldCacheServer = new LinkedHashSet<Field>();
for (Field field : this.getClass().getFields())
{
if (field.isAnnotationPresent(NetworkedField.class))
{
NetworkedField f = field.getAnnotation(NetworkedField.class);
if (f.targetSide() == Side.CLIENT)
{
this.fieldCacheClient.add(field);
}
else
{
this.fieldCacheServer.add(field);
}
}
}
}
@Override
public void getNetworkedData(ArrayList<Object> sendData)
{
Set<Field> fieldList = null;
boolean changed = false;
if (this.worldObj.isRemote)
{
fieldList = this.fieldCacheServer;
}
else
{
fieldList = this.fieldCacheClient;
}
for (Field f : fieldList)
{
boolean fieldChanged = false;
try
{
Object data = f.get(this);
Object lastData = lastSentData.get(f);
if (!NetworkUtil.fuzzyEquals(lastData, data))
{
fieldChanged = true;
}
sendData.add(data);
if (fieldChanged)
{
lastSentData.put(f, NetworkUtil.cloneNetworkedObject(data));
}
}
catch (Exception e)
{
e.printStackTrace();
}
changed |= fieldChanged;
}
//Currently unused as there is no entity in Galacticraft with extraNetworkedData
// if (changed)
// {
// this.addExtraNetworkedData(sendData);
// }
// else
// {
// ArrayList<Object> prevSendData = new ArrayList<Object>(sendData);
//
// this.addExtraNetworkedData(sendData);
//
// if (!prevSendData.equals(sendData))
// {
// changed = true;
// }
// }
networkDataChanged = changed;
}
@Override
public void decodePacketdata(ByteBuf buffer)
{
if (this.fieldCacheClient == null || this.fieldCacheServer == null)
{
try
{
this.initFieldCache();
}
catch (Exception e)
{
e.printStackTrace();
}
}
// if (this.worldObj.isRemote && this.fieldCacheClient.size() == 0)
// {
// return;
// }
// else if (!this.worldObj.isRemote && this.fieldCacheServer.size() == 0)
// {
// return;
// }
Set<Field> fieldSet = null;
if (this.worldObj.isRemote)
{
fieldSet = this.fieldCacheClient;
}
else
{
fieldSet = this.fieldCacheServer;
}
for (Field field : fieldSet)
{
try
{
Object obj = NetworkUtil.getFieldValueFromStream(field, buffer, this.worldObj);
field.set(this, obj);
}
catch (Exception e)
{
e.printStackTrace();
}
}
// this.readExtraNetworkedData(buffer);
}
}