Jump to content

[SOLVED]Tile data not updating on the client


brandon3055

Recommended Posts

I am having some trouble with a tile entity.

I am using nbt to store a data value but it seems nbt is only read on the server and i need this data on the client aswell can someone tell me how to synchronize the client with the server when the nbt is read?

 

this is my tile entity class

 

package tolkienaddon.tileentities;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagShort;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.storage.WorldInfo;
import tolkienaddon.blocks.ModBlocks;

public class TileWeatherController extends TileEntity implements IInventory {
int tick;
boolean running = false;
private ItemStack[] items;
public int charges;

public TileWeatherController() {
	items = new ItemStack[1];
}

@Override
public void updateEntity() {
	if (charges == 0)
		reload();

	final WorldInfo worldinfo = MinecraftServer.getServer().worldServers[0].getWorldInfo();
	toggleDownfall(worldinfo);
	if (worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord) && charges > 0) {
		if (worldinfo.isRaining()) {
			running = true;
		}
	}
}

private void reload() {
	ItemStack fuel = getStackInSlot(0);

	if (charges == 0 && fuel != null) {

		if (fuel.stackSize > 0 && fuel.isItemEqual(new ItemStack(Items.emerald))) {
			addCharge(10);
		}
	}
}

private void toggleDownfall(final WorldInfo worldinfo) {
	if (running) {

		if (tick < 70) {
			worldObj.spawnParticle("explode", xCoord + 0.5, yCoord + 1.5, zCoord + 0.5, 0D, 3D, 0D);
			worldObj.spawnParticle("explode", xCoord + 0.5, yCoord + 1.5, zCoord + 0.5, 0D, 5D, 0D);
			worldObj.spawnParticle("largesmoke", xCoord + 0.5, yCoord + 1, zCoord + 0.5, 0D, 1D, 0D);
			worldObj.spawnParticle("largesmoke", xCoord + 0.5, yCoord + 1, zCoord + 0.5, 0D, 2D, 0D);
			worldObj.spawnParticle("flame", xCoord + 0.5, yCoord + 1, zCoord + 0.5, 0D, 1D, 0D);
			worldObj.spawnParticle("largesmoke", xCoord + 0.5, yCoord + 1.2, zCoord + 0.5, 0D, -0.3D, 0D);
			worldObj.spawnParticle("largesmoke", xCoord + 0.5, yCoord + 1.2, zCoord + 0.5, 0D, -0.3D, 0D);
			worldObj.spawnParticle("largesmoke", xCoord + 0.5, yCoord + 1.2, zCoord + 0.5, 0D, -0.3D, 0D);

			worldObj.spawnParticle("flame", xCoord + 0.2, yCoord + 1, zCoord + 0.8, (worldObj.rand.nextFloat() - 0.5) * 1.5, 1.7D, (worldObj.rand.nextFloat() - 0.5) * 1.5);
			worldObj.spawnParticle("flame", xCoord + 0.8, yCoord + 1, zCoord + 0.8, (worldObj.rand.nextFloat() - 0.5) * 1.5, 1.7D, (worldObj.rand.nextFloat() - 0.5) * 1.5);
			worldObj.spawnParticle("flame", xCoord + 0.2, yCoord + 1, zCoord + 0.2, (worldObj.rand.nextFloat() - 0.5) * 1.5, 1.7D, (worldObj.rand.nextFloat() - 0.5) * 1.5);
			worldObj.spawnParticle("flame", xCoord + 0.8, yCoord + 1, zCoord + 0.2, (worldObj.rand.nextFloat() - 0.5) * 1.5, 1.7D, (worldObj.rand.nextFloat() - 0.5) * 1.5);
			worldObj.playSound(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D, "mob.ghast.fireball", 10F, worldObj.rand.nextFloat() * 0.1F + 0.9F, false);

		}
		if (tick > 80 && tick < 90) {
			worldObj.playSoundEffect(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D, "tolkienaddon:boom", 10F, worldObj.rand.nextFloat() * 0.1F + 0.9F);
			if(!worldObj.isRemote)
				worldinfo.setRaining(!worldinfo.isRaining());
		}
		if (tick > 110) {

			worldObj.playSound(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D, "random.fizz", 10F, worldObj.rand.nextFloat() * 0.1F + 0.9F, false);
			worldObj.spawnParticle("explode", xCoord + 0.5, yCoord + 0, zCoord + 0, 0D, 0D, 0D);
			worldObj.spawnParticle("explode", xCoord + 0.5, yCoord + 0, zCoord + 1, 0D, 0D, 0D);
			worldObj.spawnParticle("explode", xCoord + 0, yCoord + 0, zCoord + 0.5, 0D, 0D, 0D);
			worldObj.spawnParticle("explode", xCoord + 1, yCoord + 0, zCoord + 0.5, 0D, 0D, 0D);

		}
		if (tick > 130) {
			tick = 0;
			running = false;
			useCharge();
		}
		tick++;
	}

}

