Jump to content

[Solved]read/write Entity NBT for both sides?


gff1979

Recommended Posts

I'm writing a mod that creates a mob with visual attributes but I'm having a time figuring out how to save them for persistence with NBTTagCompounds. I think what is happening is that either the server or the client one is not saving nbt data but the other is. I'm also confused at to which is doing what and exactly what data is returned through isRemote. I thought that my server/client proxy class declarations might have been switched but I cannot find where they might be switched at. Do I try and capture the one Entity that's NBT value IS being saved and try to set the one that isn't to that value somehow? If so, what is the best way to do that?

 

package gff.companime.entity.companions;

import java.util.Random;

import gff.companime.Companime;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.ai.EntityAIAvoidEntity;
import net.minecraft.entity.ai.EntityAIFollowGolem;
import net.minecraft.entity.ai.EntityAILookAtTradePlayer;
import net.minecraft.entity.ai.EntityAIMoveIndoors;
import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction;
import net.minecraft.entity.ai.EntityAIOpenDoor;
import net.minecraft.entity.ai.EntityAIPlay;
import net.minecraft.entity.ai.EntityAIRestrictOpenDoor;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAITempt;
import net.minecraft.entity.ai.EntityAITradePlayer;
import net.minecraft.entity.ai.EntityAIVillagerMate;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.ai.EntityAIWatchClosest2;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;

public class EntityGal extends EntityAgeable
{

public int haircolor;
public int eyecolor;

public EntityGal(World par1World)
    {
        super(par1World);
        this.texture = "/textures/mob/gal.png";
//        this.randomTickDivider = 0;
//        this.isMating = false;
//        this.isPlaying = false;
    
        this.moveSpeed = 0.5F;
        this.setSize(0.6F, 1.8F);
        this.getNavigator().setBreakDoors(true);
        this.getNavigator().setAvoidsWater(true);
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false));
        this.tasks.addTask(2, new EntityAIMoveIndoors(this));        
        this.tasks.addTask(3, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F));
        this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F));
        this.tasks.addTask(5, new EntityAIWander(this, 0.3F));
        this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F));
        
        genFeatures();
    }

public void genFeatures()
{
	Random rnd = new Random();
	this.haircolor = rnd.nextInt(0xFFFFFF);
	this.eyecolor = rnd.nextInt(0xFFFFFF);		
}

@Override
public EntityAgeable createChild(EntityAgeable entityageable) {
	// TODO Auto-generated method stub
	return null;
}

@Override
public int getMaxHealth() {
	// TODO Auto-generated method stub
	return 10;
}

public boolean interact(EntityPlayer par1EntityPlayer)
    {
        ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem();

        System.out.println(this);
        System.out.println("ID: "+this.entityId);
        System.out.println("isRemote = "+this.worldObj.isRemote);
        System.out.println("Hair color = "+this.haircolor);
                          
        return true;
    }

// NBT for persisting attributes for this instance of a Gal
    public void writeEntityToNBT(NBTTagCompound nbt)
    {
    	super.writeEntityToNBT(nbt);
    	
    	nbt.setInteger("haircolor", this.haircolor);    	    
    	
    	
    	
    }
    
    public void readEntityFromNBT(NBTTagCompound nbt)
    {
    	super.readEntityFromNBT(nbt);
    	
    	this.haircolor = nbt.getInteger("haircolor");
    	
    	    	    	
    	// call to check for non initialized persistant variables.    	
    }    
}


 

These are the ouputs that my right click does on the Entity:

 

After right clicking the entities in a newly created world:

2013-06-26 02:41:15 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7406, l='MpServer', x=202.84, y=64.00, z=-22.14]

2013-06-26 02:41:15 [iNFO] [sTDOUT] ID: 7406

2013-06-26 02:41:15 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:15 [iNFO] [sTDOUT] Hair color = 15120629

2013-06-26 02:41:15 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7406, l='New World', x=202.74, y=64.00, z=-21.63]

