jabelar
Members-
Posts
3266 -
Joined
-
Last visited
-
Days Won
39
Everything posted by jabelar
-
Well,. You're copying not extending the built-in Ghast. So it is up to you to put all the AI code in. You might want to consider extending the ghast instead in case there is other code that looks for instanceof the ghast and you want your ghast to be treated the same. Anyway, you need to copy or extend. If you're copying then you need to copy all the methods from EntityGhast and then customize them. You need to copy the initEntityAI() method for example and maybe you missed some others.
-
I've been bashing my head on this for a bit and need help. So I have been revisiting fluids and got them working pretty nicely. So I decided to practice making a custom fluid handler item (called a "slime bag" as my fluid is "slime") and it also generally works: 1) In the creative tab (misc) it shows both the empty and full items with proper model (right now I'm using a bucket texture) 2) Using the full item places a fluid block in the world, using an empty item can fill if it is used on a fluid block 3) The model in the player hotbar properly reflects filling and emptying. However, if I save and load all the items in the player inventory are empty. Not only do they look empty (empty model and also display name just says "Bag" which indicates empty) but it also behaves as empty (can't place fluid but can pick it up). Now I know that capabilities might need work to sync across to client, and it is likely related to this problem, but I have a couple questions about that. Q1) If you use an itemstack in the client, but the function of the item is to do something on the server side, doesn't the server have a sense of what is supposed to be in the inventory and wouldn't it process accordingly? Like even though the itemstack looks empty on client, wouldn't the server treat it as being filled (since it should have saved as filled)? In other words, is my problem a client sync problem or a server save problem? Q2) What is the proper way to sync a built-in capability like fluid handling for an itemstack to client? I'm pretty familiar with packets, but I thought a capability with IStorage adds to the ItemStack NBT and I thought NBT data is already synced through various vanilla packets. Any advice here is appreciated. Q3) Possibly related, but when I trace my code using console outputs I see that my item's initCapabilities is being called repeatedly and continuously by both server and Netty server whevever my itemstack is being displayed (e.g. looking at creative menu). I thought it would be only called when an ItemStack is created, so I'm guessing that somewhere the ItemStack is getting copied / recreated. Since the Netty server is doing it, I assume it has to do with packets?
-
[1.12.1] Question about ModelBakeEvent and "baking" in general
jabelar replied to jabelar's topic in Modder Support
Okay, got my custom item model working! Do have a question though. You said that "ModelBakeEvent" is virtually never needed. However, in code that I've seen (and in my case copied) that event is still handled to setCustomMeshDefinition() for the loader and registerItemVariants() to the bakery. I tried not doing that and it then doesn't find the model. Are those two methods supposed to be done in the ModelBakeEvent, or are they supposed to be done in the ModelRegistryEvent? Or does it matter? -
[1.12.1] Question about ModelBakeEvent and "baking" in general
jabelar replied to jabelar's topic in Modder Support
Thanks so much for the detailed explanation. I've also been tracing the execution last night and some of this is becoming a lot clearer now, especially the order of the operations. I'm sure I'll have some follow on questions as I work through it a bit more... -
As mentioned by Draco, imagine using a capability on the player (or special item) that stores pairs of coordinates for linked TEs. As you place the TEs you'd record their location and then when you want to teleport you look it up. If the portals are meant to be used by multiple players then you might want to attach the data to the world instead, maybe as world save data or even just use your own Java file handling code to store it. The only trick is you also need to maintain the lists in the case where the TEs get destroyed or something.
-
I have to say that although I agree modders have to keep up to date, it is also very difficult to keep up with all the changes. For example, I was looking at some code for a fairly recent mod by another strong modder and his item model implemented IModel, ICustomModelLoader, and IRetexture and the last two were not in my class path. I did some digging and it looks like those interfaces were absorbed directly into IModel so you don't have to implement all three. But these changes just happened going from 1.11 (his code) and 1.12. As someone who writes tutorials to help people it is becoming almost impossible to keep tutorials up to date. For example, over past couple years custom item models have gone from using item mesher, being registered in pre-init etc. to now using JSON with IModel and being registered in a combination of item registry, model registry and model bake event. Literally 1.9 is different from 1.10 from 1.11 to 1.12 ... In other words, all the really good tutorials and all the github repositories out there are all getting outdated about every six months and there is no easy way for someone who is new, or someone who comes back to modding occasionally, to sort it all out. Furthermore, updating my existing mods is becoming a full time job for me. For example, I just ported my entity-based mods to 1.12.1 and now I see pull requests where they are about to change the entity registration scheme. The IEEPs became capabilities, all the achievements have become advancements, etc. So honestly giving someone a hard time for using a one year old approach, or calling tutorials out there "outdated crap" I think isn't very fair. Forge is becoming extremely "unstable" -- I don't mean buggy, just that the API is changing rapidly. And frankly in programming an API that changes rapidly is a bad thing in terms of maintainability. This is causing real trouble because all the kids I ask about which version of Minecraft they use are saying 1.7.10. That seems to have been the golden age for mods. In particular my kids seem to like the Morph mod. It is creating a situation where it is difficult for people to find a combination of Minecraft and mods that has everything they like. Having colors and parrots isn't enough for people to give up their favorite mods...If you look at the Minecraft Forum Modification Development forum you'll see that almost half the question are from people still developing for 1.7.10.
-
The most important thing is actually your file names and locations of your assets. Also, I know that previously it was a bad idea to use upper case letters in any of your registry names or asset file names. So you need to: change Riptide_Sword to riptide_sword and change RIPTIDESWORD to riptidesword and make sure all your file names match these as well. If you're still having problems after that you need to post a screen shot of your assets directory so we can see all the file names and locations. Also, you are probably getting warntings in the console about missing models or textures so you should post the console log as well.
-
So I've been revisiting modding with fluids and that is going reasonably, but I wanted to try making an item fluid handler and that works fine too except I wanted to make the texture change based on whether it is full or not (like a UniversalBucket). So I looked at the ModelDynBucket and tried to follow that, but now running into a few things I have questions about. First of all, I think the concept of "baking" simply means that you take in a base model and have an opportunity to transform it (or replace it) based on custom state data. Is that a correct way to describe it? So I have a bunch of related classes, the IModel, and ICustomModelLoader, an IBakedModel, and an ItemOverrideList. But I'm getting confused about how these all work together. Starting with the ModelRegistryEvent and ModelBakeEvent. So am I supposed to handle both of these? Like register my IModel in the ModelRegistryEvent and then do something to transform/bake it during the ModelBakeEvent? Or since I have a baked model do I skip the ModelRegistryEvent and just do something in the ModelBakeEvent? Or is the ModelBakeEvent fired after all the baking is done and meant to allow processing after the baking? ... I looked at a bunch of github repositories and most mods seem to use ModelBakeEvent for doing things like replacing other mod's models and stuff and i don't see a lot of baking going on within the event handlers.... IIf I look at the bake() method it takes a parameter called IModelState but this seems to be unrelated to the item state but rather is a way to represent a bunch of transforms Also, should I be registering the IModel or an IBakedModel? And in the ModelBakeEvent is it just about registering, or do I need to call the bake() method in my IModel somehow? The bake() method takes a bunch of parameters I don't think I really have access to. So I think the bake() method is called automatically by the handleItemState(0 method of my IItemOverrideList class which also is the one that will check the state and change the texture of my item accordingly. So is handleItemState() called during the game play or is it called once (per permutation of possible custom states) during the model loading phase of starting the game? And are JSONs involved with any of this? For the UniversalBucket that I'm mostly copying there does appear to be a blockstates file for it, but it doesn't seem to have much interesting in it... So many questions!!! My most pressing question is what should I register or do in the ModelRegistryEvent and ModelBakeEvent? Here is my current code for the classes involved: package com.blogspot.jabelarminecraft.examplemod.client.models; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; import javax.annotation.Nullable; import javax.vecmath.Matrix4f; import org.apache.commons.lang3.tuple.Pair; import com.blogspot.jabelarminecraft.examplemod.MainMod; import com.blogspot.jabelarminecraft.examplemod.init.ModFluids; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.block.model.ItemOverrideList; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.resources.IResourceManager; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.model.ICustomModelLoader; import net.minecraftforge.client.model.IModel; import net.minecraftforge.client.model.ItemLayerModel; import net.minecraftforge.client.model.ItemTextureQuadConverter; import net.minecraftforge.client.model.PerspectiveMapWrapper; import net.minecraftforge.client.model.SimpleModelState; import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.TRSRTransformation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidUtil; public final class ModelSlimeBag implements IModel { public static final ModelResourceLocation LOCATION = new ModelResourceLocation(new ResourceLocation(MainMod.MODID, "slime_bag"), "inventory"); // minimal Z offset to prevent depth-fighting private static final float NORTH_Z_FLUID = 7.498f / 16f; private static final float SOUTH_Z_FLUID = 8.502f / 16f; public static final ModelSlimeBag MODEL = new ModelSlimeBag(); @Nullable private final ResourceLocation emptyLocation = new ResourceLocation(MainMod.MODID, "slime_bag_empty"); @Nullable private final ResourceLocation filledLocation = new ResourceLocation(MainMod.MODID, "slime_bag"); @Nullable private final Fluid fluid; public ModelSlimeBag() { this(ModFluids.SLIME); } public ModelSlimeBag(Fluid parFluid) { fluid = parFluid; } @Override public Collection<ResourceLocation> getTextures() { ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder(); if (emptyLocation != null) builder.add(emptyLocation); if (filledLocation != null) builder.add(filledLocation); return builder.build(); } @Override public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) { ImmutableMap<TransformType, TRSRTransformation> transformMap = PerspectiveMapWrapper.getTransforms(state); TRSRTransformation transform = state.apply(Optional.empty()).orElse(TRSRTransformation.identity()); TextureAtlasSprite fluidSprite = null; ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder(); if(fluid != null) { fluidSprite = bakedTextureGetter.apply(fluid.getStill()); } if (emptyLocation != null) { // build base (insidest) IBakedModel model = (new ItemLayerModel(ImmutableList.of(emptyLocation))).bake(state, format, bakedTextureGetter); builder.addAll(model.getQuads(null, null, 0)); } if (filledLocation != null && fluidSprite != null) { TextureAtlasSprite liquid = bakedTextureGetter.apply(filledLocation); // build liquid layer (inside) builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, EnumFacing.NORTH, fluid.getColor())); builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, EnumFacing.SOUTH, fluid.getColor())); } return new Baked(this, builder.build(), fluidSprite, format, Maps.immutableEnumMap(transformMap), Maps.newHashMap()); } /** * Sets the liquid in the model. * fluid - Name of the fluid in the FluidRegistry * If the fluid can't be found, water is used */ @Override public ModelSlimeBag process(ImmutableMap<String, String> customData) { String fluidName = customData.get("fluid"); Fluid fluid = FluidRegistry.getFluid(fluidName); if (fluid == null) fluid = this.fluid; // create new model with correct liquid return new ModelSlimeBag(fluid); } /** * Allows to use different textures for the model. * There are 3 layers: * base - The empty bucket/container * fluid - A texture representing the liquid portion. Non-transparent = liquid * cover - An overlay that's put over the liquid (optional) * <p/> * If no liquid is given a hardcoded variant for the bucket is used. */ @Override public ModelSlimeBag retexture(ImmutableMap<String, String> textures) { // don't allow retexturing return new ModelSlimeBag(fluid); } public enum CustomModelLoader implements ICustomModelLoader { INSTANCE; @Override public boolean accepts(ResourceLocation modelLocation) { return modelLocation.getResourceDomain().equals(MainMod.MODID) && modelLocation.getResourcePath().contains("slime_bag"); } @Override public IModel loadModel(ResourceLocation modelLocation) { return MODEL; } @Override public void onResourceManagerReload(IResourceManager resourceManager) { // no need to clear cache since we create a new model instance } } private static final class BakedOverrideHandler extends ItemOverrideList { public static final BakedOverrideHandler INSTANCE = new BakedOverrideHandler(); private BakedOverrideHandler() { super(ImmutableList.of()); } @Override public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity) { FluidStack fluidStack = FluidUtil.getFluidContained(stack); // not a fluid item apparently if (fluidStack == null) { // DEBUG System.out.println("fluid stack is null, returning original model"); // empty bucket return originalModel; } // DEBUG System.out.print("Fluid stack was not null and fluid amount = "+fluidStack.amount); Baked model = (Baked)originalModel; Fluid fluid = fluidStack.getFluid(); String name = fluid.getName(); if (!model.cache.containsKey(name)) { // DEBUG System.out.println("The model cache does not have key for fluid name"); IModel parent = model.parent.process(ImmutableMap.of("fluid", name)); Function<ResourceLocation, TextureAtlasSprite> textureGetter; textureGetter = location -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString()); IBakedModel bakedModel = parent.bake(new SimpleModelState(model.transforms), model.format, textureGetter); model.cache.put(name, bakedModel); return bakedModel; } // DEBUG System.out.println("The model cache already has key so returning the model"); return model.cache.get(name); } } // the filled bucket is based on the empty bucket private static final class Baked implements IBakedModel { private final ModelSlimeBag parent; // FIXME: guava cache? private final Map<String, IBakedModel> cache; // contains all the baked models since they'll never change private final ImmutableMap<TransformType, TRSRTransformation> transforms; private final ImmutableList<BakedQuad> quads; private final TextureAtlasSprite particle; private final VertexFormat format; public Baked(ModelSlimeBag parent, ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format, ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms, Map<String, IBakedModel> cache) { this.quads = quads; this.particle = particle; this.format = format; this.parent = parent; this.transforms = transforms; this.cache = cache; } @Override public ItemOverrideList getOverrides() { return BakedOverrideHandler.INSTANCE; } @Override public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType) { return PerspectiveMapWrapper.handlePerspective(this, transforms, cameraTransformType); } @Override public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { if(side == null) return quads; return ImmutableList.of(); } @Override public boolean isAmbientOcclusion() { return true; } @Override public boolean isGui3d() { return false; } @Override public boolean isBuiltInRenderer() { return false; } @Override public TextureAtlasSprite getParticleTexture() { return particle; } } }
-
[1.12.1] Question about how the UniversalBucket models and textures work
jabelar replied to jabelar's topic in Modder Support
Nevermind, I see it has a custom model loader. I guess I missed it when I was looking through before... -
I was looking at the assets for Forge for the universal bucket and i'm a bit confused. If I follow the constructor for UniversalBucket I see it is called during the item registry event where it is given the registry name "bucketfilled". However, in the assets I can't find anything by that name. There is an model called bucket.json which contains: { "parent": "item/generated", "textures": { "layer0": "forge:items/bucket_base" } } and there are three textures called bucket_base.png, bucket_cover.png, and bucket_fluid.png. But I don't see how the model above enables those other parts (i.e. making it look filled). Also there is a blockstate json called dynbucket.json that contains: { "forge_marker": 1, "variants": { "inventory": { "model": "forge:forgebucket", "textures": { "base": "forge:items/bucket_base", "fluid": "forge:items/bucket_fluid", "cover": "forge:items/bucket_cover" }, "transform": "forge:default-item", "custom": { "fluid": "water", "flipGas": true } } } } but the weird thing about that is that it references a model called forge:forgebucket which doesn't exist (at least in these asset paths). So what's going on -- none of these really match up. Is there some other asset directory for Forge? Or is UniversalBucket getting it's models and textures in another way?
-
If you're interested in the type rather than the biomes itself, you could just iterate through the registered biomes and grab all the unique types and build up a list that way.
-
If you suscribe to the biome registry event, you can use event.getRegistry().getKeys() to get a set of all the biomes. For example I just tried it and simply printed the result to the console and got: [18:15:49] [main/INFO] [STDOUT]: [com.blogspot.jabelarminecraft.examplemod.init.ModBiomes$RegistrationHandler:onEvent:64]: Registry key set = [minecraft:ocean, minecraft:plains, minecraft:desert, minecraft:extreme_hills, minecraft:forest, minecraft:taiga, minecraft:swampland, minecraft:river, minecraft:hell, minecraft:sky, minecraft:frozen_ocean, minecraft:frozen_river, minecraft:ice_flats, minecraft:ice_mountains, minecraft:mushroom_island, minecraft:mushroom_island_shore, minecraft:beaches, minecraft:desert_hills, minecraft:forest_hills, minecraft:taiga_hills, minecraft:smaller_extreme_hills, minecraft:jungle, minecraft:jungle_hills, minecraft:jungle_edge, minecraft:deep_ocean, minecraft:stone_beach, minecraft:cold_beach, minecraft:birch_forest, minecraft:birch_forest_hills, minecraft:roofed_forest, minecraft:taiga_cold, minecraft:taiga_cold_hills, minecraft:redwood_taiga, minecraft:redwood_taiga_hills, minecraft:extreme_hills_with_trees, minecraft:savanna, minecraft:savanna_rock, minecraft:mesa, minecraft:mesa_rock, minecraft:mesa_clear_rock, minecraft:void, minecraft:mutated_plains, minecraft:mutated_desert, minecraft:mutated_extreme_hills, minecraft:mutated_forest, minecraft:mutated_taiga, minecraft:mutated_swampland, minecraft:mutated_ice_flats, minecraft:mutated_jungle, minecraft:mutated_jungle_edge, minecraft:mutated_birch_forest, minecraft:mutated_birch_forest_hills, minecraft:mutated_roofed_forest, minecraft:mutated_taiga_cold, minecraft:mutated_redwood_taiga, minecraft:mutated_redwood_taiga_hills, minecraft:mutated_extreme_hills_with_trees, minecraft:mutated_savanna, minecraft:mutated_savanna_rock, minecraft:mutated_mesa, minecraft:mutated_mesa_rock, minecraft:mutated_mesa_clear_rock]
-
I think this guy's question isn't really about modding but about USING mods. He's saying that he wants to use a bunch of mods simultaneously and already knows there are more than 256 entities combined. In that case, the answer is it depends on which version of Minecraft / Forge he's using as well as assuming that the mods have been ported properly to the newer versions. If he's back on 1.6.4 (and a surprising number of people still play with old versions) or something the answer is probably no.
-
Draco, I think the "problem" I have with the system is to me the idea of a trigger is that once I call it, it should trigger. Instead, the system is designed to sort of filter the triggers so you call the trigger but it still may not match all the conditions. The idea of calling a trigger and it still having to test if it really triggers just seems unnatural to me. The reason they did that is they wanted to allow the logic to be controlled and extended by JSON, presumably because then resource packs and people who don't know how to code well could still do some cool stuff. However, if you're already coding in Java (and assuming you're not specifically trying to enable people to replace your logic with resource packs) it makes a lot more sense to me to just trigger directly. In other words, just look at how much you just wrote about what needs to be done. Also you're a strong programmer who's comfortable with serializers, factories, enums, and such so it is easy for you. I can do those things too, but not as well and I generally like simplicity so it is a lot easier for me to simply trigger directly in code. And just imagine how much trouble all those people who are trying to mod while struggling with Java will have. For example, if you wanted to do something like have an advancement to trigger when you're killing a bat while simultaneously jumping and holding a custom sword, it is just one line of Java to instantiate it, one line of Java to register it (actually I put them the instances in an array so don't even need that), and one line of Java wherever in the code it makes sense to trigger it. I don't need to make predicates or fiddle with any JSON at all. If I want another advancement where for example you need to be playing a specific record inside a specific structure, same thing -- between two and three lines of code and its working. I just think the JSON system is more suitable for allowing other people to modify your advancements (which may be important for some people) but is much less efficient and way more error-prone compared to if you just code it.
-
Alternatively, there is actually a way to make a more "code based" custom trigger where you make a simple JSON trigger that always fires and then just call it when you want it to fire in code. I have an example here: http://jabelarminecraft.blogspot.com/p/minecraft-modding-custom-triggers-aka.html The JSON system is great for combining existing triggers and conditions (and probably can be made to work for your case) but it sort of an "indirect" system where it tries to fire and then is filtered based on predicates and such. I think there are a lot of cases in modding where your trigger is more unusual and it makes sense to have a trigger that always fires when you call it. Note: Also I have to say that some of my longest debugging efforts have been related to problems with JSON files. The problem with moving logic to JSON files is that your IDE doesn't help you much with checking the logical stuff. Your IDE can ensure you have a properly formed JSON and can format and color code to make it easier to read, but it really doesn't have a sense of whether it will execute the way you want. And then when it doesn't work you actually have to debug it is complicated to trace because it all funnels through some pretty complicated JSON deserializer code.
-
I don't think you really need to make your own renderer unless you're doing something fancy. Since you said you wanted to have them show up like "normal" liquids you might just want to check my custom fluid tutorial to see what you're doing wrong. http://jabelarminecraft.blogspot.com/p/minecraft-modding-fluids_18.html . Also, you probably have an indication in the console log. It may complain about not finding the blockstate file, or having a bad blockstate file, or missing variant, or missing texture, and so forth. So most likely related to your JSONs or else related to your registry names not matching your JSON file names. So either post your log or debug it yourself.
-
Not sure if you've figured it out yet, since it has been a while since you posted. I have only recently got back into trying modding fluids and after a bit of digging around figured it out. I haven't finished with the tanks and buckets yet, but you can get information on the fluid blocks in my tutorial here: http://jabelarminecraft.blogspot.com/p/minecraft-modding-fluids_18.html You can also see some working code in my example mod here: https://github.com/jabelar/ExampleMod-1.12/tree/master/src/main/java/com/blogspot/jabelarminecraft/examplemod In that example I made a slime fluid block (that can push you like water and also puts an colored overlay on the screen if you go deep into it (also like water).
-
Not Minecraft-related objects as a mod (Cars, etc.) - MC 1.12.1
jabelar replied to SuprizePlayz's topic in Modder Support
Anything that moves in Minecraft pretty much has to be an entity. Now I'm not exactly sure what you mean by your worries about the collisions. I think what you mean is that the bounding box for an entity has some constraints which are: it doesn't rotate with the entity, it is square at the bottom. So if you want to get more precise collisions what I usually do is create some invisible "child" entities that move along with main entity and when they collide you write code to affect the main entity with the collision. In other words, you can create multiple collision boxes for an entity using invisible entities that follow along. -
So while porting my mods I'm trying to move my old registration methods to the new registry events. However, for entities two important aspects of the registration no longer seem available -- the tracking range and tracking speed. Now many people may not have played with this, but it is critical in my mods -- for example if you make a bird entity you need to greatly increase the tracking range because even when they are flying overhead they may be over 100 blocks away. And for fast moving entities like thrown ones I tended to increase the frequency of the tracking updates. So how do you do that with the new registry system that uses EntityEntry? In EntityEntry all I can see is that you can directly set the entity and registry name, and indirectly you can set the EntityEggInfo but I can't see anything related to the tracking that the previous registry system allowed you to control. Also setting the egg seems to be a pain because it takes in the entity id which I assume is only valid after the registration is completed... so when and how should that be done? Also, while the idea of an EntityEntry class makes some sense it is inconsistent with all the other registry events whose register methods take in a "value" (the actual thing to get registered) and presumbably grab the registry name directly. It would be more consistent if Entity also had a registry name field with equivalent getter. Am I missing something, or should I work on a pull request to add those parameters? Seems like the EntityEntry registration is only half-way implemented at the moment...
-
[Solved][1.12.1] Proper way to contribute pull requests to Forge
jabelar replied to jabelar's topic in Modder Support
Perfect, thanks guys. -
Well, it is very unlikely for a mod to not require an update, but it is possible. An easy way to prove you do need to update is to copy your mod source into a new folder, update the build.gradle to download the latest Forge version, create the updated workspace and IDE project and open in your IDE. If you see a bunch of errors then you need to update! Based on my experience, every Minecraft update requires source code update. Even little things like changing the packages, to fundamental things like moving to the block state system. But a very very simple mod, where the classes it references haven't moved, been renamed (including names of methods) and none of the method parameters have been changed, then you might get away with it. I have also found times where I've had to update during same MC version as Forge usually has an inital period of development for each MC version where things can change a bit. But I think they try as hard as they can not to break things within the same MC version, so it is rare.
-
So I figure I should give back to the Forge developer community who've made such an amazing thing from which I've derived years of a fun hobby of modding. So I have a very simple pull request idea to start with but I want to make sure that I go about the right process for the pull request. Since I've primarily been a solitary programmer, I haven't had to do a lot of working with other people who are collaborating; therefore I'm nervous that I might break things by creating a bad branch/fork/commit. So I have a few questions. 1) Fork, branch or tree? I see some commits that seem to be on the main branch, but others are on a fork (which seems to be listed as a "tree"). Should I create a fork, a new branch, or just make commits to the main repository? Like should I be working in MinecraftForge/MinecraftForge or on jabelar/MinecraftForge? 2) How do you actually test it? Can you run it from the IDE or do you need to build it and apply it to a Minecraft installation? Once you clone the repository do you run some gradle commands to set up the workspace and make it more amenable to Eclipse? 3) How do you make sure the IDE doesn't ripple a bunch of formatting through the entire codebase -- I have various "on save" features turned on in Eclipse to do things like update Javadoc, update licenses, and do various import cleanup, @Override cleanup, indent formatting and such. I wouldn't want to create a commit that has changes to every file in the repository, but I also want to keep Eclipse set up the way I like it for my other modding. Should I create a separate workspace or something to help manage this? Sorry for the newbie questions...
-
Not Minecraft-related objects as a mod (Cars, etc.) - MC 1.12.1
jabelar replied to SuprizePlayz's topic in Modder Support
I don't really know what you mean by "non-Minecraft" because all things in mods are by definition not in vanilla Minecraft. However, I think you mean things that are less commonly modded (and therefore harder for a new modder to find information to help get started). However, honestly things like cars is not a new idea and there is probably lots of mod source examples out there. Anyway, I would suggest that even something like a car can have parallels to other things. For example, I would suggest that a rideable vehicle like a minecart has a lot of similarities and even a rideable animal isn't that much different. in both cases, the key point is that you would use a rideable entity. Once you have a hint on what might be closest thing currently in Minecraft I suggest that you look up tutorials for rideable entities. Also, search for mods that already have vehicles in them and find ones who give links to their source code and review that. Then try to do what you can, and come back here when you're stuck. I have a lot of tutorials about general modding here that may also be useful: http://jabelarminecraft.blogspot.com/ -
That isn't a good attitude. How do you think people who write the tutorials figure it out? No one tells them, they just look at the source and use their Java education to figure things out. Also, if someone already has a tutorial to do exactly what you want to do, then what is the fun in making a mod then? You always will need to figure out a lot for your own mod. Anyway, it isn't nice to expect other people to figure out everything for you. Although people on the forum will certainly try to give you some help, you need to also put in some work yourself.