
gff1979
Members-
Posts
19 -
Joined
-
Last visited
Everything posted by gff1979
-
[Not solved but im done.]How to save integers to a file.
gff1979 replied to deadrecon98's topic in Modder Support
I also am not being rude, but you should never accuse anyone of being rude when asking for help through a text means... that is actually rude in itself, but forgivable as it is frustrating getting something to work. If you cannot be bothered reading other peoples code then no one will want to help you... I don't think that's what you meant at all but if you are seriously considering modding, then you'll need to read a lot of other peoples code, and it will sometimes be very long and complex but should be well documented with comments. This API is not official and it's very obscured still. I understand your need to learn to gain the satisfaction of progress however, as you probably know, we all cannot help as much as we might like as we are working on projects, feeding family, working, and doing other things important to our own progress. Keep that in mind first and foremost when asking a question. Also, give a very good indication of your current skills, knowledge, and exactly what it is you want to achieve in your code. Saving an int to a file is generic. It would help to know what the purpose of doing so is and think how that feature may evolve later. It's good to want to get better but I'd have to know a lot more about your current knowledge of java and forge to help teach you something. Have you done all of the Basic tutorials? http://www.minecraftforge.net/wiki/Tutorials. Indispensable. If it becomes frustrating to follow just keep trying. You can teach yourself anything if you apply yourself and do not allow frustration to set in. I have a feeling if you have a decent enough base knowledge of java that following the basic tutorials will allow you to intuitively discover your solutions for quite sometime. I do understand the frustration that can come if you are just getting into things as a new coder. I guess the idea is that if someone does it for you you won't learn anything, but no one should have a problem if you don't understand a particular class, in giving you some ideas or help. If you are simply wanting persistent data that saves and loads on a save game, you should grok the classes for NBTTagCompounds. This is how Vanilla saves most of it's persistent/unique data when the game saves. If you have something else in mind that minecraft doesn't already do then you may need your own data file system... however I doubt it would be necessary. It does require knowledge of java's file input/output classes. If you don't understand them, I suggest you try a basic java app first then play with the classes. If your knowledge of java is up to snuff then I'd master all the knowledge gained from the Basic Tutorials then amaze yourself at how much can be learned with a bit of patience and persistence. Also, let the vanilla source guide you. ctrl+H in eclipse will let you search for text in all the packages open in your project. It's probably done me more good than the tutorials... Update: I just remembered something important. I understand that you are making a SSP mod. It is important to understand that a client and server are running even in SSP. Not much gets sent to the Client but rendering data. Even the levels, skills, other info would be on the server and the server value would be passed to the client either through a datawatcher or packet. I think the concept works best mentally if you say that the client cannot be trusted. The server is the master in this case and does all the saving of data. It's probably less intuitive but things got easier for me when dealing with Server/Client relations when I thought of it that way. But that could just be me. -
The basic tutorials cover the different Registries. They are basically how the game organizes resources... but seriously do the beginner tutorials and all will become clear. http://www.minecraftforge.net/wiki/Tutorials
-
Function problem-- Screwed up the datawatcher, or lack of a packet?(SOLVED)
gff1979 replied to Cyan's topic in Modder Support
Forget anything I said about maybe setting data to a field, this is probably where you are stuck. (btw,y ou should only need a set/getEXP method and calc your level from that return, or at least don't save both ), Anytime you want to get/setEXP it HAS to use the methods, you cannot save them to a variable anywhere and expect to reference it later. What I see is that you are still not implementing it correctly. I don't see the Init method in the Entity, this is probably the best place to create your datawatchers and put them right next to each other for easy reference... not scattered about. Something like nbt.setDouble("homeX", home.X); will do you no good what so ever. It puts something in the NBT and will read it to a field but it won't write it to the client at all. I'll use only the EXP method but you'll do the same for any persistant data sent from the Server. *Make a get and set methods to set the datawatchers value you initiated in the entityInit() method. It's a method in the Entity class, you don't need it but it's a good place to stick stuff after the constructor fires. * the setEXP( int exp) method has one line: this.dataWatcher.updateObject(20, Integer.valueOf(exp)); *the getEXP() method has one line: return this.dataWatcher.getWatchableObjectInt(20); - Notice how they don't reference any data but the watcher? This is important as we can't trust the client for anything... ever... it's a bad naughty client! It's fields are dirty and must be ignored and made to sit in the corner! !!!Never call your setEXP method ( or rather a write or update on a watcher) outside of the writeToNBT!!! That usually causes wonkyness and a struggle by the Server and Client to see who gets to set the data. !!!NBT is done only Server side!!! *Use something like nbt.setInt("exp", this.getEXP()); in the writeToNBT *Use something like this.setEXP(nbt.getInt("exp"); inside the readToNBT to make sure the system reads the NBT back into the watcher. You will not be using fields unless you come up with some safe way to update them client side (if you ABSOLUTELY had to THIS is what packets are good for), you'll just be using Entity.getEXP() the method to get the values. I think I can safely say that if you wanted to use packets... they use up a lot more code. Also, you cannot use arrays in watchers(I sure as ssssss can't get them to see array Objects), but you can use strings, and strings are practically byte arrays or even data arrays if you use string indexing and offsets. Just a hint for advanced usage when you get there. Use more // and descriptions too. It might be easier to find things in your code for people to help you out with. It's kinda hard to find stuff with no documented code. I don't see the implementation class of your abstract class so I don't know if there would be anything causing problems there but the way the abstract class is written the implementation wouldn't work. Just an update: When I say never call the setEXP method outside... I should clarify that you may call it to set the data inside the class, but it's probably not as safe to do so in something like the render or model of your entity. I think that's the best way to put it... Also: should be *the getEXP() method has one line: return this.dataWatcher.getWatchableObjectInt(20); -
Looking for a modder to help make mod, will pay up to 100$
gff1979 replied to gabinthal's topic in Modder Support
Just a thought: There is a donation button for MCForge. I think that would be a good place to put that $100... -
Got it to work with a little something like this in my Model class public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { super.render(entity, f, f1, f2, f3, f4, f5); setRotationAngles(f, f1, f2, f3, f4, f5, entity); EntityGal gal = (EntityGal)entity; renderLayeredPart(head, f5, gal.getTexArray()); renderLayeredPart(neck, f5, gal.getTexArray()); renderLayeredPart(rightarm, f5, gal.getTexArray()); renderLayeredPart(leftarm, f5, gal.getTexArray()); renderLayeredPart(chest, f5, gal.getTexArray()); renderLayeredPart(rightleg, f5, gal.getTexArray()); renderLayeredPart(leftleg, f5, gal.getTexArray()); renderLayeredPart(waist, f5, gal.getTexArray()); renderLayeredPart(hips, f5, gal.getTexArray()); renderLayeredPart(rightboob, f5, gal.getTexArray()); renderLayeredPart(leftboob, f5, gal.getTexArray()); renderLayeredPart(shirtgap, f5, gal.getTexArray()); renderLayeredPart(head, f5, gal.getTexArray()); } public void renderLayeredPart( ModelRenderer part, float f5, String[] texArray ) { int index = 0; while (index < texArray.length) { FMLClientHandler.instance().getClient().renderEngine.bindTexture(texArray[index]); part.render(f5); index++; } } the getTextureArray just returns a private string array in my EntityGal. My hypothesis is that the renderer makes interference or glitchy/clipping stuff if you try to set the textures to the whole mesh. It's far too slow and you get weird lines. This way I set each texture layer to an individual part one at a time and I don't get the weirdness. It was much easier than I thought but at least I learned a ton of GL stuff that I didn't need and how to load wavefront objects. All in all a great learning experience! Thanks for your help guys! BTW I tried with 4 layers and a couple of hundred of them and the fps did drop from 60 to 30... But that's probably with 40 or 50 times more of them than I'll be using in my mod. Now I just have to add some dynamic stuff and incorporate it into the player class as well as the character creation.
-
Function problem-- Screwed up the datawatcher, or lack of a packet?(SOLVED)
gff1979 replied to Cyan's topic in Modder Support
I wasn't saying use a packet for EVERYTHING, I was saying that I use a packet to update the client from its "dumb" stage to a slightly knowledgable level so that the client displays correct data. I am not entirely sure about datawatchers and if they update the client or not... I didn't think you did say that mate, sorry you thought I meant something by it. It's all good. Yeah data watchers update in my example. It's kinda-sorta like a pointer... the trick is declaring it in the Init so that you kinda have that pointer to the client and having the NBT read/write do the work server side. you can either call the Entity.getValue() function or set the getValue() to a field in it if you'd rather not have to keep calling the getValue() method to retrieve persistent data. Also, this is exactly how vanilla does it. -
I have blocks that I "render twice" in order to get an overlay. Icon camo = Block.blocksList[wid].getIcon(l, meta); //meta for the block's facing so that it grabs the icon of the face of the block that it is attached to renderer.renderBlockUsingTexture(Block.blocksList[wid], x, y, z, camo); //render the original block at an offset location renderer.renderBlockUsingTexture(Block.stone, x, y, z, block.getIcon(0, 0)); //render my overlay in the same location The same could be done for entities, but you'd have to rewrite their renderers. I've got multiple textures to work but I still get that odd fuzzy glitchy clipping thing that leads me to believe I'm not only rendering a second texture but a second model as well. I'm not sure where the textures are rendered to models... also I'm attaching other geometry so I gather I'll need to write something beyond just a simple custom usage of .setRenderPassModel and .shouldRenderPass. I tried futzing with these and I can never get more than one extra texture and one extra mesh to render. I'm looking into the .client.renderer package. It's lengthy but has fairly good documentation ... I probably have my work cut out for me. Update: I think I'll extend the RenderLiving class and try to implement multi-texturing like I would in openGL/C++ then see if I can pass the texture through by overloading the loadTexture method. That's where it seems to invoke the renderManagers use of glBindTexture. ... Nope... didn't work.
-
Function problem-- Screwed up the datawatcher, or lack of a packet?(SOLVED)
gff1979 replied to Cyan's topic in Modder Support
Have you looked at http://www.minecraftforge.net/wiki/Packet_Handling? I still think datawatcher is a superior means, you are just confused on how to use them like I was. Here's all I went through so far... maybe it'll be of assistance: If you are using Eclipse and have a solid understanding of Java, the magical groking tool is Ctrl+H. you can search for already existing methods in the mods, minecraft, and minecraftforge packages. It will highlight the search term in each java file it finds as well as make little boxes on the right hand side next to the scroll bar, showing you exactly where in the source the words appear in the open java file. Also, ctrl+F is the find type search it does the same but for the open java file. In an open java file you can click the mouse cursor over a single word, like a class name, field, or method it will highlight each instance of that word in the open .java file just like when you use the ctrl+H. Also, know java intimately... or at least as well as a good friend. I'm not making any assumptions on anyone's skills but it's detrimental. That said, use those techniques to look at the EntityPlayer.java file. It may help you get a method that works for you better as you'll have an good understanding. This is a simplified break down of using datawatchers with the Entity NBT read/write methods. It's written with the intent to be a tutorial so don't take it personally if you already know it all. Otherwise, pay attention to the comments I made in it for usage and tips. Feel free to ask about anything but I want you to work hard on your own with this. Even if it takes you days to get something you'll learn so much more on your own getting in touch with the source on a personal level. Zen Programming. package yourname.yourmod.client.renderer.entity; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityThingy extends Entity// Replace Entity with the parent class you are extending your Entity from. // I did this to make sure you are paying attention to my commented lines! // This is not needed but allows you to access the data with this.persistantValue // though you can use the getValue method to the same ends. public int aValue; // the data you wish to save. public EntityThingy(World par1World) { super(par1World); this.setValue(42); // again this isn't really needed as the this.getValue() method will return the value // but I used it in my example. this.aValue = this.getValue(); } public void entityInit() { // note: you cannot do this super with Entity as the parent class // as it's an abstract class with no constructor. However, if you // use a non abstract entity to base your own on, make sure you use // super to invoke the original entityInit. // Again: just making sure you are reading these and not in hypergleen mode. super.entityInit(); // Create a data watcher for the value this.dataWatcher.addObject(20, Integer.valueOf(0)); // the 20 is the id... it cannot use a value the parent class // you are extending from uses. // In this example the Entity class already has a data watcher, access through this.datawatcher. // It uses 0 and 1... so don't use them... //the maximum id is 31... use // it wisely. } // only call a get/set method for any data you need in read/writeEntityToNBT // or maybe where isRemote is false and if you know where/when you need it!!! // This is where most confusion from datawatchers comes from in my experience. public void setValue(int value) { this.dataWatcher.updateObject(20, Integer.valueOf(value)); } public int getValue() { return this.dataWatcher.getWatchableObjectInt(20); } // Here are the parts that make it work. Note all the work is being done in the NBT reader/writer method. // This is important as they only work from the Server, they don't fire from the Client. That would cause // an exception to be thrown in the data watcher // writes persistent values that is saved to the world server side // Again, due to the fact that Entity is abstract, it cannot be supered // so make sure you use the class you need in your own EntityThingy... or whatever you call it. public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("Value", this.getValue()); } // reads a persistant value from the server's world public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.setValue(nbt.getInteger("Value")); } } I hope this serves as a solid, simple, and good example. You'll have to come up with the personal implementation of course. -
lol, I tend to go OCD over a few lost FPS so I'm just over exaggerating I imagine. Though we are talking more than 24 verts, between 60 and 100 depending on the attachments and at some point there may be as many of these as there are Villagers in a village... but I've spawned a few hundred of them thus far and they seem to work just fine. I'm not very much closer to my goal but it's still a learning process for me...
-
Function problem-- Screwed up the datawatcher, or lack of a packet?(SOLVED)
gff1979 replied to Cyan's topic in Modder Support
I'm new here so forgive me if I'm wrong, but the guidlines for SMP modding suggests datawatchers over packets. I was under the impression that using datawatchers was the best way when dealing with NBT persistent data. Perhaps the guidelines are out of date. Is the DataWatcher class being depreciated in favor of packets? http://www.minecraftforge.net/wiki/SMP_Coding_Guidelines -
Casting in a nutshell: String sNumber = (String)number; would cast the int number to a string object called sNumber; so probably ... player = (EntityPlayerMP)player; ... this might work but I'm unfamiliar with the relationship between Player and EntityPlayerMP. (you shouldn't cast anything in a nutshell, it's a tight space and you could hurt someone...)
-
There are a few methods to sync them. My example uses datawatchers. If you are familiar with java you should be able to grok with my example.
-
Function problem-- Screwed up the datawatcher, or lack of a packet?(SOLVED)
gff1979 replied to Cyan's topic in Modder Support
You are stuck where I was. It works best when you use the dataWatcher inside the nbt methods. This is how I fixed the situation: package gff.companime.entity.companions; import java.util.Random; import gff.companime.Companime; import net.minecraft.client.Minecraft; import net.minecraft.entity.DataWatcher; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIFollowGolem; import net.minecraft.entity.ai.EntityAILookAtTradePlayer; import net.minecraft.entity.ai.EntityAIMoveIndoors; import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction; import net.minecraft.entity.ai.EntityAIOpenDoor; import net.minecraft.entity.ai.EntityAIPlay; import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAITempt; import net.minecraft.entity.ai.EntityAITradePlayer; import net.minecraft.entity.ai.EntityAIVillagerMate; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.ai.EntityAIWatchClosest2; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityGal extends EntityAgeable { public int haircolor; public EntityGal(World par1World) { super(par1World); this.texture = "/textures/mob/gal/gal.png"; this.moveSpeed = 0.5F; this.setSize(0.6F, 1.8F); this.getNavigator().setBreakDoors(true); this.getNavigator().setAvoidsWater(true); // AI tasks for the entity to perform this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false)); this.tasks.addTask(2, new EntityAIMoveIndoors(this)); this.tasks.addTask(3, new EntityAIOpenDoor(this, true)); this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F)); this.tasks.addTask(5, new EntityAIWander(this, 0.3F)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F)); // Generate instance specific data Random rnd = new Random(); this.setHairColor(rnd.nextInt(0xffffff)); this.haircolor = this.getHairColor(); } public void entityInit() { super.entityInit(); // Create a data watcher for hair color this.dataWatcher.addObject(20, Integer.valueOf(0)); } // writes persistent values that is saved to the world server side public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("haircolor", this.getHairColor()); } // reads a persistant value from the server's world public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.setHairColor(nbt.getInteger("haircolor")); } // This function will set an RGB color // It is called later with EntityGal.getHairColor() in the renderer public void setHairColor(int color) { this.dataWatcher.updateObject(20, Integer.valueOf(color)); } // Returns the value set by setHairColor as "haircolor" in the Entities NBTTagCompound public int getHairColor() { return this.dataWatcher.getWatchableObjectInt(20); } @Override public EntityAgeable createChild(EntityAgeable entityageable) { // TODO Auto-generated method stub return null; } @Override public int getMaxHealth() { // TODO Auto-generated method stub return 10; } public boolean interact(EntityPlayer par1EntityPlayer) { ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem(); System.out.println(this.worldObj); System.out.println("ID: "+this.entityId); System.out.println("isRemote = "+this.worldObj.isRemote); System.out.println(this.haircolor); // Example of how to get this entity haircolor return true; } } -
I'm not an expert on NBT usage, but the only way I've ever used it to save Entity specific data is within the entities class methods read/writeEntityToNBT( nbt ). Also, it doesn't work on the client side. Forgive me if you understood this already, but in my example I use it like this in the class that stands for the entity's data you wish to save and recall. I have updated it to show the full code of the Entity: package gff.companime.entity.companions; import java.util.Random; import gff.companime.Companime; import net.minecraft.client.Minecraft; import net.minecraft.entity.DataWatcher; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIFollowGolem; import net.minecraft.entity.ai.EntityAILookAtTradePlayer; import net.minecraft.entity.ai.EntityAIMoveIndoors; import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction; import net.minecraft.entity.ai.EntityAIOpenDoor; import net.minecraft.entity.ai.EntityAIPlay; import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAITempt; import net.minecraft.entity.ai.EntityAITradePlayer; import net.minecraft.entity.ai.EntityAIVillagerMate; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.ai.EntityAIWatchClosest2; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityGal extends EntityAgeable { public int haircolor; public EntityGal(World par1World) { super(par1World); this.texture = "/textures/mob/gal/gal.png"; this.moveSpeed = 0.5F; this.setSize(0.6F, 1.8F); this.getNavigator().setBreakDoors(true); this.getNavigator().setAvoidsWater(true); // AI tasks for the entity to perform this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false)); this.tasks.addTask(2, new EntityAIMoveIndoors(this)); this.tasks.addTask(3, new EntityAIOpenDoor(this, true)); this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F)); this.tasks.addTask(5, new EntityAIWander(this, 0.3F)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F)); // Generate instance specific data Random rnd = new Random(); this.setHairColor(rnd.nextInt(0xffffff)); this.haircolor = this.getHairColor(); } public void entityInit() { super.entityInit(); // Create a data watcher for hair color this.dataWatcher.addObject(20, Integer.valueOf(0)); } // writes persistent values that is saved to the world server side public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("haircolor", this.getHairColor()); } // reads a persistant value from the server's world public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.setHairColor(nbt.getInteger("haircolor")); } // This function will set an RGB color // It is called later with EntityGal.getHairColor() in the renderer public void setHairColor(int color) { this.dataWatcher.updateObject(20, Integer.valueOf(color)); } // Returns the value set by setHairColor as "haircolor" in the Entities NBTTagCompound public int getHairColor() { return this.dataWatcher.getWatchableObjectInt(20); } @Override public EntityAgeable createChild(EntityAgeable entityageable) { // TODO Auto-generated method stub return null; } @Override public int getMaxHealth() { // TODO Auto-generated method stub return 10; } public boolean interact(EntityPlayer par1EntityPlayer) { ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem(); System.out.println(this.worldObj); System.out.println("ID: "+this.entityId); System.out.println("isRemote = "+this.worldObj.isRemote); System.out.println(this.haircolor); // Example of how to get this entity haircolor return true; } }
-
Thanks for the help. I have a working implementation and just to help anyone here's the simplified version of my EntityGal implementation. package gff.companime.entity.companions; import java.util.Random; import gff.companime.Companime; import net.minecraft.client.Minecraft; import net.minecraft.entity.DataWatcher; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIFollowGolem; import net.minecraft.entity.ai.EntityAILookAtTradePlayer; import net.minecraft.entity.ai.EntityAIMoveIndoors; import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction; import net.minecraft.entity.ai.EntityAIOpenDoor; import net.minecraft.entity.ai.EntityAIPlay; import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAITempt; import net.minecraft.entity.ai.EntityAITradePlayer; import net.minecraft.entity.ai.EntityAIVillagerMate; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.ai.EntityAIWatchClosest2; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityGal extends EntityAgeable { public int haircolor; public EntityGal(World par1World) { super(par1World); this.texture = "/textures/mob/gal/gal.png"; this.moveSpeed = 0.5F; this.setSize(0.6F, 1.8F); this.getNavigator().setBreakDoors(true); this.getNavigator().setAvoidsWater(true); // AI tasks for the entity to perform this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false)); this.tasks.addTask(2, new EntityAIMoveIndoors(this)); this.tasks.addTask(3, new EntityAIOpenDoor(this, true)); this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F)); this.tasks.addTask(5, new EntityAIWander(this, 0.3F)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F)); // Generate instance specific data Random rnd = new Random(); this.setHairColor(rnd.nextInt(0xffffff)); this.haircolor = this.getHairColor(); } public void entityInit() { super.entityInit(); // Create a data watcher for hair color this.dataWatcher.addObject(20, Integer.valueOf(0)); } // writes persistent values that is saved to the world server side public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("haircolor", this.getHairColor()); } // reads a persistant value from the server's world public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.setHairColor(nbt.getInteger("haircolor")); } // This function will set an RGB color // It is called later with EntityGal.getHairColor() in the renderer public void setHairColor(int color) { this.dataWatcher.updateObject(20, Integer.valueOf(color)); } // Returns the value set by setHairColor as "haircolor" in the Entities NBTTagCompound public int getHairColor() { return this.dataWatcher.getWatchableObjectInt(20); } @Override public EntityAgeable createChild(EntityAgeable entityageable) { // TODO Auto-generated method stub return null; } @Override public int getMaxHealth() { // TODO Auto-generated method stub return 10; } public boolean interact(EntityPlayer par1EntityPlayer) { ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem(); System.out.println(this.worldObj); System.out.println("ID: "+this.entityId); System.out.println("isRemote = "+this.worldObj.isRemote); System.out.println(this.getHairColor()); // Example of how to get this entity haircolor return true; } } I learned that a DataWatcher instance can only have IDs from 0 to 31 and that if your child class is using the parents instance of datawatcher it shouldn't use any ids from the parent. These throw exceptions. Also, don't write to them from the Client or if isRemote is true. They are made to store from client then update from server so they throw an exception when written/updated clientside. It's a bit of code to have to write a get/set for each persistent parameter if you have more than a handful of them but it works. If I'm missing something or anyone has more advice it would be appreciated.
-
I'm using multi-pass but with the model rendering, which is handy for mesh changing (hair or accessories that extend the geometry). If I can grok how the textures render and stack passes in logical layers... that will probably be easier than what I started last night which was using OpenGL to create one new texture procedurally and then apply that to the models texture. I'd probably need more than two passes though and overhead might become a problem. It seems much easier to implement though and I'd rather just use the native ability to load pre-made textures to model class and then do it again without erasing the previous result, simply use alpha channels in my textures to do the work. Thanks for the ideas.
-
I've been reading up on the DataWatcher class and I think that might do what I need as well, I'll learn each way and decide though. Thank you.
-
I'm writing a mod that creates a mob with visual attributes but I'm having a time figuring out how to save them for persistence with NBTTagCompounds. I think what is happening is that either the server or the client one is not saving nbt data but the other is. I'm also confused at to which is doing what and exactly what data is returned through isRemote. I thought that my server/client proxy class declarations might have been switched but I cannot find where they might be switched at. Do I try and capture the one Entity that's NBT value IS being saved and try to set the one that isn't to that value somehow? If so, what is the best way to do that? package gff.companime.entity.companions; import java.util.Random; import gff.companime.Companime; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIFollowGolem; import net.minecraft.entity.ai.EntityAILookAtTradePlayer; import net.minecraft.entity.ai.EntityAIMoveIndoors; import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction; import net.minecraft.entity.ai.EntityAIOpenDoor; import net.minecraft.entity.ai.EntityAIPlay; import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAITempt; import net.minecraft.entity.ai.EntityAITradePlayer; import net.minecraft.entity.ai.EntityAIVillagerMate; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.ai.EntityAIWatchClosest2; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityGal extends EntityAgeable { public int haircolor; public int eyecolor; public EntityGal(World par1World) { super(par1World); this.texture = "/textures/mob/gal.png"; // this.randomTickDivider = 0; // this.isMating = false; // this.isPlaying = false; this.moveSpeed = 0.5F; this.setSize(0.6F, 1.8F); this.getNavigator().setBreakDoors(true); this.getNavigator().setAvoidsWater(true); this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(1, new EntityAITempt(this, 0.3F, Companime.braceletItem.itemID, false)); this.tasks.addTask(2, new EntityAIMoveIndoors(this)); this.tasks.addTask(3, new EntityAIOpenDoor(this, true)); this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.3F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); this.tasks.addTask(5, new EntityAIWatchClosest2(this, EntityGal.class, 5.0F, 0.02F)); this.tasks.addTask(5, new EntityAIWander(this, 0.3F)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityGal.class, 8.0F)); genFeatures(); } public void genFeatures() { Random rnd = new Random(); this.haircolor = rnd.nextInt(0xFFFFFF); this.eyecolor = rnd.nextInt(0xFFFFFF); } @Override public EntityAgeable createChild(EntityAgeable entityageable) { // TODO Auto-generated method stub return null; } @Override public int getMaxHealth() { // TODO Auto-generated method stub return 10; } public boolean interact(EntityPlayer par1EntityPlayer) { ItemStack itemstack = par1EntityPlayer.inventory.getCurrentItem(); System.out.println(this); System.out.println("ID: "+this.entityId); System.out.println("isRemote = "+this.worldObj.isRemote); System.out.println("Hair color = "+this.haircolor); return true; } // NBT for persisting attributes for this instance of a Gal public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setInteger("haircolor", this.haircolor); } public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); this.haircolor = nbt.getInteger("haircolor"); // call to check for non initialized persistant variables. } } These are the ouputs that my right click does on the Entity: After right clicking the entities in a newly created world: Second Click after exit to menu and restarting the same save: As shown, the second of each entity is saving the data properly and it states that it's the client side world or "New World". The Entities world that isn't saving is MpServer. I'm a bit confused as to what is going on. My assumption is that there are two instances of the entity one for client and one for server. As I said I'm not sure what exactly isRemote returns. Is it true if the entity is on MpServer? Because the documentation in my IDE states that it should return false, yet my entity's println(this) would state otherwise. My Entity Render: (this renders hair color based on the entity.haircolor value, but doesn't seem to use the version that gets saved...) package gff.companime.client.renderer.entity; import java.awt.Color; import org.lwjgl.opengl.GL11; import gff.companime.entity.companions.EntityGal; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.entity.RenderLiving; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.passive.EntitySheep; @SideOnly(Side.CLIENT) public class RenderGal extends RenderLiving { public RenderGal(ModelBase modelGal, ModelBase modelHair, float par2) { super(modelGal, par2); this.setRenderPassModel(modelHair); } protected int setHairColor(EntityGal gal, int par2, float par3) { this.loadTexture("/textures/mob/longhair.png"); Color c = new Color(gal.haircolor); byte red = (byte) c.getRed(); byte green = (byte) c.getGreen(); byte blue = (byte) c.getBlue(); GL11.glColor3b(red,green,blue); return 1; } /** * Queries whether should render the specified pass or not. */ protected int shouldRenderPass(EntityLiving par1EntityLiving, int par2, float par3) { return this.setHairColor((EntityGal)par1EntityLiving, par2, par3); } } My mod class: package gff.companime; //The package your mod is in import java.util.logging.Logger; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.EnumCreatureType; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.Configuration; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.Init; import cpw.mods.fml.common.Mod.Instance; import cpw.mods.fml.common.Mod.PreInit; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.network.NetworkMod; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.registry.EntityRegistry; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.LanguageRegistry; import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler; import cpw.mods.fml.common.SidedProxy; import gff.companime.*; import gff.companime.block.PetrifiedWood; import gff.companime.entity.*; import gff.companime.entity.companions.EntityGal; import gff.companime.entity.companions.EntityGalBase; import gff.companime.item.Bracelet; import gff.companime.server.CommonProxy; @NetworkMod(clientSideRequired=true,serverSideRequired=false, //Whether client side and server side are needed clientPacketHandlerSpec = @SidedPacketHandler(channels = {"NitroMod" }, packetHandler = ClientPacketHandler.class), //For clientside packet handling serverPacketHandlerSpec = @SidedPacketHandler(channels = {"NitroMod" }, packetHandler = ServerPacketHandler.class)) //For serverside packet handling @Mod(modid=Companime.modid,name="Companime",version="0.0.1") public class Companime // Mod class { public static final String modid = "gff_Companime"; // I think this is proper use but I don't fully grok // * Create instances for use in Registration * // Tiles: // blocks: public final static Block petrifiedWood = new PetrifiedWood(500, Material.rock); // Items: public final static Item braceletItem = new Bracelet(500); // Entities: // public final static EntityGal gal = new EntityGal(null); @Instance( modid ) //The instance, this is very important later on public static Companime instance = new Companime(); @SidedProxy(clientSide = "gff.companime.client.ClientProxy", serverSide = "gff.companime.server.CommonProxy") public static CommonProxy proxy; public static Logger logger; // * Methods * @PreInit public void preInit(FMLPreInitializationEvent event) { logger = Logger.getLogger(modid); logger.setParent(FMLLog.getLogger()); Configuration config = new Configuration( event.getSuggestedConfigurationFile()); //Configuration.load(config); } @Init // public void InitCobaltCraft(FMLInitializationEvent event){ //Your main initialization method public void load(FMLInitializationEvent event) { //Your main initialization method NetworkRegistry.instance().registerGuiHandler(this, proxy); //Registers the class that deals with GUI data proxy.registerRenderInformation(); proxy.registerTiles(); proxy.registerBlocks(); proxy.addNames(); proxy.addRecipes(); proxy.addEntities(); // Register entities? proxy.addEntities(); ? // EntityRegistry.registerModEntity(EntityGal.class, "Gal", 2, this, 80, 3, true); // EntityRegistry.addSpawn(EntityGal.class, 5, 2, 6, EnumCreatureType.creature, BiomeGenBase.beach); // LanguageRegistry.instance().addStringLocalization("name.gal.entity", "Gal"); } } ClientProxy: (currently just registers the entity and spawn egg data) package gff.companime.client; import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.registry.EntityRegistry; import gff.companime.*; import gff.companime.client.model.*; import gff.companime.client.renderer.entity.RenderGal; import gff.companime.client.renderer.entity.RenderGalBase; import gff.companime.entity.*; import gff.companime.entity.companions.EntityGal; import gff.companime.entity.companions.EntityGalBase; import gff.companime.server.CommonProxy; import net.minecraftforge.client.MinecraftForgeClient; public class ClientProxy extends CommonProxy { @Override public void registerRenderInformation() { // // Register Models // // Test Gal // RenderingRegistry.registerEntityRenderingHandler(EntityGalBase.class, new RenderGalBase(new ModelGalBase(), new ModelGalBase(), 0.5F)); // EntityRegistry.registerGlobalEntityID(EntityGalBase.class, "TestGal", EntityRegistry.findGlobalUniqueEntityId() , 3515848, 0xFF8020); // Real Gal RenderingRegistry.registerEntityRenderingHandler(EntityGal.class, new RenderGal(new ModelGal(), new ModelLongHair(), 0.5F)); EntityRegistry.registerGlobalEntityID(EntityGal.class, "Gal", EntityRegistry.findGlobalUniqueEntityId() , 0xd4a98a, 0xd4a98a); } } CommonProxy: package gff.companime.server; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EnumCreatureType; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.MinecraftForge; import cpw.mods.fml.common.network.IGuiHandler; import cpw.mods.fml.common.registry.EntityRegistry; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.LanguageRegistry; import gff.companime.*; import gff.companime.item.*; import gff.companime.block.*; import gff.companime.entity.companions.*; public class CommonProxy implements IGuiHandler //THIS IS IMPORTANT, CANNOT BE A PROXY/GUI HANDLER WITHOUT THIS!! { // Methods public void registerRenderInformation() //Client side texture registering { } @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { //For GUI's return null; } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { //For GUI's return null; } public void registerTiles() { //For registering TileEntities } public void registerBlocks() { //For registering Blocks // Petrified Wood Block LanguageRegistry.addName(Companime.petrifiedWood, "Petrified Wood"); MinecraftForge.setBlockHarvestLevel(Companime.petrifiedWood, "axe", 0); } public void addNames() // Change to addItems and handle more than just names soon... { //For adding Item's in game names // Friendship bracelet item LanguageRegistry.addName(Companime.braceletItem, "Friendship Bracelet"); } public void addRecipes() { //For adding your Item's recipes // Friendship Bracelet Recipes ItemStack silkString = new ItemStack(Item.silk); GameRegistry.addRecipe( new ItemStack(Companime.braceletItem) , "xxx", "x x", "xxx", Character.valueOf('x') , silkString); } public void addEntities() { // Gal EntityRegistry.registerModEntity(EntityGal.class, "Gal", 2, Companime.instance, 30, 3, true); EntityRegistry.addSpawn(EntityGal.class, 5, 2, 6, EnumCreatureType.creature, BiomeGenBase.beach); LanguageRegistry.instance().addStringLocalization("name.gal.entity", "Gal"); } } Any help would be appreciated even if it's something simple or relates to something else in the code as I just started learning MCForge this weekend...
-
Is there a direct way to layer multiple textures on a model for say dynamic skin change, clothing, scars, gore, etc? Currently I'm just using a different texture for each thing but I'm also implementing clothing AND dynamic skin, hair, eye colors for NPCs and the number of textures for the base class for armor/clothing/skin alterations is getting exponential and I'd like to be able to place multiple textures with alpha channels over each other to get the effects I'm looking for as I've been able to do in other 3d engines. I've tried using multiple models of the same shape but they get that fuzzy clipping effect like the renderer trying to display multiple faces on the same plane. Update: I cannot find where a single model can utilize an already made method of texture layers so in the meantime I'm looking over the texture stitching and buffer classes. I guess loading the textures in data and layering them that way would work but I had hoped if the source had something that did something like that already, similar to passing multiple models to the same Render... still if anyone has any better ideas let me know.