private void addCharge(int count){
	charges = 10;
	decrStackSize(0, 1);
	worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}

private void useCharge(){
	charges--;
	worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}

//==============================================INVENTORY====================================================//

@Override
	public int getSizeInventory() {
	return items.length;
}

@Override
public ItemStack getStackInSlot(int i) {
	return items[i];
}

@Override
public ItemStack decrStackSize(int i, int count) {
	ItemStack itemstack = getStackInSlot(i);

	if (itemstack != null) {
		if (itemstack.stackSize <= count) {
			setInventorySlotContents(i, null);
		} else {
			itemstack.splitStack(count);
			//updateContainingBlockInfo();
		}
	}
	return itemstack;
}

@Override
public ItemStack getStackInSlotOnClosing(int i) {
	ItemStack item = getStackInSlot(i);
	setInventorySlotContents(i, null);
	return item;
}

@Override
public void setInventorySlotContents(int i, ItemStack itemstack) {
	items[i] = itemstack;

	//updateContainingBlockInfo();
}

@Override
public String getInventoryName() {
	return "InventoryWeatherController";
}

@Override
public boolean hasCustomInventoryName() {
	return false;
}

@Override
public int getInventoryStackLimit() {
	return 64;
}

@Override
public boolean isUseableByPlayer(EntityPlayer player) {
	return player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.4) < 64;
}

@Override
public void openInventory() {
}

@Override
public void closeInventory() {
}

@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
	return itemstack.isItemEqual(new ItemStack(Items.emerald));
}

@Override
public void writeToNBT(NBTTagCompound compound) {
	NBTTagCompound[] tag = new NBTTagCompound[items.length];

	for (int i = 0; i < items.length; i++) {
		tag[i] = new NBTTagCompound();

		if (items[i] != null) {
			tag[i] = items[i].writeToNBT(tag[i]);
		}

		compound.setTag("Item" + i, tag[i]);
	}

	compound.setShort("Charges", (short) charges);

	super.writeToNBT(compound);
}

@Override
public void readFromNBT(NBTTagCompound compound) {
	NBTTagCompound[] tag = new NBTTagCompound[items.length];

	for (int i = 0; i < items.length; i++) {
		tag[i] = compound.getCompoundTag("Item" + i);
		items[i] = ItemStack.loadItemStackFromNBT(tag[i]);
	}

	charges = compound.getShort("Charges");

	super.readFromNBT(compound);
}

}

 

 

the field i am trying to save is "charges"

I am the author of Draconic Evolution

Link to comment
Share on other sites

NBT is mostly for saving and loading information either when game starts/quits or when chunks get loaded/unloaded.

 

Syncing client with server is entirely different.  The client side and the server side (as far as I understand) are pretty much separate programs and don't know anything about the classes in the other side.  So you need to send packets.

 

It is a little bit complicated, but there are a few tutorials out there.  I recently just learned it myself -- I had a render animation that I needed to do on the client but the information was based on entity AI (which runs on the server).

 

