Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. Thanks. The point about some of those being for item swinging makes a lot of sense. Anyway, yeah I figured I'd do it like that (maybe I'll just make my own additional fields in the entity). I was just hoping to understand whether there was a straight-forward way to think about it.
  2. Sorry for the long post but this simple concept has a convoluted implementation in vanilla Minecraft... As most people know, to create the walking animations where your arms and legs swing, the entity's model class uses some parameters and trigonometry to create cyclical rotations to implement the animation. Looking at the code for a while but I'm still fairly confused as to what each field represents. In EntityLivingBase there are these four fields and related methods: - swingProgressInt - swingProgress - getSwingProgress() method seems to return a value between 0 and 1 that takes into account partialTicks - getArmSwingAnimationEnd() method (comment says "Returns an integer indicating the end point of the swing animation, used by {@link #swingProgress} to provide a progress indicator.) The default value seems to be 6 (and changes with dig potion modifiers). - updateArmSwingProgress() method seems to increment the swingProgressInt each tick and compare it with the the animation end, returning a ratio between the two. - limbSwing (comment says "Only relevant when limbYaw is not 0(the entity is moving). Influences where in its swing legs and arms currently are. - limbSwingAmount (in moveEntityWithHeading() method, this seems to be the amount that is directly added to limbSwing in each update) Most of these are not overridden by specific entities, but in the models for some entities the math is different using these values. Anyway, putting it all together I think it works like this: 1) every tick the swingProgressInt is updated by 1 and swingProgress is set to ratio of swingProgressInt to the animation end. By default the animation progresses over 6 ticks. But it seems wrong to me that a full animation would only be 6 ticks (i.e. only 1/3 of a second), so I must be understanding something wrong here - is it really 6 ticks for a full cycle? 2) the Render class copies the swingProgress to the associated Model class 3) the Model class does a bunch of math to use the swingProgress (accessed directly) as well as limbSwing and limbSwingAmount (passed as parameters) to rotate the arms/legs. For example, Model Biped has the following code for the right arm rotation x (I deleted the other body parts as well as the parts related to holding bows, sneaking, isChild, to make it easier to follow): /** * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how * "far" arms and legs can swing at most. */ public void setRotationAngles(float p_78087_1_, float p_78087_2_, float p_78087_3_, float p_78087_4_, float p_78087_5_, float p_78087_6_, Entity p_78087_7_) { this.bipedRightArm.rotateAngleX = MathHelper.cos(p_78087_1_ * 0.6662F + (float)Math.PI) * 2.0F * p_78087_2_ * 0.5F; float f6; float f7; if (this.swingProgress > -9990.0F) { f6 = 1.0F - this.swingProgress; f6 *= f6; f6 *= f6; f6 = 1.0F - f6; f7 = MathHelper.sin(f6 * (float)Math.PI); float f8 = MathHelper.sin(this.swingProgress * (float)Math.PI) * -(this.bipedHead.rotateAngleX - 0.7F) * 0.75F; this.bipedRightArm.rotateAngleX = (float)((double)this.bipedRightArm.rotateAngleX - ((double)f7 * 1.2D + (double)f8)); } this.bipedRightArm.rotateAngleX += MathHelper.sin(p_78087_3_ * 0.067F) * 0.05F; } The math seems a little unusual to me. The comment for the method says "par1 represents the time(so that arms and legs swing back and forth) and par2 represents how "far" arms and legs can swing at most". But then the math for the bipedRightArm.rotateAngleX takes the following steps: this.bipedRightArm.rotateAngleX = MathHelper.cos(p_78087_1_ * 0.6662F + (float)Math.PI) * 2.0F * p_78087_2_ * 0.5F; This is pretty straight-forward but doesn't exactly match the comments since the second parameter doesn't directly limit "the swing at most". This formula also implies that the first parameter is in radian units, but it is also multiplied by 0.6662F (presumably to slow down the swing rate). That isn't the weird part, but then it does this: f6 = 1.0F - this.swingProgress; f6 *= f6; f6 *= f6; f6 = 1.0F - f6; f7 = MathHelper.sin(f6 * (float)Math.PI); float f8 = MathHelper.sin(this.swingProgress * (float)Math.PI) * -(this.bipedHead.rotateAngleX - 0.7F) * 0.75F; this.bipedRightArm.rotateAngleX = (float)((double)this.bipedRightArm.rotateAngleX - ((double)f7 * 1.2D + (double)f8)); (The swingProgress is copied from the entity#swingProgress.). So this means that the formula is f7 = sin((1.0F - (1.0F-this.swingProgress)^3)*PI) That math again seems a little unusual to me -- graph it on a graphing calculator and you'll see it is pretty strange function. I guess it works fine in practice, but I'm not sure why they didn't use a simpler trig function -- should be able to just use an arc-sine function or something which would be standard way to make a cycle. The next strange thing is that the f7 gets added to the angle. I think that is weird because I doubt that f7 is really in angle units -- the result of a sine function is unitless (you put angles in, not get angles out). So basically, they are taking a non angle, putting it into a trigonometric function and using the result as an angle. Kinda hacky I think. On top of that, the swingProgress is also used to set a value for f8 which is then also added to the rotation. Finally, after all the above, the rotateAngleX gets the third parameter added to it: this.bipedRightArm.rotateAngleX += MathHelper.sin(p_78087_3_ * 0.067F) * 0.05F; Anyway, my point is that the overall math hurts my head. Personally, if I was making a cycle I would simply step it (based on movement) through an arcsine function where the input is limited to whatever swing range is interesting. In conclusion what I am interested to know is: which out of these various parameters and fields is best base value to base my own animation cycles on? swingProgress? swingAmount? etc. I am capable of creating my own progress field (i.e. by monitoring movement and incrementing counter) but was just hoping to understand the built-in ones and make use of those... Anyone have a clear explanation of the fields and math for arm swing in ModelBiped?
  3. Do you mean you want to read from the existing models, or do you want to write your new model to that location? Also, are you talking about models for entities, or for blocks and items? In 1.8, entity models are defined in Java code (i.e. the classes that extend ModelBase) but blocks are defined in the blockstates JSON files. So I think you'd have to use different approaches for each case. For the entity models, since the model is active code instead of a resource file I think it would be difficult to "parse" directly. Basically your parser would have to sort through the class file and figure out what it is doing. So for entities I suggest you simply make your own type of resource and copy the information over but in a format that is easier for you to use. For the blockstate and item models, they are already JSON so are fairly easy to parse. However, the vanilla models are going to be in Minecraft JAR, not your mod JAR. There is probably a way to access the vanilla models from your code, but again it might be easier to simply copy all of them over into your mod (you's simply have to cut and paste all the blockstate related asset packages into your project. Reading existing ones is fairly easy, you just can either use standard Java methods for navigating the JAR, or you can use Minecraft helper methods for accessing resources. Parsing JSON files can be done with the GSON library, or you can make your own text-based format with your own parser.
  4. I've played with this before and like diesieben07 mentions it usually doesn't result in what you think -- you can fairly easily make the physics honor real time (I'll explain how below), but when everything else in the game is lagging it is really weird when the physics works real time. Basically it is just much more playable when everything lags together. But, if you want to play around with it, you can use Java's System.nanoTime field to measure the time each tick is taking and adjust accordingly. Basically, you need a field to hold the result of System.nanoTime from the previous tick, and you need a field for the time for current tick. You can update these in the tick events (probably the client tick and server tick events) where you copy current time to the previous time, then update the current time from System.nanoTime. Then you just need to compare what the tick took relative to what it should be. There is supposed to be 20 ticks per second so each tick should be 0.05 seconds = 50 miliseconds = 50,000 nanoseconds. So to adjust things for this lag, you would use a scaling factor of (currentTime - previousTime) / 50000.
  5. The key point is that instead of using the players "name" you should use their UUID. That is more specific and persistent. After that, in your game have a map between UUIDs and functionality. And you can load information from a pastebin site using standard Java. In Java, to read URLs you can do it this way (I would do it in a separate thread as shown because accessing files over internet could take time, also make sure to handle any errors): public class PermissionChecker implements Runnable { String fileContents = ""; @Override public void run() { InputStream in = null; try { in = new URL("https:put_your_link_here").openStream(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { fileContents = IOUtils.readLines(in).get(0); // toString(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { IOUtils.closeQuietly(in); } } public String getFileContents() { return fileContents; } } Then you need to write code to "parse" the string returned, and convert it to a map of UUID and permission levels. How you do that exactly is up to you.
  6. Basically it is correct use of the English word "type" even if it isn't really correct for computer language definition of "type". However, since we're discussing computer programming probably better to stick to the classic definitions ... But it is difficult sometimes to explain to people the concept of why Items and Blocks are singletons without resorting to the English definition of the world type. Because the end result is you want to create a "type" of ItemStack and you do that by associating it with the relevant Item. So the Item associated defines the "type".
  7. Choonster, did you get any response from Lex or cpw on this? I'm still very interested in this topic because it seems like such a powerful modding mechanism but several people have failed to get it to work...
  8. Someone that knows more about chunk loader / saving can probably help you better. I expect there would be a way to only update the chunk after doing all the copying, whereas the current lag might be because it is saving every time you place a block. Just a wild guess. But I have a couple other thoughts: 1) In the case where the current block matches the block you're moving to that position, like would happen for a lot of air blocks, you might not want to actually copy the block. Depending on how many air blocks are included in your copy, that might make it much more efficient (i.e. not triggering all the vanilla add block stuff). 2) When I was doing a mod that generated a castle in the sky I found that placing blocks high up were way slower (thousands of times slower). I traced it down to issue where Minecraft recalculates the lighting after every block placed and therefore higher up blocks have more processing. I was able to find a way to disable this although it was slightly tricky. If you think this is related to your problem I can maybe give you some code examples. 3) When placing blocks there is option to place it with notification of neighbors. That is often useful, but I assume there is some performance impact. Depending on how you do the copying though you might want to disable some of that.
  9. No, I use that on some computers. There are a few things that could be going for you: 1) On slower computers, sometimes the IDE takes a while to figure out everything. If you think about what the IDE is doing it is pretty amazing that it can do the real-time warnings -- it literally has to parse all the code in the file, figure out the context, follow imports if needed, etc. So maybe your computer just needs time to catch up. Maybe right-click on the project hierarchy and refresh the project, or also look at the build path settings. 2) Typographical error. Just takes one character wrong to make the computer declare a mis-match. I usually have Eclipse set to update imports automatically upon save. So I would delete all the imports and have them re-populated by Eclipse. In the cases where there are multiple possibilities then it should prompt you for which one you want. 3) Something got screwed up in the project. Try re-running the gradlew setupDecompWorkspace and gradlew eclipse commands again. If that doesn't work, maybe start fresh -- download Forge, set it up and take the example project and try to simply add the logger. 4) If all else fails, try another computer.
  10. It usually means that you either did not make your class properly extend the parent class (i.e. there are no parent methods to override), or it means that you didn't exactly get the prototype of the method correct (either the return type or the parameter list differs from the parent method). Can you just post the whole code for your class?
  11. There isn't much official documentation. Mostly though you need to look at the code itself which is for the most part well-commented. You can also read the discussions in the Forge project itself to understand the details of some aspects of the interface. But it would still be difficult to get started just with that, so some of us have written tutorials: mine are at jabelarminecraft.blogspot.com and there are many other good ones, including videos on YouTube if you prefer learning that way.
  12. One thing you can do is replace blocks as they are generated -- assuming you're talking a block that gets generated in the world. If you handle the PopulateChunkEvent you can try to iterate through the block positions to check for your block and then replace it. I have an example "Replace All Generated Blocks With Different Block" on this tutorial page: http://jabelarminecraft.blogspot.com/p/minecraft-forge-172-modding-quick-tips.html If you want to make it impossible to place the block in creative mode, you could further remove the block from the creative tabs and add your own to replace it.
  13. In 1.8 there is an event called CameraUpdateEvent. You can use that to change the position of the camera.
  14. The error says you registered it twice. So figure out where your registration and see where that code is called from. It should be easy to find out when it is getting registered twice.
  15. You just code it. If you want to spawn an entity in the structure, then just spawn one. If you want items or tile entities with loot, just place them. Basically, in your schematic you should have indications on where possible entity spawn points, or loot points are, and then you would use standard Java to check random chance and pick loot or entities or whatever to place.
  16. Again you need to go through every line of the related code and trace the execution. So if you think something is supposed to be in a slot, print out what the computer thinks is in the slot, if you think it should have found a recipe match, print out whether it found a match or not, and so on. I'm sure that if you just trace through you will find that you made some simple mistake (like wrong slot number assignment, or something).
  17. In your ref strings class, you have the server proxy string wrong. You have: public static final String SERVERSIDE = "Com.gun.main.SlientProxy"; That might be causing the trouble.
  18. The way you should be doing it is download and extract Forge to location you want your workspace, open a console window in the folder and first run command: gradlew setupDecompWorkspace then run command: gradlew eclipse. Then in Eclipse, you should import the project (right click on project hierarchy, choose Import, then choose Existing Project). That should come up with example mod project that includes all the Forge libraries.
  19. In these sort of cases, you need to learn how to debug yourself. It is your code and any such problem will be specific to your code. So it is important to learn how to be self-sufficient. Here is my suggestion -- trace the execution of your code carefully and confirm that every step of the code does exactly what you expect. You can do this through debug mode in Eclipse, but I prefer to use console statements since then you can just play the game and still monitor what is happening. So with console statements I put a System.out.println (or you can use logger) statement in every method to confirm that the method is being called. Then in every conditional statement (like an if statement) I print out the fields that are being tested to make sure the value is correct. Lastly, any code related to the bug, I put a print out of the relevant fields. When you do that, you've very quickly figure out where things are going wrong. Computers are entirely logical, so there is simply some step along the way where your code isn't doing the logic you expect. Look for that.
  20. A similar question was asked recently on the forum, although the guy was only wanting to detect symmetry rather than specific patterns. The short answer is that the number of possibilities for pattern positions expands exponentially as the search area grows, especially if asymmetric patterns need to be considered. Think about it -- if you had a 5 x 5 asymmetrical pattern that you wanted to search in a 10 x 10 area, then there would be 25 possible translations times 4 rotations = 100 possibilities. If you increase the search area to 15 x 15 then there are 100 possible translations times 4 rotations = 400 possibilities. If you increase the search area further to 20 x 20 then there are 225 tranlations times 4 roations = 900 possibilities. Now that isn't too bad, since a computer is still extremely fast but there are 25 blocks in a 5 x 5 pattern so you'd have to check up to (average would be half of this) 22, 500 blocks! Then, it depends on how many patterns you want to look for and multiply that up. Anyway, you get my point -- don't get too ambitious about making the search area big. Okay, back to your main question about best approach. Well, in the end you simply have to check all the possibilities. However, you can stop searching as soon as you find the pattern, so sometimes it will happen at the beginning of the search, sometimes at the end. In terms of checking the possibilities it is all just using arrays -- you can store the pattern in an array (could be an array of blocks, or block names, or some coded int value) and then have the code create the rotated arrays. Then you use a loop to go through an array of locations, just like you mentioned from -x, -z to +x, +z looking for each of the rotations. And escape from the loop as soon as you find the pattern to avoid wasting processing power. Note that it is possible to simply use math to figure out the rotations on the fly, but I think it would be much easier to get right if you simply create the rotations and check for each.
  21. I think it is important to understand that an Item instance is never really useful on its own. You really need an ItemStack or an EntityItem depending on whether it is in an inventory or on the ground. If you only have a single item, you are really holding an ItemStack with quantity 1. I think there are only one main instance of each Item class, and it describes the behavior of items generally. But if you want a specific item of that type to be a bit different then you need to use the ItemStack and a combination of metadata and/or NBT data. So you don't name an Item, you name an ItemStack. You don't damage an Item, you damage an ItemStack.
  22. You need to post your code if you want us to find problems with it.
  23. Some of the change logs have indicated there is some known problems with the substitution alias system. For example it looks like they may have made a fix for this in Build 1.8-11.14.3.1559. The changelog says "Fix substitutions for recipes and oredict recipes. Should mean that substitutions start working properly." But yes others have been reporting problem with substitution alias. For example, even in 1.7.10 this was reported: http://www.minecraftforge.net/forum/index.php?topic=30675.0 There is an interesting thread here which I think was related to the implementation of the substitution alias: https://github.com/MinecraftForge/FML/issues/370 There are a couple interesting points in that discussion. First it is not clear that you should normally register your new block (that might be creating the duplicates). Also, you might need to ensure that the substitution is fully qualified (i.e. vanilla name includes "minecraft:" as modid. However, it seems like there was still acknowledgement that it might now work in the later comments.
  24. the FML lifecycle includes a post-init event that can be used for code that needs to make sure all mods are loaded. Furthermore, you can specify dependencies and load priority in the mod info file, I believe and maybe also in the @Mod annotation.
  25. Right. That is actually the good thing about child parts. But in this case the point is to do the model the same way that growable entities do. And yes, like you pointed out, the head must be a separate part and not made as child.
×
×
  • Create New...

Important Information

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