jabelar
Members-
Posts
3266 -
Joined
-
Last visited
-
Days Won
39
Everything posted by jabelar
-
Using other mods' items in my crafting recipes
jabelar replied to Aspiring-Mod-Maker's topic in Modder Support
One trick is you can just make a debug method in your mod that lists names and/or ids of all the registered items (or blocks or entities) to the console, and then run your mod with the other mods. I think you can probably also inspect the lang files of the other mods. -
Unexpected client/server discrepancy in entity.rotationYaw
jabelar replied to MrCaracal's topic in Modder Support
Regarding clamped versus non-clamped angles, it is just a style thing although obviously there is a theoretically the problem with unclamped if the game ran for so long with the player spinning in just one direction that it actually overflowed, but that is not a realistic worry since the rotation is a float (so would take over 5x10^27 years of continuous turning). But in general programming practice clamping the angle is probably more correct/safe. The one danger with clamping can be if you have to handle the difference between angles or if the direction of change is important. For example, is going -45degrees clockwise really the same as going 315degrees counter-clockwise? If you only care about the angle in the moment it is, but what if you had an animation where the entity looked in the direction it was rotating, in that case you'd need to know direction. And what if you were calculating physics of angular momentum, in that case going more degrees in same time period would have higher angular momentum. Yeah, both diesieben07 and I are saying that in an individual tick the server and client could easily be off by the movement that occurred in the tick, and possibly longer depending on networking delay. Network packets are asynchronous to the ticks, so there is no guarantee that server and client could be synced on a tick by tick basis. If the discrepancy was large I'd be worried, but 10degrees sounds quite expected. -
@Kwibble, these are private methods -- if they're not being called in the class, they're unlikely being called anywhere. @Tuhljin, when I write code I often include "helper" functions that I find occasionally useful. If I'm creating a tutorial I sometimes leave them in the code even if they aren't being used in my example. For example, in my Model tutorials I have a set of classes called spinX(), spinY(), spinZ() that I use for debugging of rotation points. Of course in my case I try to explain in my tutorial what those do, but my point is that I do sometimes include methods in my classes that don't happen to be used. So I think your suspicion is right that they are just potentially useful methods that the author either left for interest's sake or forgot to remove at some point. I usually let my IDE help find all that stuff. Usually Eclipse will give warnings about unused fields and methods.
-
Yeah no problem. I'm okay with helping anyone that's willing to put in the work.
-
Well, it is probably just a programming mistake. Honestly you're probably making the payload processing a little more complicated than necessary, although your general approach seems workable. Generally you shouldn't need to access the bytes in the buffer directly, but use ByteBuf and ByteBufUtils to access it.
-
I know you said "don't tell you to learn Java" but your problem is exactly that -- you need to understand Java better as you're doing about four things that are Java mistakes and have nothing to do with Minecraft. First of all, you assign CreatureChoice (which should really be creatureChoice for programming convention) to a String value but then in your example of your checking for a minotaur you aren't comparing to String. Furthermore, String is a little tricky as you shouldn't use == to test if it is equals, but rather you should use the equals() method. Note also that you put a capital "M" on "Minotaur", but used a lowercase "s" on "satyr" so that could cause trouble if you didn't get it right. So instead it should be something like: if (creatureChoice.equals("Minotaur"){ But then you have another Java programming problem -- the value of creatureChoice exists in the EntityMinotaur and EntitySatyr instead of the ModelHornedBiped class. So you'd have to "cast" the Entity parameter into the class to access the creatureChoice field. But the problem is that you actually can't know which type is being passed so you can't cast it. To solve that, you'd have to create a common parent class called EntityHornedBiped but that changes your whole class structure ... anyway, the approach you're taking is not the right approach. The good news is that there is a much easier way. Just use the instanceof operator to check what kind of entity is being modeled. So forget about all that string stuff. Instead you should just do something like this in your ModelHornedBiped class: if (entity instanceof EntityMinotaur){ GL11.glPushMatrix; GL11.glTranslatef(0F, -0.2F, 0F); GL11.glScalef(1.5F, 1.5F, 1.5F); GL11.glPopMatrix(); }
-
Well if you're sharing the class, you could just use variables to check to see if you want to scale. For example, in my code above the scaleFactor variable is passed from the entity so each entity using that model can have different scaling.
-
Well I do the scaling like this, in the Model class for my entity. // scale the whole thing for big or small entities GL11.glPushMatrix(); GL11.glTranslatef(0F, -0.2F, 0F); // need to move the model a bit to keep "feet" on the ground. Actual formula seems to be 1.5-1.5*scaleFactor but you can just play around with it manually. GL11.glScalef(entity.getScaleFactor(), entity.getScaleFactor(), entity.getScaleFactor()); // put your own scaling amount here myModelRenderer.render(f5); // render your own stuff here // don't forget to pop the matrix for overall scaling GL11.glPopMatrix(); }
-
Yes, I often think it is not working because it will take long time to start up, can even disappear for a moment. Give it time.
-
Make something happen to the player every x ticks or every tick.
jabelar replied to sigurd4's topic in Modder Support
Okay, I'm still planning to augment the tutorials with full github examples, although I did put a lot of instruction into the tutorial. I'll see if I can make a clearer summary though because I guess I do have a lot of information there. The basic idea is: 1) Create an event handling class, call it whatever you want. I give an example of such a class in the tutorial. 2) Put a method in it that follows the example in my tutorial. In needs to have the @SubscribeEvent annotation and the parameter must be the type of event you're trying to handle (I put lists of pretty much all known events in the tutorial). That method should do whatever you want when the event happens. 3) register the handling class to the event bus. This is done in your main class (or CommonProxy) in the init() method. I give examples of registering the class to the bus in my tutorial. That's pretty much it. -
I have created an abomination (custom entity model)
jabelar replied to Zer0HD2's topic in Modder Support
Good. Yeah, I think the concept of what a child is needs more explaining. I'm actually going to do more to add the convertToChild() method that I came up with while helping delpi on a similar issue. I really wish Techne just handled child parts better... Techne is so close to being fully useful, but their Java export has a few nagging issues. -
Okay, here's the concept. A network sends a byte stream. They break it up into "chunks" called packets. At the networking layer the packets have various bytes that delimit them, but Netty take care of that. What we care about is called the "payload" of the packet. The payload is just a series of bytes. We can put whatever we want into them. The Netty system allows us to access this series of bytes through a type called ByteBuf (meaning byte buffer). There are methods that help convert various data types like boolean, String, int, float into series of bytes. So it becomes easy to put variable values into the byte buffer and to read them back. What you put into the payload is entirely up to you. The only important thing is you need to read back the values in the exact order you write them. Since you may have packets that have different orders of variables in their payloads, most people use the first int value as a packet type identifier (also called the discriminator). So the toBytes() and fromBytes() methods are just creating and reading back the sequence of values from the packet payload (which is a ByteBuf). So let's say you have a variable on server side that represents the mana level of the player. If you want the client to also be aware of that mana value, you want to send a packet. To send a packet you need a packet system with a sendToAll() method (because you usually want all the client players to know the value of the mana of all the players) and you will pass a packet (I think usually an FMLProxyPacket or some other class that implements IPacket) to the sendToAll() method. The packet you pass needs to have the payload you want, so in the packet class you need to create the payload. To create the payload, you simply take the ByteBuf that represents the payload and write the values you want to send. Again the first int is usually a packet type, so if you want packet type 1 to represent a mana packet you would writeInteger(1) to the ByteBuf. Then, assuming the mana value is also an int, you would write it to the buffer: writeInteger(mana). That's it for sending the packet -- you call sendToAll(new ManaPacket()) where the ManaPacket writes the packet type and mana value to the payload. Then on the receiving side (all the clients that will receive the packet) you will get an event when a packet is received and you will handle the event by taking the payload of the packet (which again will be a ByteBuf) and read back the values in same order. You will first readInteger() and check that the value is 1 (representing mana packet), and then readInteger() and take that value and assign it to mana. This will sync the client, as the mana value there will now match the server that sent the packet. That's pretty much the idea. You're writing data to ByteBuf in the order of your choosing and putting those into payload of a packet. You send the packet, and when it is received you handle the event by reading back the data in the same order. Does that make sense? The toBytes() and fromBytes() are just the methods for creating and processing the payloads in the packet.
-
Unexpected client/server discrepancy in entity.rotationYaw
jabelar replied to MrCaracal's topic in Modder Support
Agreed that the "always increasing" versus within 360 rangs shouldn't be any issue because it is common to use modulo to keep in range as in the example TheGreyGhost gave. In fact, if you're ever comparing angles in computing, for most purposes you should remember to put both into range before the comparison as many methods can let them get out of range. The only weirdness would be the discrepancy mentioned. Again in the example cited, it takes the rotationYaw as the value (not an increment), and similarly if you look at the sendMotionUpdates() in the EntityClientPlayer class it sends the value (not an increment). So it seems pretty clear that the client is sending the rotationYaw value directly to server and server is directly updating (with exception of aliasing to the 360 range). The only possible discrepancy seems like it would be due to lag of however many ticks it might be between update packets. I do see that the messages go into a queue (rather than being sent immediately) so lag is possible. However again, when a packet is received it should sync it fully so unless you're continuously moving the Player entity it should sync up faster than human can really notice. -
I have created an abomination (custom entity model)
jabelar replied to Zer0HD2's topic in Modder Support
There are only two things that can really mess up. Once you get the idea it will be easy. First, you should not render the child if you render the parent. Rendering both will cause duplicate in different positions. The second thing is that the rotation point of the child has to be *relative* to the parent's rotation point. So if you made a Techne model that had the parent rotation point at (0, 12, 0) then in Java you have to subtract that amount from the rotation point of the child's rotation point (if you got the values from Techne). The other tip I will give you is to ensure that the rotation points in Techne are correct (i.e. at the joint or connection point that you want) because a lot of people erroneously use offsets to make it look right but then it will go really wrong when you rotate. -
If you want a modern example (in addition to the one the diesieben07 already referenced) you can look at https://github.com/pahimar/Equivalent-Exchange-3/tree/master/src/main/java/com/pahimar/ee3/network Those are really examples, rather than tutorials because they don't really explain all the concepts. So you might want to check out my tutorial -- it is my own (not recommended exactly, but works fine) packet system but I wrote it as a tutorial so I explain the concepts. The concepts are common to every Netty-based packet handling system, so maybe helpful. Perhaps I put too much information there, but probably worth reading the subsection called "Steps Needed For A Packet Handling System". Anyway, check it out at: http://jabelarminecraft.blogspot.com/p/packet-handling-for-minecraft-forge-172.html
-
Make something happen to the player every x ticks or every tick.
jabelar replied to sigurd4's topic in Modder Support
I've just drafted a tutorial on 1.7.2 event handling. There is a lot of information there, but it should explain the concepts, how to register handlers, and list of various available events. As diesieben07 advises, there is PlayerTickHandler (on FML event bus) available. Just create a counter there that you can test to see that so many ticks have gone by and you can use event.player to find the player and then you can call his NBT handling methods. -
It sets the size of the bounding collision box only. It does not affect visible scaling. Note also that you can only specify two dimensions -- the X and Z are always equal so the the base of the bounding box is always square. For fun, you can see the bounding boxes of the entities while you're playing the game -- just press F3+B. I recommend doing this when making custom entity models because it is easy to have the collision box needing adjustment.
-
The point is that the extended properties is a feature intended to easily save and load extra information about entities (and in CoolAlias' example he uses it for players). However, saving and loading refers to when you start and stop the game -- it doesn't actually handle syncing the client and the server. I think you know this since you mention the issue that the client needs to know about it in order to draw the mana bar (in that example). So you need a custom packet from server to client. Unfortunately the packet handling method on the wiki, which many of us including CoolAlias used, turned out to have some memory leak issue. Further, Forge has been fixing bugs in their simple network wrapper system, and it seems to be ready to use. So we're just saying that (a) you need a custom packet system, and (b) gave you some links to examples of the recommended system. It does seem painful at first to set up your first packet system -- you only want to send one int of data and need to have handlers and payload encoders and such. However, it is worth taking the time to set it up once and then you can (usually) make use of it for many modding purposes thereafter.
-
Spawning Entity at player through keybind press
jabelar replied to Sear_Heat's topic in Modder Support
You should look at this example code. It uses simple network wrapper method to do keybindings -- pretty much what you're doing. Pashimar (the author of that example) is a respected coder so you can trust his stuff. https://github.com/pahimar/Equivalent-Exchange-3/tree/master/src/main/java/com/pahimar/ee3/network -
I have created an abomination (custom entity model)
jabelar replied to Zer0HD2's topic in Modder Support
Well, for example the part where I mention that if you use addChild() you should only render the parent. In your case, you are rendering the children like the ears and such. That will cause a double rendering effect (or triple if they are children of children) and each render will be offset by the relative rotation point). So my first suggestion is that you should only be rendering the parent parts -- the children get rendered automatically. -
Back to your original problem (saving data to be shared across mods). While I think the idea of an API mod as the intermediary is an interesting way to do that, it is slightly problematic in that it kinda complicates the installation (in addition to the complicating the implementation of each of your mods). For example even if you just want to run one of the mods, you'll have to have this API mod as well. No big deal I guess, but I think an alternative is just to share a configuration file between them. Or actually any file between them. We're working in Java after all, so you have access to regular file methods. And the Configuration class in Forge allows you to use file locations other than the default. Anyway, when I think of storing data my first instinct is a file, not a whole 'nother mod.
-
How to make a block that mobs of a certain type can't walk over?
jabelar replied to AskHow1248's topic in Modder Support
We already went through this idea -- the problem is that would block all entities, including players. He wants to only block certain mobs from crossing. Overriding the addCollisionBoxToList will allow you to selectively block things. Look at the code I posted. Also, the vanilla Pathfinding will path around the invisible blocks, as they are stacked 2 high, as well. The only real caveat is if you bury the block, in a hole, the mob could walk over the invisible blocks, but i would call that user error, as they aren't using the block right. You could even add a simple check for such a thing to prevent placing if their is no block 3 blocks above where it is placed or something. Okay, after looking into it I agree. In your original post you should have pointed out what you were really suggesting -- you made it sound like you were simply putting invisible blocks above. The trick is that these have dynamic bounding boxes. Very cool trick. -
Spawning Entity at player through keybind press
jabelar replied to Sear_Heat's topic in Modder Support
With custom packets, it is up to you to put information into the payload however you choose. The packet payloads are passed as ByteBuf type which has methods for writing int, float, String, etc. to the buffer. The first byte you write is usually a unique int value (sometimes called the discriminator) that you use to identify the packet type (because in most mods you will end up with multple types). So for example you could have this key press packet type be 1. In that case you may not need anything further -- a packet type 1 could represent this particular key press. Then in your client processing code, you would sendToServer() this packet type when appropriate. The server will then get a network event when it receives the packet, and then you check the channel to confirm it is from your mod (for compatibility otherwise you might mis-process unknown packets) then you start reading back the payload of the received packet in the same order you wrote to it. In this case you'd just read the first int in the payload, check if it equaled 1 (i.e. it is the packet type expected) and then spawn your entity. Not sure if that makes sense. The main point is that you need to send the packet by calling the sendToServer() method and you need to pass the method a packet you create that has type that you choose to indicate this event. For example, in this tutorial (http://www.minecraftforum.net/topic/1798625-172sobiohazardouss-forge-keybinding-tutorial/) you can see they have following in their key handling class -- notice the sentToServer() method call: /** * KeyInputEvent is in the FML package, so we must register to the FML event bus */ @SubscribeEvent public void onKeyInput(KeyInputEvent event) { // FMLClientHandler.instance().getClient().inGameHasFocus if (!FMLClientHandler.instance().isGUIOpen(GuiChat.class)) { if (keys[CUSTOM_INV].isPressed()) { TutorialMain.packetPipeline.sendToServer(new OpenGuiPacket(TutorialMain.GUI_CUSTOM_INV)); } } } -
Spawning Entity at player through keybind press
jabelar replied to Sear_Heat's topic in Modder Support
The reason this is more involved is that you want to do this with a key press -- which happens on the client side. Spawning the entity has to happen on the server side so somehow you need to send information to the server that indicates that the key was pressed by a certain player and then use that player's position to spawn your entity. -
I have created an abomination (custom entity model)
jabelar replied to Zer0HD2's topic in Modder Support
I can't look at dropbox from work, but will give it a look when I get home. It seems that you have used addChild() to create hiearchy so that is good start.