Here's how I did it (trust me, my way is one of the more simple, but feel free to look at other tutorials).  I used a system that took advantage of the FMLProxyPacket class and subscribed to some available packet events.

 

Basically, you’ll need a packet system that:

a. Registers a networking channel specific for your mod (this allows you to ignore packets that may come from other mods)

b. Has packet handler classes with Subscribes to the onClientPacketReceived and the onServerPacketReceived events.

c. Has a packet class that can distinguish packet type and what side it is on and process the packet accordingly

d. Sends the packets as needed (ideally just when there are changes, which is often in a setter method).

 

(In my examples, my mod is called WildAnimals -- wherever you see that you should replace with something relevant to your mod.)

Register a networking channel:

  - in your mod's main class create variables:

 

    
    public static final String networkChannelName = "WildAnimals"; // put the name of your mod here
public static FMLEventChannel channel;

  - in your mod's init event handler method (probably in your proxy class) you need:

		WildAnimals.channel = NetworkRegistry.INSTANCE.newEventDrivenChannel(WildAnimals.networkChannelName); // replace WildAnimals with the name of your main class

 

Create and Register Your Packet Handler Classes:

  - also in same init event handler method register your packet handler classes.  In the common proxy init() you need:

		WildAnimals.channel.register(new ServerPacketHandler());  // replace WildAnimals with name of your main class

  - and in your client proxy init() you need to additionally register the packet handler class:

		WildAnimals.channel.register(new ClientPacketHandler()); // replace WildAnimals with name of your main class

 

Create a new class called ServerPacketHandler which contains subscription to a server packet event with something like:

package wildanimals.networking;

import java.io.IOException;

import wildanimals.WildAnimals;
import wildanimals.network.entities.PacketWildAnimals;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent;

public class ServerPacketHandler 
{
protected String channelName;

@SubscribeEvent
public void onServerPacket(ServerCustomPacketEvent event) throws IOException 
{
	channelName = event.packet.channel();

	if (channelName == WildAnimals.networkChannelName)
	{
		PacketWildAnimals.processPacketOnServerSide(event.packet.payload(), event.packet.getTarget());
	}
}
}

 

And create a ClientPacketHandler class that extends the ServerPacketHandler class and subscribes to a client packet event:

package wildanimals.networking;

import java.io.IOException;

import wildanimals.WildAnimals;
import wildanimals.network.entities.PacketWildAnimals;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent;

// Remember client run configuration includes server side too
public class ClientPacketHandler extends ServerPacketHandler
{
@SubscribeEvent
public void onClientPacket(ClientCustomPacketEvent event) throws IOException 
{
	channelName = event.packet.channel();

	if (channelName == WildAnimals.networkChannelName)
	{
		PacketWildAnimals.processPacketOnClientSide(event.packet.payload(), event.packet.getTarget());
	}
}
}

 

Create a Packet Class

Create a packet class that allows you to generate and process received packets as needed.  Note that the actual data you create and receive will need to be changed for your particular need.  Hopefully you can understand how my example packet could be modified for your need.

 

There are a few things to understand -- a packet has a payload that consists of a byte stream.  It is totally up to you what bytes you put in the packet, but you have to come up with a useful format.  I expect to have other packet types so my first data sent consists of a packet type identifier.  I know it is a packet from my mod because of the channel it comes on (I check for the channel).  After that, I want to be able to put information about any of my entities into the packet so my next information is the entityID.  But since I have multiple types of entities, I have to get the class from the entityID and then change my processing based on that.  In that processing I simply take the information I want to send and put it in.  The key thing is to read back the data in the same order that you put it in when you create the packet.

 

package wildanimals.network.entities;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;

import java.io.IOException;

import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import wildanimals.WildAnimals;
import wildanimals.entities.bigcats.EntityBigCat;
import wildanimals.entities.herdanimals.EntityHerdAnimal;
import wildanimals.entities.serpents.EntitySerpent;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;