2013-06-26 02:41:15 [iNFO] [sTDOUT] ID: 7406

2013-06-26 02:41:15 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:15 [iNFO] [sTDOUT] Hair color = 9323139

2013-06-26 02:41:16 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7409, l='MpServer', x=203.63, y=64.00, z=-23.59]

2013-06-26 02:41:16 [iNFO] [sTDOUT] ID: 7409

2013-06-26 02:41:16 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:16 [iNFO] [sTDOUT] Hair color = 4058533

2013-06-26 02:41:16 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7409, l='New World', x=203.62, y=64.00, z=-24.09]

2013-06-26 02:41:16 [iNFO] [sTDOUT] ID: 7409

2013-06-26 02:41:16 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:16 [iNFO] [sTDOUT] Hair color = 12925493

2013-06-26 02:41:18 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7411, l='MpServer', x=200.50, y=64.00, z=-25.50]

2013-06-26 02:41:18 [iNFO] [sTDOUT] ID: 7411

2013-06-26 02:41:18 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:18 [iNFO] [sTDOUT] Hair color = 15959885

2013-06-26 02:41:18 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7411, l='New World', x=200.50, y=64.00, z=-25.50]

2013-06-26 02:41:18 [iNFO] [sTDOUT] ID: 7411

2013-06-26 02:41:18 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:18 [iNFO] [sTDOUT] Hair color = 4745496

Second Click after exit to menu and restarting the same save:

2013-06-26 02:41:28 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7573, l='MpServer', x=207.23, y=63.00, z=-19.99]

2013-06-26 02:41:28 [iNFO] [sTDOUT] ID: 7573

2013-06-26 02:41:28 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:28 [iNFO] [sTDOUT] Hair color = 14664608

2013-06-26 02:41:28 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7573, l='New World', x=207.66, y=63.00, z=-20.27]

2013-06-26 02:41:28 [iNFO] [sTDOUT] ID: 7573

2013-06-26 02:41:28 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:28 [iNFO] [sTDOUT] Hair color = 9323139

2013-06-26 02:41:31 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7574, l='MpServer', x=205.88, y=64.00, z=-26.38]

2013-06-26 02:41:31 [iNFO] [sTDOUT] ID: 7574

2013-06-26 02:41:31 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:31 [iNFO] [sTDOUT] Hair color = 16074411

2013-06-26 02:41:31 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7574, l='New World', x=205.85, y=64.00, z=-26.36]

2013-06-26 02:41:31 [iNFO] [sTDOUT] ID: 7574

2013-06-26 02:41:31 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:31 [iNFO] [sTDOUT] Hair color = 12925493

2013-06-26 02:41:32 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7575, l='MpServer', x=200.50, y=64.00, z=-25.50]

2013-06-26 02:41:32 [iNFO] [sTDOUT] ID: 7575

2013-06-26 02:41:32 [iNFO] [sTDOUT] isRemote = true

2013-06-26 02:41:32 [iNFO] [sTDOUT] Hair color = 6780648

2013-06-26 02:41:32 [iNFO] [sTDOUT] EntityGal['entity.Gal.name'/7575, l='New World', x=200.50, y=64.00, z=-25.50]

2013-06-26 02:41:32 [iNFO] [sTDOUT] ID: 7575

2013-06-26 02:41:32 [iNFO] [sTDOUT] isRemote = false

2013-06-26 02:41:32 [iNFO] [sTDOUT] Hair color = 4745496

 

As shown, the second of each entity is saving the data properly and it states that it's the client side world or "New World". The Entities world that isn't saving is MpServer.

 

I'm a bit confused as to what is going on. My assumption is that there are two instances of the entity one for client and one for server. As I said I'm not sure what exactly isRemote returns. Is it true if the entity is on MpServer? Because the documentation in my IDE states that it should return false, yet my entity's println(this) would state otherwise.

 

 

