Posted May 3, 201411 yr 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
May 3, 201411 yr 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/
May 3, 201411 yr Author Thanks i will look over your code and see if i can figure it out. I looked at a few of the 1.7.2 tutorials using the netty system but i couldn't figure out how to use it. I will let you know how i go. I am the author of Draconic Evolution
May 3, 201411 yr Author 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
May 3, 201411 yr @jabelar this is awesome. Could you please post this tutorial somewhere on the wiki? Here could be your advertisement!
May 3, 201411 yr @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/
May 3, 201411 yr 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/
May 3, 201411 yr Or just use the getDescriptionPacket() and the onPacketData() method in the TileEntity class... Yeah, I see now he's talking about TileEntities not regular Entities. TileEntities do have built in packet handling methods. Check out my tutorials here: http://jabelarminecraft.blogspot.com/
May 3, 201411 yr Author 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. I am the author of Draconic Evolution
May 4, 201411 yr 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/
May 4, 201411 yr Author 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
May 4, 201411 yr Author 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
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.