// this class is intended to be sent from server to client to keep custom entities synced
public class PacketWildAnimals
{
// define IDs for custom packet types
public final static int packetTypeIDEntity = 1;

public PacketWildAnimals()
{
	// don't need anything here
}

public static FMLProxyPacket createEntityPacket(Entity parEntity) throws IOException
{
	// DEBUG
	System.out.println("Sending PacketWildAnimals on Server Side");

	ByteBufOutputStream bbos = new ByteBufOutputStream(Unpooled.buffer());

	// create payload by writing to data stream
	// first identity packet type
	bbos.writeInt(packetTypeIDEntity);

	// write entity instance id (not the class registry id!)
	bbos.writeInt(parEntity.getEntityId());

	// now write entity-specific custom fields
	// process herd animals
	if (parEntity instanceof EntityHerdAnimal)
	{
		EntityHerdAnimal entityHerdAnimal = (EntityHerdAnimal)parEntity;
		bbos.writeFloat(entityHerdAnimal.getScaleFactor());
		bbos.writeBoolean(entityHerdAnimal.isRearing());			
	}
	// process serpents
	else if (parEntity instanceof EntitySerpent)
	{
		EntitySerpent entitySerpent = (EntitySerpent)parEntity;
		bbos.writeFloat(entitySerpent.getScaleFactor());
	}
	// process big cats
	else if (parEntity instanceof EntityBigCat)
	{
		EntityBigCat entityBigCat = (EntityBigCat)parEntity;
		bbos.writeFloat(entityBigCat.getScaleFactor());
	}

	// put payload into a packet		
	FMLProxyPacket thePacket = new FMLProxyPacket(bbos.buffer(), WildAnimals.networkChannelName);

	// don't forget to close stream to avoid memory leak
	bbos.close();

	return thePacket;
}

public static void processPacketOnClientSide(ByteBuf parBB, Side parSide) throws IOException
{
	if (parSide == Side.CLIENT)
	{
		// DEBUG
		System.out.println("Received PacketWildAnimals on Client Side");

		World theWorld = Minecraft.getMinecraft().theWorld;
		ByteBufInputStream bbis = new ByteBufInputStream(parBB);

		// process data stream
		// first read packet type
		int packetTypeID = bbis.readInt();

		switch (packetTypeID)
		{
			case packetTypeIDEntity:  // a packet sent from server to sync entity custom fields
			{
				// find entity instance
				int entityID = bbis.readInt();
				// DEBUG
				System.out.println("Entity ID = "+entityID);
				Entity foundEntity = getEntityByID(entityID, theWorld);
				// DEBUG
				System.out.println("Entity Class Name = "+foundEntity.getClass().getSimpleName());

				// process based on type of entity class
				// process herd animals
				if (foundEntity instanceof EntityHerdAnimal)
				{
					EntityHerdAnimal foundEntityHerdAnimal = (EntityHerdAnimal)foundEntity;
					// apply custom fields to entity instance
					foundEntityHerdAnimal.setScaleFactor(bbis.readFloat());
					foundEntityHerdAnimal.setRearing(bbis.readBoolean());
					// DEBUG
					System.out.println("Is rearing = "+foundEntityHerdAnimal.isRearing());
				}
				// process serpents
				else if (foundEntity instanceof EntitySerpent)
				{
					EntitySerpent foundEntitySerpent = (EntitySerpent)foundEntity;
					// apply custom fields to entity instance
					foundEntitySerpent.setScaleFactor(bbis.readFloat());
				}
				// process big cats
				else if (foundEntity instanceof EntityBigCat)
				{
					EntityBigCat foundEntityBigCat = (EntityBigCat)foundEntity;
					// apply custom fields to entity instance
					foundEntityBigCat.setScaleFactor(bbis.readFloat());
				}
				break;
			}
		}

		// don't forget to close stream to avoid memory leak
		bbis.close();			
	}
}

public static void processPacketOnServerSide(ByteBuf payload, Side parSide) 
{
	if (parSide == Side.SERVER)
	{
		// currently haven't defined any packets from client

	}
}

// some helper functions
public static Entity getEntityByID(int entityID, World world)        
{         
	for(Object o: world.getLoadedEntityList())                
	{                        
		if(((Entity)o).getEntityId() == entityID)                        
		{                                
			System.out.println("Found the entity");                                
			return ((Entity)o);                        
		}                
	}                
	return null;        
}	
}

 

