Jump to content

Blazer Nitrox

Members
  • Posts

    29
  • Joined

  • Last visited

Posts posted by Blazer Nitrox

  1. When you say touching, do you mean which side they're bumping against, or which side they're clicking on?

     

    For clicking on, there's an event that gets fired (PlayerInteractEvent) that includes the face of the block they interacted with. Or, if you want a block to do something depending on which face the player interacts with, the Block class has onBlockActivated which takes a BlockRayTraceResult, which contains the side of the block that was clicked.

    For which side a player has run in to, that's a bit tricker. I don't think there's any event which gets fired off for that, so the easiest way would be to check PlayerTickEvent or some other similar event and just see if a player is colliding with any blocks, and then from there it'd be pretty simple (i.e. if the player is colliding with a block in the +x direction, then they must be touching the western face (since the block is to their east, the player is to the block's west)).

    • Like 1
  2. As the title says.

     

    A few months ago I had to mess around with creating my own texture atlas in order to render some GUI elements. A problem I ran into then, that didn't really fit the direction of the initial thread (which I'm also not really willing to necro at this point) is that despite the atlas registering itself as a reload listener with the texture manager, it doesn't get loaded at start up. It does, however, automatically reload any time a reload request is sent (either through changing resource packs or via F3+T). My interim solution was to simply request a reload in FMLLoadComplete. This is what we in the business call a "dumb solution."

     

    So: Where am I supposed to be registering the reload listener? I've been doing it in FMLClientSetup, but that was apparently too late, and the texture manager had already loaded (and for some reason doesn't like auto-loading any listeners that get added when they're added). I tried doing it in ModelBake, but that was also too late it seems.
    Near as I can tell, the TextureStitchEvent for each vanilla atlas is fired after FMLClientSetup, but before FMLLoadComplete.

     

    All of my searching both here and across Google has turned up nothing. What am I missing here?

  3. 5 hours ago, Solarient said:

    One more question!

    I am coding in forge 1.15.2 for a mod, say I were to upgrade to 1.16.1, would the API change in anyway? if so, what were the changes.

    There are absolute gods out there who occasionally make a TL;DR of the Forge changes and how to update to the newest version. 1.16 is still hot off the presses so it'll probably be a bit, but you can always download the MDK and troll through the provided code; except in rare circumstances (1.7 to 1.8, and 1.12 to 1.13) the changes are usually pretty small.

  4. 1a) Forge 1.12 is no longer supported, as in nobody on this forum is working on the 1.12 version, and so if you want support here you need to use a newer Forge version (most mods I've seen are updated to 1.15; you might give that a try.)

    1b) Your thread was locked by a mod for the above reason
    2) If you want to use 1.12 mods, I'd recommend downloading from CurseForge; if you need support with your mod setup, go over to the official Minecraft Forums. I'm not sure if they will be able to help you, but it's worth a try.

  5. 2 minutes ago, DavidM said:

    If your tree is not a tree (as in data structure; in your case it resembles a graph), then there is no need to separate the parent and child. Instead of keeping track of parent and children, create a set for all other connect nodes.

    Right, and that's how I've been doing it. I think you actually might have touched on the underlying problem... data structures have always kind of confused me for some reason, and I think part of the problem is in some ways I'm still thinking of this as a tree when in reality what I need is a graph, just with a pseudo-root node.

  6. @Draco18s I took another look at the advancements screen and realized I was a complete moron lol. I had been avoiding doing a proper parent/child hierarchy because I want the player to be able to loop around the tree like so:

    image.png.ac79200ae962b137e563f795d48e9f31.png

    (excuse the terrible quality, I threw this together in like 2 minutes in Paint because I didn't feel like waiting for GIMP to load)

    At the time, I had thought that a parent/child hierarchy wouldn't be capable of this because the last node in the sequence (top right) wouldn't have it's parent node active, and so it would think that it couldn't be activated. And I only just now realized that when the player tries to activate the node I could just... check if any child nodes are activated as well.
     

    All of this is to say that I've been a miserable fool who wasted his time because his solution was only half-baked. Nice.

  7. 6 minutes ago, Turtledove said:

    What stops you from knowing a node's position at runtime? Try to separate the concept of a node to anything related to your skill tree.

     

    If you can calculate/determine what skills a player knows at any time from player capabilities, access it from the GUI. Determine a pre-determined layout of the tree, like where a node will go (the physical node, not the skills attached to it) and where to draw arrows pointing to it. For example, if you have 40 skills in the tree, you could set up a lookup array of size 40 to determine if a node representing a particular skill should be drawn or not. This is the background layer. And in the foreground, overlay your skill name, description, etc over their respective positions. Then within the various mouse action methods, access this array whether it should detect player hovers/clicks there or not.

     

    This is something similar I've done, if a player doesn't want to have the third row for example, the node and the arrows pointing to it aren't drawn. Notice that some concessions needed to be made, like the length of the names (I've formatted the string so it's inside the node, but anything longer will make the text go over the boundary). But if I wanted to, I could even vary the size of each node and have a lookup table that tells me how large a certain node needs to be for a certain skill name.

     

    image.png.0ed0a18e21ed9ac582756a83bf9dbe71.png

    Under normal circumstances I would have done it that way, however I know that over time I'm going to be adding nodes to the tree (and potentially letting other mods add nodes to the tree as well), so I want to be able to programmatically add the nodes to the tree, meaning I won't know their textures or positions until they are registered. While it does mean I have to do more work in building the screen, theoretically it will also allow me to simply register a new node without having to modify the tree itself. It would also potentially allow me to create a tool later on which allows me to visually build the tree out and then simply export it as a JSON which the mod could then load, although it'll be a looong time before I pursue that route.

  8. Okay, having taken a bit to mess around with everything, I think I understand how I need to go about this. I did notice that SpriteUploader doesn't seem to have any markers for being called on reload, is there some way I should be registering it with the resource manager, or does it take care of that itself somewhere that I'm not seeing? There certainly doesn't appear to be any events I can attach to for registration or to manually call reload(), nor does TextureManager provide any such functionality.

  9. 9 hours ago, DavidM said:

    Few things to add:

    1. You might want to check out SpriteUploader.

    2. Check out AbstractGui::blit. It is the built-in method of rendering sprites with UV coords.

    3. You won't need to check on for the rendering thread if you are rendering in the Screen code (in the appropriate method).

     

    On an irrelevant note, almost everything in BufferBuilder as well as AtlasTexture (and a few other mentioned classes) has been deobfuscated on recent MCP mappings. You should consider updating your mappings if you find them obfuscated on your setup.

    Oh, hey! In the process of updating my MCP mappings I noticed that for some reason Forge was claiming it was 1.15 (and downloading Minecraft 1.15), but it was using the 1.14 MCP mappings, so I had no idea that AbstractGui#blit had a version which took a TextureAtlasSprite.

     

    So SpriteUploader seems to do exactly what I was originally expecting, with the added bonus of being able to be called whenever the resource engine reloads. That is very useful, although SpriteUploader#getSprite is set to protected, limiting its use pretty drasically IMHO. I assume the idea is that I would ask it to bind the texture atlas and then access the atlas directly from there.

     

    As far as checking the rendering thread, I figured that the relevant methods would always be called on the rendering thread, but since bindTexture does it I figured it wouldn't hurt.

     

    All of this has been extremely helpful, thanks a bunch!

  10. Okay, I did some poking around with AtlasTexture, and I think I figured out how to do what I need to. I'm going to record it here for future generations, and as a second post because it just doesn't make sense to me to combine this with the above, since they're mostly unrelated (and the separation will help identify this as me explaining what I think I need to do).

     

    AtlasTexture texture = new AtlasTexture(new ResourceLocation(MODID, "atlas"));
    Stream<ResourceLocation> stream = list.stream(); //We get a stream of all of the textures we want, probably using Collection#stream()
    SheetData data = texture.func_229220_a_((IResourceManager) Minecraft.getInstance().getTextureManager(), stream, Minecraft.getInstance().getProfiler(), 0); //Last argument is mipmap level, we use 0
    map.upload(data);

    So, first I must actually create a new AtlasTexture, passing in a ResourceLocation which will act as a registry name.
    Then, to actually generate the stitched texture, I must call AtlasTexture#func229220_a_. It seems I should pass in Minecraft.getInstance().getTextureManager() (which I can do because I'm specifically doing this on Dist.CLIENT) for the first argument, a Stream containing the ResourceLocation's of all of the textures I want to stitch (so this will be done after all of the nodes are registered, no surprise there), an IProfiler (whatever that is, it seems to be used to track the progress of the texture stitching), and an integer mipmapping level (I would assume I'd use either 0 or 1, since I won't need mipmapping for a GUI I don't think). I would capture the output of this and pass it to AtlasTexture#upload, which would actually create the texture information I would then use for drawing. At this point, the AtlasTexture is ready for use.

     

    if (!RenderSystem.isOnRenderThread()) {
    	RenderSystem.recordRenderCall(() -> {
    		manager.func_229263_a(texture.func_229223_g_(), texture);
          	texture.func_229148_d_();
    	});
    } else {
    	textureManager.func_229263_a(texture.func_229223_g_(), texture);
      	texture.func_229148_d();
    }

    When we first start drawing, we have to bind the texture. First, we must ensure we are actually on the rendering thread, and ask the rendering thread to do it if we aren't. Then we call TextureManager#func_229263_a, which takes two arguments, a ResourceLocation we want to use as a key for our AtlasTexture and the AtlasTexture itself.  We can cheat the first argument here by calling AtlasTexture#func_229223_g_, which is essentially getRegistryName. This will set up our texture so it's ready to be bound to OpenGL (the above is ripped directly from TextureManager#bindTexture). We then call Texture#func229148_d, which actually binds the texture.

     

    ((I would provide a code example, except that Screen doesn't seem to provide any way to draw textures using UV coordinates which is all TextureAtlasSprite provides, and directly drawing via OpenGL requires calling Tessellator to get a BufferBuilder, and none of the methods in BufferBuilder (or, for that matter, Screen) have been deobfuscated yet.))

     

    Now, in order to draw a texture from the Atlas onto the GUI, we call AtlasTexture#getSprite and pass in the key for the particular texture we want. That returns a TextureAtlasSprite, which contains the coordinates of our texture on the Atlas in absolute pixels as well as the relative min/max UV coordinates of our texture. Asking OpenGL to draw the part of the texture from min UV to max UV will draw our chosen texture and only that texture.

  11. I don't know of any tutorials which really lay it out for 1.15, but the Forge docs are helpful.

    First thing you'll need is a class which implements IRecipe<C extends IInventory>. When you create the recipe JSON (i.e. a crafting table recipe), that JSON will get converted into one of these objects. All the JSON says is what should be used as inputs and what should be used as outputs. Your object is a code representation of that data, which provides methods for getting the input list, checking if a given inventory matches your crafting requirements, getting the result of the crafting, and so on.

    Once you have that, you will need a factory which will take the provided JSON and convert it into your IRecipe object. The factory should extend ForgeRegistryEntry<IRecipeSerializer<?>> and implement IRecipeSerializer<((whatever your IRecipe class is))>. The factory will have methods for getting the recipe from either JSON or from the network, and will produce your IRecipe object.

     

    I hope I've helped to clarify some. As I said, the docs are a great resource (when they actually have what you're looking for, that is), and a lot of what my code is based on what I've read from the docs, examples I've found online, or just trolling through Minecraft's code until I find what I'm looking for.

  12. 29 minutes ago, DavidM said:

    You could specify the position of the node as part of its data, which should be part of the instance you use as the registry entry, and draw each node according to its position data. This allows you (as well as other mods that use your mod) to have more control over where the newly added nodes should appear. This also circumvents the "dynamically position the node and draw line between" problem.

    That's what I'm doing, sorry I didn't make that clear. As part of the node's data I've got the position and the resource location for the appropriate texture. My main concern was that since I won't know where the node will be located until it gets registered I can't just include the path as part of the background texture, so I would have to dynamically draw it.

     

    32 minutes ago, DavidM said:

    Directly using OpenGL should be the easier approach, as it has more flexibility (and Screen uses OpenGL anyways). Create a texture of a line and scale/rotate it to point it to other nodes. Some trigonometry will be needed.

    I suspected this would be the case, but thanks for confirming it. I assume I can still use Screen for a convenient way to access the GUI, and then override the various rendering methods in order to actually draw what I need?

    Side note: how did you code-ify `Screen`?

  13. Okay, so admittedly this is a really complex thing I'm trying to do, but I figure I'd learn some things along the way, so I decided to give it a shot.

    My goal is to recreate something like a skill tree in Minecraft. Specifically, my inspiration comes from the Passive Skill Tree in Path of Exile. I definitely do NOT expect to replicate the kind of complexity they've got, as the skill tree has evolved over the course of many years.
    I've (mostly) figured out my implementation for the skill tree, and now I need to have a GUI allowing the player to actually allocate their skill points. This, unfortunately, seems to be much harder than the tree implementation itself, while also being extremely important to using the tree (I suppose I could implement the whole thing using commands, but I'm going to have to create a GUI at some point so I might as well ask now).

    Currently, I'm trying to future-proof by using a custom registry for my SkillNodes. While this will allow me to easily add nodes programmatically (and will allow other mods to expand upon the skill tree), it also means that I have no way of knowing what nodes will need to be drawn to the tree at compile time, so I have to dynamically generate the GUI. I likewise have no way of knowing what positions I will need to draw the nodes' textures at, which means I won't know until runtime how long I will need to make the paths between each node.


    So, here are my questions:
    1.  I expect I will need to take advantage of Minecraft's built-in texture stitching, that way I don't have to rebind the texture every time I draw a node. Near as I can tell, there is no built-in GUI TextureAtlas, so I would need to create my own. How would I go about doing that, and would it need to be registered somewhere in order to still fire TextureStitchEvents?
    2a.  Since I also don't know each node's position until runtime, I will need to dynamically draw the paths between them, which means I won't know the lengths of each path and therefore can't just draw a texture 1:1 between each node.

    2b. I would like to make the paths straight lines between each node, which means I could potentially be dealing with diagonals as well. Can  `Screen` handle either of these scenarios, or would I need to directly access OpenGL?

     

    This situation is something I'm not very experienced with at all, so please bear with me. I'll probably be asking several more questions to make sure I understand what I need to do here.

    And as I said, I know I'm probably biting off more than I can chew, but I find that I learn best by bodging a solution together at first and then rewriting it with the knowledge I gained.

     

     

  14. 19 minutes ago, Turtledove said:

    It's got nothing to do with how I'm writing/reading nbt data within the data provider class, I'm 100% certain of that, plus it implements ICapabilitySerializable and doesn't rely on strings as tags.

    OH, I CapabilitySerializable! I'll be honest, I haven't messed with it, as I could never seem to find any resources for how to use it. I honestly just have an interface defining methods for reading to/writing from NBT, and then use those in my ICapabilityStorage implementation. I'm pretty sure what I'm doing violates diesieben07's coding guidelines, but it's how I first learned to do it back in... was it 1.10?

    Anyway, I'm going to defer to DavidM's judgement here, as he's clearly more experienced than I.

    • Like 1
  15. 8 hours ago, Cadiboo said:

    Ah. Remove that hack and override getSpawnPacket or whatever it’s called in your entity and return NetworkHooks.getSpawnPacket(this) (I think)

    Yep, that fixed it. It's NetworkHooks.getEntitySpawningPacket(this), btw.

     

    Thanks a bunch for your help. Hopefully something can be done about the official documentation once the API's settled down a bit more.

     

  16. So, uh... I think I discovered the problem.

     

    In net.minecraft.client.renderer.WorldRenderer#func_228428_a_:

    Breakpoint on line 944 shows that this line is never reach where `entity` is an EntityDart, even if one exists in the world. Problem is, the line immediately before it (943):

    for(Entity entity : this.world.getAllEntities()) {

     

    So... somehow... my EntityDart doesn't exist in the client-side world.

    Interesting.

    And AFAIK I'm not overriding anything that would be taking care of that - it should be doing it on its own.

     

    -----EDIT #2-----

    Well, this rabbit hole just goes deeper and deeper. I stumbled across FMLPlayMessages.SpawnEntity, and realize "oh, hey, I can just use this!" And then I realized, "shouldn't this already be called?"

    Lo and behold, it's not. I have yet to figure out what should be sending the SpawnEntity packet, but it isn't doing its job - it never trips any of the breakpoints I put in it.

    In the mean time, I'm going to attempt to build my own implementation and see if that accomplishes anything at all.

     

    -----EDIT #3-----

    Well, I finally got something to render. I ended up implementing my own packet specific to my entity and had ItemDart send it when it constructed the entity. It's super dirty (the best I could figure for who to send the packet to was just anybody tracking the chunk the dart was in), but it works... which begs the question of why FMLPlayMessages.SpawnEntity wasn't doing its job. I dunno, but at least I got something to show up on my gorram screen.

  17. 19 minutes ago, luquo said:

    I´m currently playing ftb Infinity Evolved, shaders work fine in single player but when I join my creeper host server and use shaders the game crashes about 10 seconds later.

     

    Here´s the crashlog

     

    [REDACTED for sanity's sake]

     

    Thanks in advance!!

    First, please put your crash logs into spoilers (or upload them to PasteBin).

     

    Second, this is something you should bring up with either the GLSL Shaders Mod or the FTB Infinity Evolved support crew (probably Shaders Mod since it's a problem specifically with shaders).

     

    Third, this is the mod development forum, not the general user support forum. That would be in the "Support & Bug Reports" section.

  18. 8 hours ago, Cadiboo said:

    I was in a hurry when I wrote that and I noticed your setting/getting item refs and thought it could be an issue. I’m not sure what the issue is, can you please post your code on GitHub?

     

    Sure thing :) I think you noticed the same thing I did, but near as I can tell the itemRef should be fine, since I'm instantiating ItemDart multiple times, once for each item instance.

    Here's that GitHub repo. I appreciate the help!

  19. Oh :P Am big dumb. I see what you mean about singletons now, although that doesn't seem to be the cause of my current issue - it's never getting far enough to have undefined behavior. I know for a fact that my DartRenderer isn't being called from debug calls, and stepping through shows that indeed neither is ArrowRenderer. Near as I can figure, I somehow convinced Minecraft that I don't have any renderer registered for the entity, although I don't see anything in the logs that would indicate that.

     

    Actually, looking back on it, I'm still treating the items as though they're singletons... where were you seeing behavior that indicates otherwise?

  20. Entities, Renderers, and Registers, oh my!

     

    So the gist of the issue right now is that I've created a custom arrow (ItemDart) that is just an ArrowItem modified to allow for setting the damage an arrows does and what item the arrow should give when picked up by the player (otherwise it would always return an arrow). This then creates a custom AbstractArrowEntity (EntityDart) which takes the reference item and returns it in getArrowStack. Then, to render that entity, I have a custom ArrowRenderer (DartRenderer) which overrides getEntityTexture and returns a ResourceLocation whose path is generated based on the item the EntityDart refers to.

     

    Two problems. First, DartRenderer is being constructed as it should when registered, but isn't being called in order to render the EntityDart. Second, EntityDart no longer has a renderer, as it seems not even ArrowRenderer is being called for it.

     

    As always, here are the relevant bits of code. Some of this is kind of messy simply because I'm relearning Forge (and its best practices) for the first time, so if something is blatantly wrong, please let me know.

    ItemDart

    Spoiler
    
    package io.github.tntftw21.agab.item;
    
    import io.github.tntftw21.agab.entity.EntityDart;
    import net.minecraft.entity.LivingEntity;
    import net.minecraft.item.ArrowItem;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.RegistryObject;
    
    /**
     * A version of ArrowItem which allows for custom damage values as well as
     * having the resultant entity drop its respective dart (i.e. EntityStoneDart can drop a stone
     * instead of a wooden one)
     *
     * @author TNTftw21
     */
    public class ItemDart extends ArrowItem {
        
        /**
         * The amount of damage this Dart does by default.
         */
        public final float damage;
        
        private RegistryObject<Item> ref;
    
        /**
         *
         * @param properties Default Item.Properties
         * @param damageIn Amount of damage this dart deals as base (will be multiplied by projectile velocity later!)
         */
        public ItemDart(Properties properties, float damageIn) {
            super(properties);
            this.damage = damageIn;
        }
        
        /**
         * Set an internal reference to the represented item.
         * This is needed specifically for ensuring that EntityDart drops the correct dart item.
         * @param refIn a RegistryObject for building the Item
         * @returns Reference to this object, for method chaining
         */
        public ItemDart setItemReference(RegistryObject<Item> refIn) {
            this.ref = refIn;
            return this;
        }
        
        /**
         * Create an ArrowEntity representing this Item.
         * @returns the relevant Entity (in this case EntityDart) for use by the firing tool.
         */
        @Override
        public EntityDart createArrow(World worldIn, ItemStack stack, LivingEntity shooter) {
            EntityDart arrowentity = new EntityDart(shooter, worldIn, ref.get());
            arrowentity.setDamage(this.damage);
            return arrowentity;
        }
    
        /**
         * @returns whether the Dart is infinite and, therefore, whether one should be expended upon firing.
         */
        // We override this method here because the version in ArrowItem *directly* compares against ArrowItem.class, rather than this more flexible check.
        @Override
        public boolean isInfinite(ItemStack stack, ItemStack bow, net.minecraft.entity.player.PlayerEntity player) {
            int enchant = net.minecraft.enchantment.EnchantmentHelper.getEnchantmentLevel(net.minecraft.enchantment.Enchantments.INFINITY, bow);
            return enchant <= 0 ? false : this instanceof ArrowItem;
        }
    
    }

     

    EntityDart (I'll do JavaDocs on this once I get it working lol):

    Spoiler
    
    package io.github.tntftw21.agab.entity;
    
    import io.github.tntftw21.agab.AGAB;
    import io.github.tntftw21.agab.init.ModEntityTypes;
    import net.minecraft.entity.EntityType;
    import net.minecraft.entity.LivingEntity;
    import net.minecraft.entity.projectile.AbstractArrowEntity;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    
    public class EntityDart extends AbstractArrowEntity {
    
        private final Item referenceItem;
    
        @SuppressWarnings("unchecked")
        public EntityDart(EntityType<?> type, World world) {
            super((EntityType<? extends AbstractArrowEntity>) type, world);
            this.referenceItem = null;
        }
        
        public EntityDart(LivingEntity shooter, World world, Item referenceItemIn) {
            super(ModEntityTypes.DART.get(), shooter, world);
            this.referenceItem = referenceItemIn;
        }
    
        @Override
        public ItemStack getArrowStack() {
            AGAB.LOGGER.debug("Getting Arrow Stack");
            return new ItemStack(this.referenceItem);
        }
    
    }

     

    DartRenderer:

    Spoiler
    
    package io.github.tntftw21.agab.client.render;
    
    import io.github.tntftw21.agab.AGAB;
    import io.github.tntftw21.agab.entity.EntityDart;
    import net.minecraft.client.renderer.entity.ArrowRenderer;
    import net.minecraft.client.renderer.entity.EntityRendererManager;
    import net.minecraft.item.Item;
    import net.minecraft.util.ResourceLocation;
    
    /**
     * Custom ArrowRenderer for EntityDart. Designed to be usable with all Dart types.
     * 
     * @author TNTftw21
     */
    public class DartRenderer extends ArrowRenderer<EntityDart> {
    
    	public DartRenderer(EntityRendererManager renderManagerIn) {
    		super(renderManagerIn);
    	}
    
    	@Override
    	public ResourceLocation getEntityTexture(EntityDart entity) {
    		Item refItem = entity.getArrowStack().getItem();
    		return new ResourceLocation(AGAB.MODID, "textures/entity/projectile/" + refItem.getRegistryName().getPath());
    	}
    
    }

     

    This next few I'm included because the problem might be something to do with how I'm registering everything. To be frank, for the life of me I couldn't find any explanation as to how Entity/Renderer registration is done, so I lifted some code of the Web (Thanks, Cadiboo!) and modified it until it """worked""".

    ModItems:

    Spoiler
    
    package io.github.tntftw21.agab.init;
    
    import io.github.tntftw21.agab.AGAB;
    import io.github.tntftw21.agab.item.ItemAtlatl;
    import io.github.tntftw21.agab.item.ItemDart;
    import net.minecraft.item.Item;
    import net.minecraftforge.fml.RegistryObject;
    import net.minecraftforge.registries.DeferredRegister;
    import net.minecraftforge.registries.ForgeRegistries;
    
    public class ModItems {
    	
    	public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, AGAB.MODID);
    
    	//public static final RegistryObject<Item> EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties().group(ModItemGroups.MOD_ITEM_GROUP)));
    	public static final RegistryObject<Item> WOODEN_ATLATL = ITEMS.register("wooden_atlatl", () -> new ItemAtlatl(new Item.Properties().group(ModItemGroups.AGAB_WEAPONS).maxDamage(288), 1.33F));
    	public static final RegistryObject<Item> ENHANCED_ATLATL = ITEMS.register("enhanced_atlatl", () -> new ItemAtlatl(new Item.Properties().group(ModItemGroups.AGAB_WEAPONS).maxDamage(288), 1.75F));
    	
    	public static final RegistryObject<Item> WOODEN_DART = ITEMS.register("wooden_dart", () -> new ItemDart(new Item.Properties().group(ModItemGroups.AGAB_WEAPONS), 1.5F));
    	public static final RegistryObject<Item> STONE_DART = ITEMS.register("stone_dart", () -> new ItemDart(new Item.Properties().group(ModItemGroups.AGAB_WEAPONS), 1.75F));
    	
    }

     

     

    ClientModEventSubscriber:

    Spoiler
    
    package io.github.tntftw21.agab.client;
    
    import io.github.tntftw21.agab.AGAB;
    import io.github.tntftw21.agab.client.render.DartRenderer;
    import io.github.tntftw21.agab.init.ModEntityTypes;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.eventbus.api.SubscribeEvent;
    import net.minecraftforge.fml.client.registry.RenderingRegistry;
    import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
    import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
    
    @EventBusSubscriber(modid = AGAB.MODID, bus=EventBusSubscriber.Bus.MOD, value=Dist.CLIENT)
    public class ClientModEventSubscriber {
    
    	@SubscribeEvent
    	public static void onClientSetup(final FMLClientSetupEvent event) {
    		RenderingRegistry.registerEntityRenderingHandler(ModEntityTypes.DART.get(), DartRenderer::new);
    	}
    
    }

     

     

    ModEntityTypes:

    Spoiler
    
    package io.github.tntftw21.agab.init;
    
    import io.github.tntftw21.agab.AGAB;
    import io.github.tntftw21.agab.entity.EntityDart;
    import net.minecraft.entity.EntityClassification;
    import net.minecraft.entity.EntityType;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fml.RegistryObject;
    import net.minecraftforge.registries.DeferredRegister;
    import net.minecraftforge.registries.ForgeRegistries;
    
    public class ModEntityTypes {
    
    	public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = new DeferredRegister<>(ForgeRegistries.ENTITIES, AGAB.MODID);
    	
    	public static final String DART_NAME = "dart";
    	public static final RegistryObject<EntityType<EntityDart>> DART = ENTITY_TYPES.register("dart",
    			() -> EntityType.Builder.<EntityDart>create(EntityDart::new, EntityClassification.MISC).size(0.5F, 0.5F).build(new ResourceLocation(AGAB.MODID, DART_NAME).toString()));
    
    }

     

     

    I'm not including them, but I am initializing the DeferredRegistries in my main mod file's constructor. Also, I'm calling ItemDart#setItemReference in my main EventSubscriber class's item register event, as according to my testing the deferred register fires before the registry event does. That being said, I have no idea if that a safe assumption to make in the wild, so I intend to test that a big more unless someone can shoot it down right here.

     

    As far as I know, everything should be working properly. At the very least, Minecraft seems to know that EntityDart is using a custom renderer, but it's not properly attaching it. I haven't seen any related errors in the logs, however. I'd include debug.log, but Forge insists on generating a 3M dump of every single class it loads and I've yet to find a way to tell it to not.

  21. 6 hours ago, desht said:

    If you need proof, look at ShapedRecipe#deserializeItem(), where the "data" field is explicitly disallowed.

     

    This is due to the Flattening: item and block data is no longer a thing as of Minecraft 1.13 (which is great).  See https://gist.github.com/williewillus/353c872bcf1a6ace9921189f6100d09a#whats-the-deal-with-metadata

    Yeah, I had noticed that when I was reading through his document. I gotta admit, part of me is sad to see magic metadata numbers go, if only for nostalgia's sake. On the other hand, I would much rather avoid magic numbers entirely.

     

    9 hours ago, Cadiboo said:

    That’s the way it was in 1.12.2, it changed in 1.13

    Yeah, I'm loving the changes you guys made so far. Now that I'm getting used to it again everything feels a lot... I dunno, cleaner? It just seems like a much nicer experience than it used to be

     

    Oh, I suppose I should mark this solved now lol

×
×
  • Create New...

Important Information

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