My Entity Render: (this renders hair color based on the entity.haircolor value, but doesn't seem to use the version that gets saved...)

package gff.companime.client.renderer.entity;

import java.awt.Color;

import org.lwjgl.opengl.GL11;

import gff.companime.entity.companions.EntityGal;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.passive.EntitySheep;

@SideOnly(Side.CLIENT)
public class RenderGal extends RenderLiving 
{

public RenderGal(ModelBase modelGal, ModelBase modelHair, float par2) 
{
	super(modelGal, par2);
	this.setRenderPassModel(modelHair);
}

protected int setHairColor(EntityGal gal, int par2, float par3)
    {
        this.loadTexture("/textures/mob/longhair.png");
        
        Color c = new Color(gal.haircolor);
        byte red = (byte) c.getRed();
        byte green = (byte) c.getGreen();
        byte blue = (byte) c.getBlue();
        
        GL11.glColor3b(red,green,blue);
        return 1;     
    }
    /**
     * Queries whether should render the specified pass or not.
     */
    protected int shouldRenderPass(EntityLiving par1EntityLiving, int par2, float par3)
    {
        return this.setHairColor((EntityGal)par1EntityLiving, par2, par3);
    }

}

 

My mod class:

package gff.companime; //The package your mod is in

import java.util.logging.Logger;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.Configuration;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PreInit;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
import cpw.mods.fml.common.SidedProxy;
import gff.companime.*;
import gff.companime.block.PetrifiedWood;
import gff.companime.entity.*;
import gff.companime.entity.companions.EntityGal;
import gff.companime.entity.companions.EntityGalBase;
import gff.companime.item.Bracelet;
import gff.companime.server.CommonProxy;

@NetworkMod(clientSideRequired=true,serverSideRequired=false, //Whether client side and server side are needed
clientPacketHandlerSpec = @SidedPacketHandler(channels = {"NitroMod" }, packetHandler = ClientPacketHandler.class), //For clientside packet handling
serverPacketHandlerSpec = @SidedPacketHandler(channels = {"NitroMod" }, packetHandler = ServerPacketHandler.class)) //For serverside packet handling

@Mod(modid=Companime.modid,name="Companime",version="0.0.1")

public class Companime // Mod class
{ 

public static final String modid = "gff_Companime"; // I think this is proper use but I don't fully grok

// * Create instances for use in Registration *

// Tiles:

// blocks:
public final static Block petrifiedWood = new PetrifiedWood(500, Material.rock);

// Items:
public final static Item braceletItem = new Bracelet(500);

// Entities:
// public final static EntityGal gal = new EntityGal(null);	

@Instance( modid ) //The instance, this is very important later on
public static Companime instance = new Companime();

@SidedProxy(clientSide = "gff.companime.client.ClientProxy", serverSide = "gff.companime.server.CommonProxy")
public static CommonProxy proxy;

public static Logger logger;

// * Methods *
@PreInit
public void preInit(FMLPreInitializationEvent event) 
{
	logger = Logger.getLogger(modid);
	logger.setParent(FMLLog.getLogger());

	Configuration config = new Configuration(
			event.getSuggestedConfigurationFile());
	//Configuration.load(config);
}

@Init
//	public void InitCobaltCraft(FMLInitializationEvent event){ //Your main initialization method
public void load(FMLInitializationEvent event)
{ //Your main initialization method									

	NetworkRegistry.instance().registerGuiHandler(this, proxy); //Registers the class that deals with GUI data

	proxy.registerRenderInformation();

	proxy.registerTiles();

	proxy.registerBlocks();

	proxy.addNames();

	proxy.addRecipes();

	proxy.addEntities();

	// Register entities? proxy.addEntities(); ?
//		 EntityRegistry.registerModEntity(EntityGal.class, "Gal", 2, this, 80, 3, true);
//	     EntityRegistry.addSpawn(EntityGal.class, 5, 2, 6, EnumCreatureType.creature, BiomeGenBase.beach);
//	     LanguageRegistry.instance().addStringLocalization("name.gal.entity", "Gal");

}

}

 

ClientProxy: (currently just registers the entity and spawn egg data)

 

package gff.companime.client;

import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.registry.EntityRegistry;
import gff.companime.*;
import gff.companime.client.model.*;
import gff.companime.client.renderer.entity.RenderGal;
import gff.companime.client.renderer.entity.RenderGalBase;
import gff.companime.entity.*;
import gff.companime.entity.companions.EntityGal;
import gff.companime.entity.companions.EntityGalBase;
import gff.companime.server.CommonProxy;
import net.minecraftforge.client.MinecraftForgeClient;

public class ClientProxy extends CommonProxy {

@Override
public void registerRenderInformation()
{		
//		// Register Models
//		// Test Gal
//		RenderingRegistry.registerEntityRenderingHandler(EntityGalBase.class, new RenderGalBase(new ModelGalBase(), new ModelGalBase(), 0.5F));				
//		EntityRegistry.registerGlobalEntityID(EntityGalBase.class, "TestGal", EntityRegistry.findGlobalUniqueEntityId() , 3515848, 0xFF8020);
	// Real Gal
	RenderingRegistry.registerEntityRenderingHandler(EntityGal.class, new RenderGal(new ModelGal(), new ModelLongHair(), 0.5F));				
	EntityRegistry.registerGlobalEntityID(EntityGal.class, "Gal", EntityRegistry.findGlobalUniqueEntityId() , 0xd4a98a, 0xd4a98a);
}

}

 

CommonProxy:

package gff.companime.server;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.MinecraftForge;
import cpw.mods.fml.common.network.IGuiHandler;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
import gff.companime.*;
import gff.companime.item.*;
import gff.companime.block.*;
import gff.companime.entity.companions.*;

public class CommonProxy implements IGuiHandler //THIS IS IMPORTANT, CANNOT BE A PROXY/GUI HANDLER WITHOUT THIS!!
{ 	

// Methods
public void registerRenderInformation() //Client side texture registering
{

}

@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{ //For GUI's
return null;
}

@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{ //For GUI's
	return null;
}

public void registerTiles()
{ //For registering TileEntities

}

public void registerBlocks()
{ //For registering Blocks

	// Petrified Wood Block

	LanguageRegistry.addName(Companime.petrifiedWood, "Petrified Wood");
	MinecraftForge.setBlockHarvestLevel(Companime.petrifiedWood, "axe", 0);
}

public void addNames() // Change to addItems and handle more than just names soon...
{ //For adding Item's in game names

	// Friendship bracelet item

	LanguageRegistry.addName(Companime.braceletItem, "Friendship Bracelet");
}

public void addRecipes()
{ //For adding your Item's recipes

	// Friendship Bracelet Recipes
	ItemStack silkString = new ItemStack(Item.silk);		

	GameRegistry.addRecipe( new ItemStack(Companime.braceletItem) ,
	"xxx", 
	"x x",
	"xxx",
	Character.valueOf('x') , silkString);
}

public void addEntities()
{

	// Gal		
	EntityRegistry.registerModEntity(EntityGal.class, "Gal", 2, Companime.instance, 30, 3, true);
	EntityRegistry.addSpawn(EntityGal.class, 5, 2, 6, EnumCreatureType.creature, BiomeGenBase.beach);		
	LanguageRegistry.instance().addStringLocalization("name.gal.entity", "Gal");
}

}

 

Any help would be appreciated even if it's something simple or relates to something else in the code as I just started learning MCForge this weekend...

Link to comment
Share on other sites

"isRemote" returns true if the world is client-side. what's actually saving correctly in your post is the server side. so, when you exit and return, the server loads what's saved on the nbt, but the client side generates a new random hair color. i'm not too familiar with mc's entity stuff, but i've played around with it a bit and i think you can use the data watcher to fix that. if not, then maybe you can send packets from the server to the client containing the entity id and hair color

Link to comment
Share on other sites

Thanks for the help. I have a working implementation and just to help anyone here's the simplified version of my EntityGal implementation.

package gff.companime.entity.companions;

import java.util.Random;

import gff.companime.Companime;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.DataWatcher;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.ai.EntityAIAvoidEntity;
import net.minecraft.entity.ai.EntityAIFollowGolem;
import net.minecraft.entity.ai.EntityAILookAtTradePlayer;
import net.minecraft.entity.ai.EntityAIMoveIndoors;
import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction;
import net.minecraft.entity.ai.EntityAIOpenDoor;
import net.minecraft.entity.ai.EntityAIPlay;
import net.minecraft.entity.ai.EntityAIRestrictOpenDoor;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAITempt;
import net.minecraft.entity.ai.EntityAITradePlayer;
import net.minecraft.entity.ai.EntityAIVillagerMate;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.ai.EntityAIWatchClosest2;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;

public class EntityGal extends EntityAgeable
{
public int haircolor;

public EntityGal(World par1World)
    {
        super(par1World);
        this.texture = "/textures/mob/gal/gal.png";
        this.moveSpeed = 0.5F;
        this.setSize(0.6F, 1.8F);
        this.getNavigator().setBreakDoors(true);
        this.getNavigator().setAvoidsWater(true);
        // AI tasks for the entity to perform
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false));
        this.tasks.addTask(2, new EntityAIMoveIndoors(this));        
        this.tasks.addTask(3, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F));
        this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F));
        this.tasks.addTask(5, new EntityAIWander(this, 0.3F));
        this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F));
        
        // Generate instance specific data
        Random rnd = new Random();
        this.setHairColor(rnd.nextInt(0xffffff));
        this.haircolor = this.getHairColor();

    }

    public void entityInit()
    {
        super.entityInit();
        // Create a data watcher for hair color
        this.dataWatcher.addObject(20, Integer.valueOf(0));
        
    }