Send the Packet When Needed:

Now all you need to do is to send the packet when you need to.  You could just send it in the onUpdate() method of your entity, but that is a bad idea because it is wasteful -- it sends a packet every tick.  Instead you should send it every time the variables you are tracking change.  Personally it can be tricky to remember to send a packet every time, so I rely on encapsulation -- I only change my variables by using a "setter" method and I put the sending packet inside that sender. 

 

Anyway, it is up to you when you want to send the packets to sync up the client.  The code you need depends on whether you're sending it to just one player (e.g. for their personal GUI) or to all the players (like in my case where I want all the players to see the entity animations at the same time).  Here are some examples of the code you can use to send the packet:

   // method to send sync packet from server to client, should send whenever a custom field is set (from setter method)
// send sync packet to client, if on server side
public void sendSyncPacket()
{
	if (!this.worldObj.isRemote)
	{
    	try 
    	{
			WildAnimals.channel.sendToAll(PacketWildAnimals.createEntityPacket(this));
		} 
    	catch (IOException e) 
    	{
			e.printStackTrace();
		}
	}
}

 

You should check out the other methods for the channel, because you can sendToServer, etc.

 

Hope this helps.  I know it is annoying that you have to do so much work in order to simply send a couple values to the client, but trust me that you have to do it and you might as well learn.  I won't feel bad if you use a different tutorial to do it, but I'm pretty happy with my implementation so far.

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

YOU ARE AWESOME! Thats the first tutorial I have been able to understand all the other tutorials i looked at were insanely complex and impossible for me to figure out but i think i understand how this works now.

 

I just have one thing i cant figure out and that is the "Create and Register Your Packet Handler Classes" part can you please explain in more detail. i dont use init() methods in my proxys and im not sure how to set them up.

 

My proxys:

common

 

 

Thank you for your help!
package tolkienaddon.core.proxy;

import tolkienaddon.tileentities.TileSunDial;
import tolkienaddon.tileentities.TileWeatherController;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;

public class CommonProxy {

public void registerTileEntities() {
	GameRegistry.registerTileEntity(TileWeatherController.class, "TileWeatherController");
	GameRegistry.registerTileEntity(TileSunDial.class, "TileSunDial");
}

public void registerRendering() {
}

}

 

client

 

package tolkienaddon.core.proxy;

import net.minecraftforge.client.MinecraftForgeClient;
import tolkienaddon.client.render.BowRenderer;
import tolkienaddon.items.ModItems;

public class ClientProxy extends CommonProxy {

@Override
public void registerRendering() {
	//ClientRegistry.bindTileEntitySpecialRenderer(TileEntityTestContainer.class, new RenderTestContainer());
	MinecraftForgeClient.registerItemRenderer(ModItems.wyvernBow, new BowRenderer());
	MinecraftForgeClient.registerItemRenderer(ModItems.draconicBow, new BowRenderer());
}

}

 

And my main mod class:

 

 
package tolkienaddon;

import net.minecraft.creativetab.CreativeTabs;
import net.minecraftforge.common.MinecraftForge;
import tolkienaddon.blocks.ModBlocks;
import tolkienaddon.client.interfaces.GuiHandler;
import tolkienaddon.core.handler.CraftingHandler;
import tolkienaddon.core.handler.FMLEventHandler;
import tolkienaddon.core.handler.ModEventHandler;
import tolkienaddon.core.handler.packethandling.ClientPacketHandler;
import tolkienaddon.core.handler.packethandling.ServerPacketHandler;
import tolkienaddon.core.proxy.CommonProxy;
import tolkienaddon.creativetab.TolkienTab;
import tolkienaddon.items.ModItems;
import tolkienaddon.lib.References;
import tolkienaddon.world.TolkienWorldGenerator;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.FMLEventChannel;
import cpw.mods.fml.common.registry.GameRegistry;

