Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. Yeah, it was a bummer when I realized the same thing -- I just wanted to pass one boolean to my model. However, since then I've been playing with more complicated animations where I pass other states, counters, and such, and you'll probably want to expand into such things too so probably worth setting it up. However, for quick fix you might be able to use dataWatcher. It is another method for doing simply syncs of entities. It has some drawbacks, but only if you're concerned about other people adding mods that interact with your entities and such. My main point is that you need to get the information to the client entity. There are multiple ways you can try to do that.
  2. I think the problem is that the rendering happens on the client but the state is probably updated (along with other mob AI and behavior) on the server. I just ran into this sort of thing myself for an elephant entity I made where I wanted it to rear up when attacked. The solution is you need to send a custom packet to sync the client. You can see my elephant model processing the state in this Youtube video (near the end you can see the Elephant gets attacked by the tiger and rears up). Check it out here: If you want to see how I used packets for the elephant model state sync, see my tutorial (still sort of draft but should be useful to you) here: http://jabelarminecraft.blogspot.com/p/packet-handling-for-minecraft-forge-172.html I have other tips about doing entity animations here: http://jabelarminecraft.blogspot.com/p/complex-entity-models-including.html You can also use other packet systems, or the dataWatcher to do this. But my way seems to work well. Anyway, my point is that I suspect the problem is your state isn't detected by the entity on the client because it is being updated on the server side and not being synced.
  3. What do you mean by "valid"? You mean you can't find it in the code source, or you mean you never see it triggered if you subscribe to it?
  4. In that tutorial it is done in the initialise() method in the PacketPipeline class. I think your issue is that you can't see the io.netty from your dev environment. I'm not sure how to fix that but otherwise just follow the tutorial.
  5. Netty is already built in. So all you have to do is register a channel for your mod, create a class for the packet creation and create a "handler" class to process the received packets. The packets have a payload that isbadically a ByteBuf that allows you to create a stream of information. It is up to you what information you put in, but typical example would be custom fields for an entity. What part of the tutorial are you having trouble with? I think the main confusion is that there are several ways to do it so the tutorials aren't all the same.
  6. While diesenben's comments are often terse you shouldn't take them as being on a high horse or belittling. He spends time to correct a lot of us, and being corrected can feel like being criticized but diesenben is usually right on the mark with his comments. Confusion about ==, .equals() and instanceof is a failure to understand basic java. (I'm also new to Java and have similar failures all the time, for example I'm always trying to compare strings with == which is a no-no). You can see that GoToLink (another highly respected commenter here) suggested .equals() and diesenben even had improvement over that in understanding the performance impact of instanceof. I would treat diesenben like a tough martial arts instructor. Just the fact that he is commenting on your thread shows that he cares about you and his comments have a point you should consider carefully. It's tough love.
  7. That's a really useful tip actually. I can see a lot of uses of non-updating (or selectively updating) tile entities.
  8. Thanks diesieben, I appreciate the time you take to write up these detailed clarifications.
  9. First of all, what version of Forge are you trying to mod? Even that wiki page you linked to said it won't work as written for 1.7.2... Secondly, what are you actually trying to do that requires access transformer?
  10. Obfuscation means that it isn't easy for human to read it. So yes the JAR contains Java code but if it is obfuscated there won't be any nice comments or formatting, and all the field and method names will be changed to something that doesn't make obvious sense. If you have a method called initializeMyBlock() when it is obfuscated it might be called m23438_b(). That is generally what obfuscation means. Specifically for Minecraft modding the issue is that mods will call vanilla code and Minecraft vanilla code is normally obfuscated. In Forge environment, thanks to the work of MCP, we can call vanilla methods with names that make sense (e.g. worldObj.isRemote), but in actual Minecraft it needs to call the obfuscated method (e.g. f2434356_b.f243435_b). So basically the mod will work in the Forge environment if it is calling the vanilla methods based on their deobfuscated names. At least that is how I understand it. I'm a noob too...
  11. The bounding box would also properly affect the mob's path, but unfortunately it would also affect every other mob and the player -- you player couldn't cross it either. Like Delpi says, it really depends on how you want the mob to behave when blocked with this block. To really do it "properly" you'd want the mob to be able to figure out a way around it if the path exists, so in that case you would just create your own AI tasks (could copy the vanilla ones) that call custom path finding (you'd copy the vanilla path finding but treat your blocks like having lava or water in the way). Then to block the mob you'd have to place enough of your blocks to truly block their path. Alternatively, if you don't mind the mob sort of getting "stuck" (i.e. they'll keep trying to cross but get knocked back) when it tries to cross your block then there are several ways to do it. One simple way is you can check if the mob is over top of your block and then simply set the position of the mob to its previous position (entities have previous X, Y, Z coordinates stored in fields).
  12. I understand that the entity is spawned on both sides, on server and then that causes spawn on client. But it seems weird to me that the entity spawned is on the opposite side as the worldObj passed to it. I mean right in the same constructor if you query whether the world object parameter is remote and compare that with whether the entity. Actually, I also tried comparing this.worldObj.isRemote and this.isClientWorld() and they return opposite values! These methods come from vanilla EntityLivingBase: /** * Returns whether the entity is in a local (client) world */ public boolean isClientWorld() { return !this.worldObj.isRemote; } Is my mind just fried, but isn't that backwards? I thought isRemote meant a client world, but the vanilla method says the opposite. Anyway, that is where my code has gone wrong -- I was using both interchangeably. Solution: The isClientWorld() method seems to have logic backwards -- don't use it. Only use worldObj.isRemote to test entity side.
  13. [Edited] In the course of trying to better understand which side different code runs on, I've been putting in prints to console to try to trace it. I got a weird result I'm trying to understand. Probably simple, but in the constructor of my entity I print out what side it is on and what side the world parameter passed to it is. In the game when the entity is created as expected I see the constructors on both sides, but the weird thing is the entity is on different side than the world passed to it. I'm probably just doing something dumb, but can you see what it is? The console output: The entity's constructor is: public EntityHerdAnimal(World par1World) { super(par1World); // DEBUG System.out.println("EntityHerdAnimal constructor(), entity.isClientWorld() = "+this.isClientWorld()+", par1World.isRemote = "+par1World.isRemote); setSize(0.9F, 1.3F); getNavigator().setAvoidsWater(true); tasks.addTask(0, new EntityAISwimming(this)); tasks.addTask(1, new EntityAIPanicHerdAnimal(this)); // the leap and the collide together form an actual attack tasks.addTask(2, new EntityAILeapAtTarget(this, 0.4F)); tasks.addTask(3, new EntityAIAttackOnCollide(this, 1.0D, true)); tasks.addTask(5, new EntityAIMate(this, 1.0D)); tasks.addTask(6, new EntityAITempt(this, 1.25D, Items.wheat, false)); tasks.addTask(7, new EntityAIFollowParent(this, 1.25D)); tasks.addTask(8, new EntityAIWander(this, 1.0D)); tasks.addTask(9, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F)); tasks.addTask(10, new EntityAILookIdle(this)); targetTasks.addTask(4, new EntityAIHurtByTargetHerdAnimal(this, true)); // needs to have lower priority than panic (which does rearing) } Is this expected? I thought the world parameter gets passed to the worldObj which is then queried for the isClientWorld() which should be equivalent to worldObj.isRemote ...
  14. As SanAndreas said using that method there is a limit of 256 including all vanilla mods and including all other mods. If you want to confirm that you've used up the amount you can print out the global ID as they are registered.
  15. By the way, since the thread started with question about my packet handling system, the solution was there was some missing @SideOnly annotation in the Packet class. In any case, both methods are very similar.
  16. Yeah, the problem is the way it checks if it is a fence. If it had checked the class using isMemberOf then your blocks would be considered fences, but since it is checking specifically against the registered instance then yeah that won't work.
  17. What does the crash report say? If there was a cap in the coding then it probably would "fail gracefully" meaning it just wouldn't spawn or something, it shouldn't crash. I suspect that it is some other problem. It may be "capped" by memory available or something. But let's see the crash report.
  18. Firstly, if your fence classes extend the vanilla fence class then the vanilla fence class will consider them fences. Secondly, if there is a cancellable event at the time of interest you can intercept it by subscribing to it and doing your own processing. Like maybe when player places a block you could intercept it. Thirdly you can replace the vanilla block with your own that extends the vanilla block but overrides the methods you want to customize. You can do the replacement by maybe changing the crafting recipe for the fence to output yours instead, or you can look for any instances of fence and simply replace them with yours, and so forth. Not necessarily elegant but possible.
  19. You're not really approaching the problem the right way. You normally don't add and remove the AI task, rather you always have the task on the list but you use the shouldExecute() method in the AI class to determine whether it should in fact execute. So the hasBombed would be checked in the shouldExecute(). Also, the priority and the mutexBits() settings are important to avoid conflicting AI. I posted this elsewhere, but the mutexBits() are set in each AI to help indicate which other AI tasks should not execute concurrently. It turns out that most movement AI is mutexBits set to 1, so I would set the same to yours. Otherwise the entity may choose to wander in the middle of running away! Next, the task number indicates the priority (sort of) with lower numbers going first. So I would put yours at a fairly high priority (low number) on the list to ensure it is checked early and then once it starts executing it will prevent lower priority movement AI from executing. Anway, the main point is if you have a Boolean controlling the AI, you should use it in the shouldExecute() method not to add the AI to the list.
  20. Actually I understand it now. I guess that Java is going to process any imports needed for any methods in the class, whether or not they might actually be called during execution. So the import of the World class was causing trouble. I thought Java would only look at the import if it needed it (i.e. when method was called) during execution, but it actually makes more sense that it would look at it in advance so it would be able to execute the method if called. I still think the error report should indicate the actual error (i.e. the import line in the PacketWildAnimals class) rather than the line that calls the class. Definitely solved.
  21. Well, I added some SideOnly annotation in the PacketWildAnimals and it fixed the problem. I have to say I don't quite understand it -- if it was calling a method before on wrong side, wouldn't the SideOnly also cause failure because then there wouldn't be any method present at all? In any case, I'll consider this solved. Here is the revised PacketWildAnimals class: 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.entity.player.EntityPlayer; 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; import cpw.mods.fml.relauncher.SideOnly; // 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 final static int packetTypeIDC2STest = 2; public PacketWildAnimals() { // don't need anything here } // ***************************************** // Server To Client Packet Creation // ***************************************** @SideOnly(Side.SERVER) 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; } // ***************************************** // Client to Server Packet Creation // ***************************************** @SideOnly(Side.CLIENT) public static FMLProxyPacket createClientToServerTestPacket(EntityPlayer parPlayer, int parTestValue) throws IOException { if (parPlayer.getEntityWorld().isRemote) { // DEBUG System.out.println("Sending PacketWildAnimals on Client Side"); ByteBufOutputStream bbos = new ByteBufOutputStream(Unpooled.buffer()); // create payload by writing to data stream // first identity packet type bbos.writeInt(packetTypeIDC2STest); // write entity instance id (not the class registry id!) bbos.writeInt(parTestValue); // 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; } else { return null; } } // ***************************************** // Received By Client Packet Processing // ***************************************** @SideOnly(Side.CLIENT) public static void processPacketOnClient(ByteBuf parBB, Side parSide) throws IOException { if (parSide == Side.CLIENT) // packet received on client side { // 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 if (foundEntity != null) { System.out.println("Entity Class Name = "+foundEntity.getClass().getSimpleName()); } else { System.out.println("Entity Class Name = null"); } // 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(); } } // ***************************************** // Received By Server Packet Processing // ***************************************** @SideOnly(Side.SERVER) public static void processPacketOnServer(ByteBuf parBB, Side parSide, EntityPlayer parPlayer) throws IOException { if (parSide == Side.SERVER) // packet received on server side { // DEBUG System.out.println("Received PacketWildAnimals on Server Side from Player = "+parPlayer.getEntityId()); ByteBufInputStream bbis = new ByteBufInputStream(parBB); // process data stream // first read packet type int packetTypeID = bbis.readInt(); // DEBUG System.out.println("Packet type ID = "+packetTypeID); switch (packetTypeID) { case packetTypeIDC2STest: { // DEBUG System.out.println("Test packet received"); int testVal = bbis.readInt(); // DEBUG System.out.println("Test payload value = "+testVal); break ; } } // don't forget to close stream to avoid memory leak bbis.close(); } } // 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; } }
  22. Okay, I admit it seems like some sort of side annotation issue. However, I'm still a little perplexed for two reasons: 1) the error report doesn't call out any of my classes as the missing problematic class. 2) I don't use the SideOnly annotation much except for the traditional proxy stuff and all my packet handling is in common proxy. Here is my PacketWildAnimals class, which doesn't have any side annotations so should be available on both sides: And here is my CommonProxy, where all the networking stuff is: And here is my main class which does fairly traditional use of proxy: But I'll keep crawling through it. I guess I'll add some side only annotations and see if it complains unexpectedly so I can figure out where the failure in my logic is.
  23. It is the client. Server can't access it. Okay, but that line (474 in HerdAnimals class) is after checking that you're on server side (the problem line is the sendToAll() inside the try): public void sendSyncPacket() { if (!this.worldObj.isRemote) { try { WildAnimals.channel.sendToAll(PacketWildAnimals.createEntityPacket(this)); } catch (IOException e) { e.printStackTrace(); } } } And the sendToAll() method is a vanilla server side method: /** * Send a packet to all on the server * * @param pkt */ public void sendToAll(FMLProxyPacket pkt) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL); channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); } So I'm using the vanilla Entity worldObj field (which should exist on both sides right? I also tried the isClientWorld() method still failed), checking to ensure I'm on server side and calling a server side method. So why do I get a "no class def error" on server side? One other thing to mention -- the same code seems to work fine in single player. I still call sendAll() but of course there is only one client. So it that kinda seems like a @Side kind of thing, but I'm not using that annotation and the neither does the FMLEventChannel class.
  24. I know that the actual problem is that the config file directory was in wrong place, so I know how to fix that. And I know that the Configuration class will create a file if it doesn't find one (I think that is bad programming practice, but whatever). But I was curious because my check for whether the file existed seem to pass when I'm pretty sure there wasn't such a file, and the check for the file comes before the Configuration is created. It's okay, I can fix the actual problem. I just like to understand when I find something unexpected.
  25. In the course of trying to send a packet in multiplayer mode, while running in dev environment, I get the following error related to a vanilla class. Minecraft otherwise seems to be working, so it's not like the class paths are totally hosed. Any ideas? I can't imagine that I created the problem as I don't touch this class, it is still present in the code, and I reinstalled Forge just to make sure. [13:59:45] [server thread/ERROR] [net.minecraft.server.MinecraftServer]: Encountered an unexpected exception java.lang.NoClassDefFoundError: net/minecraft/client/multiplayer/WorldClient at wildanimals.entities.herdanimals.EntityHerdAnimal.sendSyncPacket(EntityHerdAnimal.java:474) ~[EntityHerdAnimal.class:?] at wildanimals.entities.herdanimals.EntityHerdAnimal.setRearing(EntityHerdAnimal.java:417) ~[EntityHerdAnimal.class:?] at wildanimals.entities.herdanimals.EntityHerdAnimal.attackEntityFrom(EntityHerdAnimal.java:292) ~[EntityHerdAnimal.class:?] at net.minecraft.entity.player.EntityPlayer.attackTargetEntityWithCurrentItem(EntityPlayer.java:1401) ~[EntityPlayer.class:?] at net.minecraft.network.NetHandlerPlayServer.processUseEntity(NetHandlerPlayServer.java:873) ~[NetHandlerPlayServer.class:?] at net.minecraft.network.play.client.C02PacketUseEntity.processPacket(C02PacketUseEntity.java:51) ~[C02PacketUseEntity.class:?] at net.minecraft.network.play.client.C02PacketUseEntity.processPacket(C02PacketUseEntity.java:69) ~[C02PacketUseEntity.class:?] at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:232) ~[NetworkManager.class:?] at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) ~[NetworkSystem.class:?] at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:720) ~[MinecraftServer.class:?] at net.minecraft.server.dedicated.DedicatedServer.updateTimeLightAndEntities(DedicatedServer.java:341) ~[DedicatedServer.class:?] at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:608) ~[MinecraftServer.class:?] at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:482) [MinecraftServer.class:?] at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:746) [MinecraftServer$2.class:?] Caused by: java.lang.ClassNotFoundException: net.minecraft.client.multiplayer.WorldClient at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:188) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[?:1.7.0_51] at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ~[?:1.7.0_51] ... 14 more Caused by: java.lang.RuntimeException: Attempted to load class net/minecraft/client/multiplayer/WorldClient for invalid side SERVER at cpw.mods.fml.common.asm.transformers.SideTransformer.transform(SideTransformer.java:50) ~[forgeSrc-1.7.2-10.12.1.1071.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.runTransformers(LaunchClassLoader.java:276) ~[launchwrapper-1.9.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:174) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[?:1.7.0_51] at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ~[?:1.7.0_51]
×
×
  • Create New...

Important Information

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