// writes persistent values that is saved to the world server side
    public void writeEntityToNBT(NBTTagCompound nbt)
    {
    	super.writeEntityToNBT(nbt);
    	
    	nbt.setInteger("haircolor", this.getHairColor());  	        	    	
    }
    
// reads a persistant value from the server's world
    public void readEntityFromNBT(NBTTagCompound nbt)
    {
    	super.readEntityFromNBT(nbt);
    	
    	this.setHairColor(nbt.getInteger("haircolor"));        	    	       
    }   
    
    // This function will set an RGB color
    // It is called later with EntityGal.getHairColor() in the renderer
    public void setHairColor(int color)
    {
        this.dataWatcher.updateObject(20, Integer.valueOf(color));
    }
    
    // Returns the value set by setHairColor as "haircolor" in the Entities NBTTagCompound
    public int getHairColor()
    {
        return this.dataWatcher.getWatchableObjectInt(20);
    }
    
@Override
public EntityAgeable createChild(EntityAgeable entityageable) {
	// TODO Auto-generated method stub
	return null;
}

@Override
public int getMaxHealth() {
	// TODO Auto-generated method stub
	return 10;
}

public boolean interact(EntityPlayer par1EntityPlayer)
    {
        ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem();
        
        System.out.println(this.worldObj);
        System.out.println("ID: "+this.entityId);
        System.out.println("isRemote = "+this.worldObj.isRemote);
        System.out.println(this.getHairColor()); // Example of how to get this entity haircolor
        return true;
    }

}

 

I learned that a DataWatcher instance can only have IDs from 0 to 31 and that if your child class is using the parents instance of datawatcher it shouldn't use any ids from the parent. These throw exceptions. Also, don't write to them from the Client or if isRemote is true. They are made to store from client then update from server so they throw an exception when written/updated clientside.

 

It's a bit of code to have to write a get/set for each persistent parameter if you have more than a handful of them but it works. If I'm missing something or anyone has more advice it would be appreciated.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.