@Mod(modid = References.MODID, name = References.MODNAME, version = References.VERSION)
public class Tolkienaddon {
@Mod.Instance
public static Tolkienaddon instance;

@SidedProxy(clientSide = References.CLIENTPROXYLOCATION, serverSide = References.COMMONPROXYLOCATION)
public static CommonProxy proxy;

private static CreativeTabs tolkienTab = new TolkienTab(CreativeTabs.getNextID(), References.MODID);

public static final String networkChannelName = "tolkienaddon";
public static FMLEventChannel channel;

public static CreativeTabs getCreativeTab() {
	return tolkienTab;
}

@Mod.EventHandler
public static void preInit(final FMLPreInitializationEvent event) {

	ModBlocks.init();

	ModItems.init();

	CraftingHandler.init();

	GameRegistry.registerWorldGenerator(new TolkienWorldGenerator(), 1);

	proxy.registerTileEntities();

	proxy.registerRendering();

}

@Mod.EventHandler
public void init(final FMLInitializationEvent event) {
	//I thought i would give this a try but it just gives me a null point exeption
	Tolkienaddon.channel.register(new ServerPacketHandler()); 
	Tolkienaddon.channel.register(new ClientPacketHandler());

	MinecraftForge.EVENT_BUS.register(new ModEventHandler());

	FMLCommonHandler.instance().bus().register(new FMLEventHandler());

	new GuiHandler();

}

@Mod.EventHandler
public void postInit(final FMLPostInitializationEvent event) {

}
}

 

 

Thank you for your help!

I am the author of Draconic Evolution

Link to comment
Share on other sites

@jabelar this is awesome. Could you please post this tutorial somewhere on the wiki?

 

Thanks.  I've just learned modding recently and finally have confidence to share my understanding on a couple topics.  I'm just figuring out best place to post my tutorials and plan to post a few.  I think this packet handling approach deserves a tutorial, and also my entity modeling has gotten pretty good (check out my snake and elephant entities in this video:

).

 

I don't like posting mis-information though, so want to make sure I thoroughly understand something before deciding to teach others.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Or just use the getDescriptionPacket() and the onPacketData() method in the TileEntity class...

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

so would you be able to help me out with my proxys? im not sure how you set up your init() methods.

 

When you start your tutorials i would very much like to take a look the way you explained this was awesome.

 

