Jump to content

HashtagShell

Members
  • Posts

    94
  • Joined

  • Last visited

Everything posted by HashtagShell

  1. Any plans? Browsers look like they'll be slowly but surely breaking anything that doesn't use at least military grade encryption, jeez.
  2. Rebuilding reflections against guava 21 just works out of the box, seems there were no relevant API changes. Minecraft does start loading in the devenv, which means the binary compatibility problem is fixed (thx MDW and diesieben for pointing that out). It's still a good idea to shadow reflections (and javassist) if it needs to be present in production. Guava doesn't need to be shaded, since v21 comes with forge (thx loordgek). Since reflections is under the WTFPL, here's the jar (reflections 9.11 against guava 21.0 and javassist 3.21.0-GA). It's literally just a maven build with the version changed in the pom. (Keep in mind that once you're including the library from the filesystem, and not maven, you have to depend on its deps manually somehow) reflections-0.9.11.jar
  3. Heh, I just ran into the same problem today. What a coincidence. Anyway, I tried shading both reflections and guava (and javassist too while I was at it) using forge's reobf task. Reobfuscating them to a unique package should fix this collision as far as I can tell. The jar builds correctly and, while I haven't tested it yet, should work in an obfuscated environment. In the devenv however, since the reobf task doesn't run (why would it), the collision remains. The reobf task can be run on arbitrary artifacts since FG 2.3ish, but I'm not sure how the devenv runClient task works, there might technically not be any gradle artifacts involved in the process. Just my two cents.
  4. Or apparently it *does* run over https, but with a cert for the mercurius subdomain, and nginx doesn't route it. At least the login page should be running over HTTPS imo. (Personally I don't really care that much because password manager, but others might not be using one)
  5. Depends on how much you already know. If you have almost no knowledge of Java at all, you should go through a tutorial/course/JLS first, you won't learn what alien syntax means by just looking at it (unless you already know C# or the like). If you have quite good knowledge of the syntax, but not the APIs or quirks (return-in-finally, reflection, ASM, unsafe, etc.), it is well worth going through some example code, for instance, ASM is used quite heavily in Forge. Still, expect to be reading lots of papers and manuals; the likes of ASM will hardly make any sense without a prior understanding of the internals of the JVM, ie. having at least skimmed through the JVMS. If you already know how Java and all its quirks work, there is still a lot to learn in public domain code - best practices, keeping good code readability, algorithms and ideas. For example, once you already know how to render stuff in OpenGL, going through a few examples of how people have solved some rendering concepts will over time make you understand how to render your own shapes in the most efficient way (Though, rendering might not be the best example since it also requires a lot of knowledge outside the field of informational technology - math; rendering is a no-no without knowing trig and vectors). TL;DR: You will profit from reading open-source code, if you already know the language syntax and API basics, if you don't, do a tutorial or something first.
  6. Usually, the method names chosen by the MCP team already describe the purpose of a method well enough, and if not, many methods have a JavaDoc added as well. When a method is either unnamed or without a JavaDoc, you are welcome to name it and its parameters according to its purpose, adding a JavaDoc if necessary, and submit it either via the MCPBot_Reborn bot in #mcp on the Esper IRC, or by submitting an issue on the MCP github.
  7. To toy around with vanilla minecraft code only, setting up an MCP workspace directly might prove more useful.
  8. Tip 1: Try avoiding copy&paste. Tip 2: If you do have to copy&paste, make sure to read through and understand what the code is doing. Avoid "blind" copy&pasting. Tip 3: Refactor and optimise the code to your liking and your style of coding. Example: When I had to copy the elytra motion logic, I went through it and analysed every statement, commented it with what it did, and, in this concrete example, removed all the Mojang derps. (https://gitlab.com/snippets/1657880) If I may ask, where was this specifically copied from? If it was vanilla minecraft, then the decompiler might have been confused by how enums work in Java, producing this mess.
  9. A few notes: In EnumType: Field meta is obsolete, use the autogenerated enum method Enum#ordinal() instead. Returns the index of the enum in the declared order starting from 0. Static field META_LOOKUP is obsolete, just do Enum#values()[index] on demand. The compiler generates a VALUES array, which is then directly returned by Enum#values() The field name is obsolete, every enum stores its declaration name as a field, which can be accessed with Enum#name(). It returns the exact field name (often uppercase), so you have to toLowerCase() it before using it in this case. The getName() method can thus be overridden to return name().toLowerCase(); Also note the Enum#valueOf(String) method, which looks up an enum by its field name (often uppercase). It might be worth your time disassembling a simple enum with a few fields to see what the compiler does to it (you can also use the ASM plugin for idea/eclipse to see the bytecode): user@machine:~$ javac TestEnum.java; javap -l -p -c -s -constants TestEnum.class Instead of you private getResourceLocation(), use getRegistryName().toString(). Same result, but avoids the code duplication. Set the registry name in the constructor with setRegistryName(new ResourceLocation(MODID, name)). I'm surprised Forge didn't scream at you for not doing it. Unlocalized names are per convention in the form MODID:NAME. Although other things will work, they don't follow convention. Set your registry name first and then set your unlocalized name with setUnlocalizedName(getRegistryName().toString()). This follows the convention and makes sure your registry name is symmetric with the unlocalized name, which makes things more organised.
  10. Wouldn't throwing around events for received events be something for Forge to be able to do?
  11. Why am I not surprised that Windows handled something smartly again. </sarcasm>
  12. Following the calls, you will get from gradle calling ant to ant calling the jarsigner tool and throwing an exception when it returns non-zero. Thus, oracle's jarsigner tool failed. Debugging where exactly the failure was is hard, since the call to it is wrapped in an ExecTask. It does tell us about code 1 though. Citing the doc for the jarsigner cmdline tool: Meaning SOMETHING went wrong. (well, isn't that a new one) You'll probably want to run the jarsigner cmdline tool directly with an attached debugger and the exact same options that gradle would have constructed from your configs. Step through it step by step or put a breakpoint on the (I assume there is one) method call that terminates the program with an error code, and then look a level up the frame stack to see where the code is being 'thrown' exactly.
  13. Pretty sure timeout is not a thing forge or minecraft do, ie. probs no events. Isn't it like a socket/packet/networking/connection deal?
  14. Stack traces are useful! Also, ForgeGradle is a (kinda) separate project from Forge, and has its own wiki https://forgegradle.readthedocs.io/ Googling got me this: https://gist.github.com/matthewprenger/9b2da059b89433a01c1c Searching the FG git repo got me this: https://github.com/MinecraftForge/ForgeGradle/blob/c438b06df6339a6763e1549ebfa7b039100c1c0c/src/main/java/net/minecraftforge/gradle/tasks/SignJar.java#L94 Which delegates the signJar call to ant: https://ant.apache.org/manual/Tasks/signjar.html Which delegates the call to JDK jarsigner: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html
  15. The renderers for entities, apart from rendering themselves, also render a list of extra layers. For the player renderer, that would be the elytra, the cape, armor, arrows, held item, DeadMau5's ears, etc. Say I want to add one myself, for, say, rendering a cupcake on the player's head. Is this the correct approach to rendering extra stuff around vanilla entities? If not, which one is? If yes, how exactly does one add extra layers, when one doesn't have access to the RenderPlayer constructor, where they are added? There are Post and Pre render events, which seem viable, but do they have access to parameters that the LayerRenderer#doRenderLayer() method has (stuff like limbSwingAmount, etc)? RenderLivingBase#doRender(), which calls doRenderLayer() for all the layer, calculates all these parameters from the entity's fields. Thus one could calculate them for oneself in the event, but that seems wasteful since the values are already being calculated every tick.
  16. That may be the case, but there are other grave inefficiencies in the code. When you look at the variables' values after this block of code, you will find that two will have the same value (I think f4 and d6) and are calculated differently (=overhead). I made a more efficient version of it with a little hacked together benchmark (https://gitlab.com/snippets/1657880). Mojang Math.
  17. There's won't-fix about generic movement events here (https://github.com/MinecraftForge/MinecraftForge/issues/2859), but not closely related. Other than that no issues or PRs pertaining to elytra that are at least somewhat relevant. Can't see why instanceof wouldn't work, but it is so simple a solution there may well be some amendments. Thanks for the support
  18. Just a simple instanceof? I didn't think about that. Great, imma do that.
  19. The reference comparison is also made in NetHandlerPlayServer#processEntityAction for players. Another issue with that idea is that motion isn't everything, there are the client-side controller checks to start flying, the player renderer, the elytra model... all these things check EntityLivingBase#isElytraFlying. It just doesn't really seem feasible.
  20. Say I want to add elytra that behave motion-wise in a similar fashion of vanilla's but with some tweaks, say, custom colour or whatever. Every tick almost at the end of EntityLivingBase#onLivingUpdate, EntityLivingBase#updateElytra gets called, which checks for the one and only vanilla elytra by reference comparison, and if (not) present in the chest armour slot, is sets the 7-flag (elytra-flight) to true (false). The method updateElytra() gets called immediately before EntityLivingBase#moveEntityWithHeading, which calculates the motion of elytra flight, but only if flag-7 is true (through EntityLivingBase#isElytraFlying), so there is no point of entry to set the flag manually (in an armorTick or whatever). One could replace the player entity with a subclass that overrides EntityLivingBase#isElytraFlying, but that seems awkward to do. Coremodding can always be used, but never should. The last idea I have is just bailing on the vanilla code, and applying motion calculated by an equivalent (heh, copy&paste) algorithm directly from the custom item. This doesn't seem update-proof however, what if Mojang changes the algorithm? (Probs not an issue, but still) Lastly, if I decide to go with the third option, which seems the most sensible, what if the custom elytra are meant to be won in, say, the leggings slot, and the player simultaneously equips regular elytra? Any other ideas or arguments pro/contra my ideas are greatly appreciated.
  21. So I was looking at the code for elytra motion, and I found this: In net.minecraft.entity.EntityLivingBase#moveEntityWithHeading, in the isElytraFlying() if-clause, this happens: Vec3d vec3d = this.getLookVec(); float f = this.rotationPitch * 0.017453292F; double d6 = Math.sqrt(vec3d.xCoord * vec3d.xCoord + vec3d.zCoord * vec3d.zCoord); double d8 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); double d1 = vec3d.lengthVector(); float f4 = MathHelper.cos(f); f4 = (float)((double)f4 * (double)f4 * Math.min(1.0D, d1 / 0.4D)); this.motionY += -0.08D + (double)f4 * 0.06D; Looking at javadocs and stuff, getLookVec() returns a normalised vector. A few lines later, the length of that vector is calculated, and further down the line used in computations. Isn't the length of a normalised vector always 1?
  22. (The ItemModelEntry class can be static.) Can we get the class where the proxy is declared? Probs the main mod class.
  23. I was thinking about Problem 3, and something along the lines of this came to mind: During execution of the TE#onLoaded() method, we replace the TE's world field with a singleton instance of a delegate class to World, let's call that class WorldDelegateDormantLoad for now. This class will be constructed lazily for each world (maybe even stored inside the world object itself), and it will have the following properties: It will store the delegate world in one of its fields. The getChunk() (or similar) method will be modified. If the chunk is loaded, return it. If the queried chunk's coords are unloaded, then the chunk will be loaded into a Chunk object from disk, all Entities will be initialized, all TEs will have their TE#onLoad() (if there is one) run, but NOT TE#onLoaded() (this is the part that helps with cascading chunk loading), but its objects will not be added to the world, and it will be stored as a dormant chunk in forge's ChunkManager. If the chunk is dormant (includes the case when it was just dormant-loaded), then return it. All methods that reference the world's storage structures (loaded Entities, TEs) will be modified: If the requested position is loaded, then delegate the call to its delegate world. Otherwise, dormant-load it with getChunk() and query the TE/Entity/Block directly from the chunk object, and return it. Once the TE is done with its TE#onLoaded() logic, we replace the world with the original again. We repeat for all TEs in the chunk that is being loaded. We will also have to modify forge's dormant chunk manager to allow us to store chunks there even though the config might set it to zero. Alternatively, if the config disallows dormant chunks, we could just skip this patch and execute all cascading loads. If a chunk is loaded from the dormant cache by a regular world's loadChunk() call, we will add the chunk's objects to the world and execute all TE#onLoaded() methods prior to returning it for further processing. If a completely unloaded chunk is loaded by such a call, we let the current logic load it the standard way (with exception to doing the delegate thing with all TEs). This relies on the assumption that forge manages dormant chunks in an intelligent manner. If I understand the code correctly, dormant chunks are just chunk objects in memory with their members removed from the world, and they are prevented from ticking, which is ideal for this. This essentially attempts to do a sort of temp-load to the chunk without reloading chunks several times, which was the major caveat I think Queueing the operations is not a bad idea either, but there would have to be some sort of threshold since, without one, you could actually stand in a chunk that is still waiting for a cascaded call in a chunk which is currently unloaded. The best example in practice is a line of chunks, requesting data from the next one in line, longer than renderDistanceRadius.
  24. I was thinking about that, but two methods means two stages of loading, so it allows more interoperation between TEs. It's kinda like the loading stages, where you first do blocks/items, and only in init do you do recipes. That way, you can expect the processing in the earlier stage to be done, and build on the data generated by it in the second stage. Just looping twice at the call site would probably make more sense for this, though, since both calls would have world access. But limiting world access in the first stage is also not a bad idea, it gives the modder the opportunity to do stuff with their TE when it is loaded, but before other modders could interact with it. Still, might be a little too overcomplicated loading system for something like TEs. Would be great if people with more experience than me could express their opinion about the possible use-cases of this and if it would help in any way.
  25. Building against mods is just the case of getting the deobfuscated (deobf in short) mod file and adding it to the gradle compile configuration. All files in /libs are added to that configuration automagically as far as I can remember. Not sure about mods with a declared api.
×
×
  • Create New...

Important Information

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