Well, as larsgerrit said for TileEntities they are specifically made for syncing extra data between client and server (for instance they are the intermediary for container GUIs and such.  So you don't need to do my packets for that.  But you still can, and mine are a useful general packet that I use a lot for regular Entities.

 

Anyway, for proxies you can do it a few different ways.  This is one of the tricky points to understand when first modding -- the proxies are related to your run configuration (i.e. in Eclipse).  When you run Minecraft, there is always a server but you may or not have a client running locally.  When you use the Client run configuration, it also includes the server classes.  So this idea of proxy helps organize the case where your run configuration is only server, or also server with client. 

 

The server stuff goes in the "Common" proxy because it is common to both the Client and the Server run configurations.  Then any client-specific stuff goes into a "Client" proxy, but that actually extends "Common" proxy to cover both sides that will execute in the run configuration.

 

I know that is kinda confusing, but keep reading it over until it makes sense.

 

Okay, with that being said I personally organize my proxy like this.  Note I took out a lot of stuff to make so you can just see the organization.

 

CommonProxy:

 

public class CommonProxy implements IGuiHandler // the IGuiHandler is used for a simple client-server packet interface

{

   

    protected int modEntityID = 0;

    protected Configuration config;

 

public void preInit(FMLPreInitializationEvent event)

{

// load configuration before doing anything else

processConfig();

 

// register stuff

registerBlocks();

    registerItems();

      registerTileEntities();

        registerModEntities();

        registerEntitySpawns();

        registerFuelHandlers();

}

 

public void init(FMLInitializationEvent event)

{

        // register custom event listeners

        registerEventListeners();

 

        // register networking channel

        registerNetworkingChannel();

       

        // register server packet handler

        registerServerPacketHandler();

       

        // register recipes here to allow use of items from other mods

    registerRecipes();

    }

 

public void postInit(FMLPostInitializationEvent event)

{

// can do some inter-mod stuff here

}

 

protected void processConfig()

{

// might need to use suggestedConfigFile (event.getSuggestedConfigFile) location to publish

}

 

// register blocks

    public void registerBlocks()

    {

//example: GameRegistry.registerBlock(blockTomato, "tomatoes");

    }

 

// register items

    private void registerItems()

    {

// DEBUG

        System.out.println("Registering items");

 

        // spawn eggs are registered during entity registration

   

    // example: GameRegistry.registerCustomItemStack(name, itemStack);

    }

 

// register tileentities

    public void registerTileEntities()

    {

// DEBUG

        System.out.println("Registering tile entities");

         

    // example: GameRegistry.registerTileEntity(TileEntityStove.class, "stove_tile_entity");

    }

 

    // register recipes

    public void registerRecipes()

    {

// DEBUG

        System.out.println("Registering recipes");

         

// examples:

    //    GameRegistry.addRecipe(recipe);

//    GameRegistry.addShapedRecipe(output, params);

//    GameRegistry.addShapelessRecipe(output, params);

//    GameRegistry.addSmelting(input, output, xp);

    }

 

    // register entities

    public void registerModEntities()

    {   

// DEBUG

        System.out.println("Registering entities");

       

        // uses configuration file to control whether each entity type is registered, to allow user customization

       

 

    }

         

    public void registerEntitySpawns()

    {

// DEBUG

        System.out.println("Registering natural spawns");

 

    // register natural spawns for entities             

    }

   

    public void registerFuelHandlers()

    {

// DEBUG

        System.out.println("Registering fuel handlers");

       

    // example: GameRegistry.registerFuelHandler(handler);

    }

   

    public void registerEventListeners()

    {

// DEBUG

        System.out.println("Registering event listeners");

 

        MinecraftForge.EVENT_BUS.register(new WildAnimalsEventHandler());

    MinecraftForge.TERRAIN_GEN_BUS.register(new WildAnimalsTerrainGenEventHandler());;

    MinecraftForge.ORE_GEN_BUS.register(new WildAnimalsOreGenEventHandler());   

    // some events, especially tick, is handled on FML bus

    FMLCommonHandler.instance().bus().register(new WildAnimalsFMLEventHandler());

}

 

public void sendMessageToPlayer(ChatComponentText msg) { }

 

public void serverLoad(FMLServerStartingEvent event) { }

 

public void registerNetworkingChannel()

{

WildAnimals.channel = NetworkRegistry.INSTANCE.newEventDrivenChannel(WildAnimals.networkChannelName);

}

 

public void registerServerPacketHandler()

{

WildAnimals.channel.register(new ServerPacketHandler());

}

 

@Override

public Object getServerGuiElement(int ID, EntityPlayer player, World world,

int x, int y, int z) {

return null;

}

 

@Override

public Object getClientGuiElement(int ID, EntityPlayer player, World world,

int x, int y, int z) {

return null;

}

}

 

 

And ClientProxy:

 

public class ClientProxy extends CommonProxy

{

 

@Override

public void preInit(FMLPreInitializationEvent event)

{

// DEBUG

        System.out.println("on Client side");

       

// do common stuff

super.preInit(event);

 

        // do client-specific stuff

        registerRenderers();

}

@Override

public void init(FMLInitializationEvent event)

{

// DEBUG

        System.out.println("on Client side");

 

        // do common stuff

super.init(event);

 

// do client-specific stuff

registerClientPacketHandler();

}

 

private void registerClientPacketHandler()

{

WildAnimals.channel.register(new ClientPacketHandler());

}

 

@Override

public void postInit(FMLPostInitializationEvent event)

{

// DEBUG

        System.out.println("on Client side");

 

        // do common stuff

super.postInit(event);

 

// do client-specific stuff

}

 

public void registerRenderers()

    {

     

    }

 

    @Override

    public void sendMessageToPlayer(ChatComponentText msg) {

        Minecraft.getMinecraft().thePlayer.addChatMessage(msg);

    }

   

    @Override

public void serverLoad(FMLServerStartingEvent event)

    {

// DEBUG

        System.out.println("on Client side");

}

 

}

 

 

Then in my mod's main class the organization is very simple and clean.  Basically you call the proxy's related method as appropriate.  Here's just the event handler stuff (not quite my whole main class):

 

    // Says where the client and server 'proxy' code is loaded.

    @SidedProxy(clientSide="wildanimals.proxy.client.ClientProxy", serverSide="wildanimals.proxy.server.ServerProxy")

    public static CommonProxy proxy;

           

    @EventHandler

    // preInit "Run before anything else. Read your config, create blocks, items, etc, and register them with the GameRegistry."

    public void preInit(FMLPreInitializationEvent event)

    { 

        // DEBUG

        System.out.println("preInit()"+event.getModMetadata().name);

        event.getModMetadata().autogenerated = false ; // stops it from complaining about missing mcmod.info

        event.getModMetadata().credits = "jabelar";

        event.getModMetadata().description = "The wildest animals that ever inhabited Minecraft";

 

        proxy.preInit(event);

    }

 

    @EventHandler

    // load "Do your mod setup. Build whatever data structures you care about. Register recipes."

    public void init(FMLInitializationEvent event)

    {

   

        // DEBUG

        System.out.println("init()");

       

        proxy.init(event);

    }

 

@EventHandler

    // postInit "Handle interaction with other mods, complete your setup based on this."

    public void postInit(FMLPostInitializationEvent event)

{

        // DEBUG

        System.out.println("postInit()");

       

        proxy.postInit(event);

    }

 

@EventHandler

// register server commands

// refer to tutorial at http://www.minecraftforge.net/wiki/Server_Command#Mod_Implementation

public void serverLoad(FMLServerStartingEvent event)

{

        // DEBUG

        System.out.println("serverLoad()");

       

proxy.serverLoad(event);

}

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

ok now i understand. If you look at my earlier post that is how ALL of the tutorials i have seen so far have set up the proxys. I have never seen anyone add the FMLPreInit/Init/PostInit events to their proxys. After i get some sleep i will try setting up my proxys like yours and will let you know how i go.

 

I will also have to look into what larsgerrits said and see if i can figure that out. 

I am the author of Draconic Evolution

Link to comment
Share on other sites

Ok im calling this one solved! I ended up going with larsgerrits suggestion because it was simple and its designed for this exact application although it did take a bit to figure out because it seems to have changed a little in 1.7.2 For anyone else having the same problem.

@Override
public Packet getDescriptionPacket() {
//Debug
System.out.println("[DEBUG]:Server sent tile sync packet");

NBTTagCompound tagCompound = new NBTTagCompound();
this.writeToNBT(tagCompound);
return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, tagCompound);
}

@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
//Debug
System.out.println("[DEBUG]:Client recived tile sync packet");

readFromNBT(pkt.func_148857_g());
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}

@jabelar I will still be using your packet handler because the next thing on my list is adding buttons to the gui which requires a packet handler. If i have any more problems figuring it out i will pm you (if that's ok with you?) but i think i have it figured out.

 

I am the author of Draconic Evolution

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.