Leaderboard
Popular Content
Showing content with the highest reputation on 01/10/20 in Posts
-
Its logical server side (per-world) and syncs to the client on connection. You register it on all distributions. Using a "proxy" or "baked" value is much better. You can see and/or profile the performance of the get method yourself. It's (possibly nested) Map#get calls so isn't extremely slow but is a lot slower than direct field access. Forge registers its client & server configs on all distributions, however they only use simple config values like booleans and numbers. If you're using a class that only exists on a specific distribution (for example an enum) you might want to look into only registering that config on that distribution. The config types contain some documentation. I've got a tutorial on configs here if you'd like some info. It's not very in-depth though (yet).2 points
-
In honor of this thread, Im going to quickly summarise what I have gathered about creating villagers professions in 1.14.4 (forge 28.1.109) as there is not really that much information about that available right now. If anyone sees me doing something wrong or saying bs, just let me know and I will fix it. Specifically the reflection fix I mention below. EDIT: Make sure you check the first couple replies as well. Source for all of this can be found specifically in this commit: https://github.com/CAS-ual-TY/GunCus/commit/817848784868f4e8362d4270be6f8fc19863dc42 Tho I have done a few extra things which are unrelated so dont wonder. PointOfInterestType If you check out the vanilla class, you could come to the conclusion, that these are generally types of points of interest for villagers. You have the blocks in there that give the villagers their professions (eg. the Armorer type has a Blast Furnace passed to the constructor), you have a Bed type for sleeping, Unemployed type, Meeting type, etc. (But most importantly you have all the professions). You make your POITypes in the forge registry event for that (Register<PointOfInterestType>) (dont forget to set the registry name). Constructor is: String name, Set<BlockState> blockStates, int maxFreeTickets, SoundEvent workSound, int something. Name seems to just be the lower case name (eg. "fletcher", "leatherworker" etc.), the blockStates are just all block states of the interest block. There is a helper method for this (unfortunately its private, so youll have to figure something out for yourself) which I will post below. Next you have what it seems to be the amount of villagers that can use this at once. All vanilla professions have this at 1. Next you have the work sound. I just use vanilla sounds here, so youll have to check yourself if your sound event public static final instances are populated already at this point. And finally you have another integer which I have no idea about. All vanilla professions have this at 1 too. VillagerProfession Now we create the villager profession. This is the type of profession a villager can have (eg. Flether, Weapon Smith etc.). We use the forge registry event for this again (Register<VillagerProfession>) (again, dont forget to set registry name). Constructor: String nameIn, PointOfInterestType pointOfInterestIn, ImmutableSet<Item> noIdea, ImmutableSet<Block> noIdeaAgain. The name is the lowercase name again (eg. "fisherman", "mason" etc.). This is needed for the texture and translation (see below). Next you pass the PointOfInterestType for this profession (read above that this is). Since P comes before V, these are already registered and object holders are populated, so you can just pass your static fields here. The 2 sets that come now I havent really looked into because all vanilla professions just pass an empty set here (ImmutableSet.of()). Profession Texture Location assets\MOD_ID\textures\entity\villager\profession\PROFESSION_NAME.png You just have to put the texture in the appropriate location. Rendering is done automatically. If you want to play around with the model a bit (eg. change the hat), check out the vanilla villagers. You can do that by adding extra PROFESSION_NAME.png.mcmeta files to the same location. Just check out vanilla for examples: assets\minecraft\textures\entity\villager\profession Profession Trading GUI Title Translation entity.minecraft.villager.MOD_ID.PROFESSION_NAME This is the key for your .lang file. Translate this to set the title of the trading GUI. At first I was confused, because there is 2 mod ids in there (mine and minecraft). But it makes sense because the villager is part of minecraft, but the professions part of *MOD_ID*. So ye. Adding Trades to Professions Forge has 2 events for that: VillagerTradesEvent, WandererTradesEvent. You can add trades to any profession here. 1st one allows to add trades to every profession and their levels (1-5, novice to master or smth). 2nd one allows to add generic or rare trades to the wanderer. I highly suggest checking out the vanilla trades to have an idea what (or how much) to set here for all the params: https://minecraft.gamepedia.com/Trading#Armorer - To do the first: Call event.getTrades().get(level).add(some_ITrade_instance_or_lamda_action). To do this for the profession you want, check if event.getType() == ModVillagerProfessions.YOUR_PROFESSION (this event gets called once for every profession). - To do the second: Just check out the event class. Pretty simple. Easy getters easy life I have made a helper class for this to allow easy trade creation. I will post it below. Example usage of this helper class (adds a trade to level 1; You can buy 2-4 (picked randomly per villager, but steady) acacia fences for 12 emeralds): event.getTrades().get(1).add(new RandomTradeBuilder(8, 10, 0.05F).setEmeraldPrice(12).setForSale(Items.ACACIA_FENCE, 2, 4).build()); Final Reflection Fix Im just going to quote what I have written on forge discord. See below for fix (in helper section, call for every POIType in your init): ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ Helper Stuff (use this as you please) Get all Block States static Set<BlockState> getAllStates(Block block) { return ImmutableSet.copyOf(block.getStateContainer().getValidStates()); } Easy/Random Trades Builder package here import java.util.Random; import java.util.function.Function; import net.minecraft.entity.merchant.villager.VillagerTrades.ITrade; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.MerchantOffer; public class RandomTradeBuilder { protected Function<Random, ItemStack> price; protected Function<Random, ItemStack> price2; protected Function<Random, ItemStack> forSale; protected final int maxTrades; protected final int xp; protected final float priceMult; public RandomTradeBuilder(int maxTrades, int xp, float priceMult) { this.price = null; this.price2 = (random) -> ItemStack.EMPTY; this.forSale = null; this.maxTrades = maxTrades; this.xp = xp; this.priceMult = priceMult; } public RandomTradeBuilder setPrice(Function<Random, ItemStack> price) { this.price = price; return this; } public RandomTradeBuilder setPrice(Item item, int min, int max) { return this.setPrice(RandomTradeBuilder.createFunction(item, min, max)); } public RandomTradeBuilder setPrice2(Function<Random, ItemStack> price2) { this.price2 = price2; return this; } public RandomTradeBuilder setPrice2(Item item, int min, int max) { return this.setPrice2(RandomTradeBuilder.createFunction(item, min, max)); } public RandomTradeBuilder setForSale(Function<Random, ItemStack> forSale) { this.forSale = forSale; return this; } public RandomTradeBuilder setForSale(Item item, int min, int max) { return this.setForSale(RandomTradeBuilder.createFunction(item, min, max)); } public RandomTradeBuilder setEmeraldPrice(int emeralds) { return this.setPrice((random) -> new ItemStack(Items.EMERALD, emeralds)); } public RandomTradeBuilder setEmeraldPriceFor(int emeralds, Item item, int amt) { this.setEmeraldPrice(emeralds); return this.setForSale((random) -> new ItemStack(item, amt)); } public RandomTradeBuilder setEmeraldPriceFor(int emeralds, Item item) { return this.setEmeraldPriceFor(emeralds, item, 1); } public RandomTradeBuilder setEmeraldPrice(int min, int max) { return this.setPrice(Items.EMERALD, min, max); } public RandomTradeBuilder setEmeraldPriceFor(int min, int max, Item item, int amt) { this.setEmeraldPrice(min, max); return this.setForSale((random) -> new ItemStack(item, amt)); } public RandomTradeBuilder setEmeraldPriceFor(int min, int max, Item item) { return this.setEmeraldPriceFor(min, max, item, 1); } public boolean canBuild() { return this.price != null && this.forSale != null; } public ITrade build() { return (entity, random) -> !this.canBuild() ? null : new MerchantOffer(this.price.apply(random), this.price2.apply(random), this.forSale.apply(random), this.maxTrades, this.xp, this.priceMult); } public static Function<Random, ItemStack> createFunction(Item item, int min, int max) { return (random) -> new ItemStack(item, random.nextInt(max) + min); } } Reflection Fix private static Method blockStatesInjector; static { try { blockStatesInjector = PointOfInterestType.class.getDeclaredMethod("func_221052_a", PointOfInterestType.class); blockStatesInjector.setAccessible(true); } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } public static void fixPOITypeBlockStates(PointOfInterestType poiType) { try { blockStatesInjector.invoke(null, poiType); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } }1 point
-
"Structures" are what they say they are. They are features that use the Structure class and place blocks for things like village houses, mineshafts, shipwrecks, and other structures. I've looked into the code and barely understand it. You can see some of my fooling around (I've been working on trying to get Custom Ore Gen on 1.14, so my code is oriented in that direction) here: https://github.com/Draco18s/ReasonableRealism/tree/1.14.4/src/main/java/com/draco18s/harderores/world1 point
-
You've specified the forge marker and then you didn't use Forge variants. And instead specified all 40 variants manually. Forge would have let you write 11. Anyway: This error says that there is a texture specified as a reference (ie. "#side", starting with a #) and that texture reference hasn't gotten a definitive resource location. The model with that issue is minecraft:block/inner_stairs. The code you have posted does not include a reference to this model (or the other models generating an error).1 point
-
I would expect spelling "assets" correctly (instead of "asstes") will make a world of difference. Even in 1.14.4.1 point
-
This is what advacements are for. Look at the vanilla data package data/minecraft/advacements/recipes1 point
-
OOOOOOHHHHH i found the solution. I changed the drive that i was running minecraft on from my non-boot hard drive to my boot drive and it worked1 point
-
I solved it. Here's how I did it: When I set the EntityType variable for my named variable "ENT_PROJECTILE" and build, I use the setCustomClientFactory method, so it would look exactly like this: ENT_PROJECTILE = registerEntity(EntityType.Builder.<EntityModProjectile>create(EntityClassification.MISC).setCustomClientFactory(EntityModProjectile::new).size(0.25F, 0.25F), "ent_projectile"); Inside of my EntityModProjectile class I extended the ProjectileItemEntity class, overrided the createSpawnPacket method and returned getEntitySpawningPacket from NetworkHooks class. Like this: @Override public IPacket<?> createSpawnPacket() { return NetworkHooks.getEntitySpawningPacket(this); } I then created another constructor inside of the EntityModProjectile class, like this: public EntityModProjectile(FMLPlayMessages.SpawnEntity packet, World worldIn) { super(ModEntityType.ENT_PROJECTILE, worldIn); }1 point
-
I don't recommend using any instanceof checks as it can cause problems with various mods including my own. I have several mobs that are hostile but can be tamed/summoned by players no longer being hostile but still use the same class, therefore instanceof wont work. I've been using the vanilla method: isCreatureType(EnumCreatureType type, boolean forSpawnCount) to check for hostile mobs, where you can use it like this: isCreatureType(EnumCreatureType.monster, false), it works great for vanilla mobs and can be overridden by modders like myself to add logic to hostility checks, in my case I can check if a mob is owned by a player (not hostile) or wild (hostile). It also has the forSpawnCount boolean which is handy for other spawner mods, etc too!1 point
-
I'm having these crashes which I can't get to the bottom to at all, I've updated to 1.9.4 but my server is still waiting at 1.9 for a few other mods to update so I'm not sure if there is an issue with 1.9 or forge or if it my mod causing the problem somehow as the stack trace doesn't really tell me anything from what I can see. I've tried this using 1865, 1887 and 1907. I've just noticed 1923 so I'll give that a try to see if this stops, in the mean time I'll keep this post in case it's a problem on my end. func_70636_d seems to be onLivingUpdate java.lang.Error at net.minecraft.entity.EntityLiving.func_70626_be(EntityLiving.java:763) at net.minecraft.entity.EntityLivingBase.func_70636_d(EntityLivingBase.java:2131) at net.minecraft.entity.EntityLiving.func_70636_d(EntityLiving.java:564) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70636_d(EntityCreatureBase.java:1295) at lycanite.lycanitesmobs.api.entity.EntityCreatureAgeable.func_70636_d(EntityCreatureAgeable.java:106) at net.minecraft.entity.EntityLivingBase.func_70071_h_(EntityLivingBase.java:1961) at net.minecraft.entity.EntityLiving.func_70071_h_(EntityLiving.java:296) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70071_h_(EntityCreatureBase.java:1242) at net.minecraft.world.World.func_72866_a(World.java:1934) at net.minecraft.world.WorldServer.func_72866_a(WorldServer.java:836) at net.minecraft.world.World.func_72870_g(World.java:1903) at net.minecraft.world.World.func_72939_s(World.java:1737) at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:619) at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:705) at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:386) at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:609) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:467) at java.lang.Thread.run(Thread.java:745) This one looks related to my nearest target sorter but I can't repeat this crash consistently: java.lang.Error at java.util.Collections$SetFromMap.contains(Collections.java:5459) at net.minecraft.util.ClassInheritanceMultiMap.func_181157_b(SourceFile:45) at net.minecraft.util.ClassInheritanceMultiMap$1.iterator(SourceFile:101) at net.minecraft.world.chunk.Chunk.func_177430_a(Chunk.java:915) at net.minecraft.world.World.func_175647_a(World.java:3039) at lycanite.lycanitesmobs.api.entity.ai.EntityAITarget.getPossibleTargets(EntityAITarget.java:142) at lycanite.lycanitesmobs.api.entity.ai.EntityAITarget.getNewTarget(EntityAITarget.java:124) at lycanite.lycanitesmobs.api.entity.ai.EntityAITargetAttack.func_75250_a(EntityAITargetAttack.java:194) at net.minecraft.entity.ai.EntityAITasks.func_75774_a(SourceFile:94) at net.minecraft.entity.EntityLiving.func_70626_be(EntityLiving.java:757) at net.minecraft.entity.EntityLivingBase.func_70636_d(EntityLivingBase.java:2131) at net.minecraft.entity.EntityLiving.func_70636_d(EntityLiving.java:564) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70636_d(EntityCreatureBase.java:1295) at lycanite.lycanitesmobs.api.entity.EntityCreatureAgeable.func_70636_d(EntityCreatureAgeable.java:106) at lycanite.lycanitesmobs.api.entity.EntityCreatureTameable.func_70636_d(EntityCreatureTameable.java:177) at lycanite.lycanitesmobs.shadowmobs.entity.EntityGrue.func_70636_d(EntityGrue.java:114) at net.minecraft.entity.EntityLivingBase.func_70071_h_(EntityLivingBase.java:1961) at net.minecraft.entity.EntityLiving.func_70071_h_(EntityLiving.java:296) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70071_h_(EntityCreatureBase.java:1242) at net.minecraft.world.World.func_72866_a(World.java:1934) at net.minecraft.world.WorldServer.func_72866_a(WorldServer.java:836) at net.minecraft.world.World.func_72870_g(World.java:1903) at net.minecraft.world.World.func_72939_s(World.java:1737) at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:619) at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:705) at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:386) at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:609) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:467) at java.lang.Thread.run(Thread.java:745) I've had several crashes like this, MoveSwimmingWithHeading is a custom method of mine but this crash has also occured with MoveEntityWithHeading which doesn't do much in my override before calling it on EntityLivingBase. java.lang.Error at net.minecraft.world.World.func_175674_a(World.java:2982) at net.minecraft.world.World.func_72839_b(World.java:2965) at net.minecraft.world.World.func_184144_a(World.java:1250) at net.minecraft.entity.Entity.func_70091_d(Entity.java:633) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.moveSwimmingWithHeading(EntityCreatureBase.java:1665) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70612_e(EntityCreatureBase.java:1610) at net.minecraft.entity.EntityLivingBase.func_70636_d(EntityLivingBase.java:2165) at net.minecraft.entity.EntityLiving.func_70636_d(EntityLiving.java:564) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70636_d(EntityCreatureBase.java:1295) at lycanite.lycanitesmobs.api.entity.EntityCreatureAgeable.func_70636_d(EntityCreatureAgeable.java:106) at net.minecraft.entity.EntityLivingBase.func_70071_h_(EntityLivingBase.java:1961) at net.minecraft.entity.EntityLiving.func_70071_h_(EntityLiving.java:296) at lycanite.lycanitesmobs.api.entity.EntityCreatureBase.func_70071_h_(EntityCreatureBase.java:1242) at net.minecraft.world.World.func_72866_a(World.java:1934) at net.minecraft.world.WorldServer.func_72866_a(WorldServer.java:836) at net.minecraft.world.World.func_72870_g(World.java:1903) at net.minecraft.world.World.func_72939_s(World.java:1737) at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:619) at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:705) at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:386) at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:609) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:467) at java.lang.Thread.run(Thread.java:745) I've also had a similar crash related to getting a pathing node both with one of my entities and with EntityBat. Here are some relevant samples of my code: EntityCreatureBase: @Override public void onLivingUpdate() { super.onLivingUpdate(); <-- Crashes Here EntityAITarget: public EntityAITarget(EntityCreatureBase setHost) { this.host = setHost; this.targetSelector = new Predicate<Entity>() { @Override public boolean apply(Entity input) { if(!(input instanceof EntityLivingBase)) return false; return EntityAITarget.this.isSuitableTarget((EntityLivingBase)input, false); } }; this.allySelector = new Predicate<Entity>() { @Override public boolean apply(Entity input) { if(!(input instanceof EntityLivingBase)) return false; return EntityAITarget.this.isAllyTarget((EntityLivingBase) input, false); } }; this.nearestSorter = new TargetSorterNearest(setHost); } public EntityLivingBase getNewTarget(double rangeX, double rangeY, double rangeZ) { EntityLivingBase newTarget = null; try { List possibleTargets = this.getPossibleTargets(rangeX, rangeY, rangeZ); if (possibleTargets.isEmpty()) return null; Collections.sort(possibleTargets, this.nearestSorter); newTarget = (EntityLivingBase) possibleTargets.get(0); } catch (Exception e) { LycanitesMobs.printWarning("", "An exception occurred when target selecting, this has been skipped to prevent a crash."); e.printStackTrace(); } return newTarget; } public List getPossibleTargets(double rangeX, double rangeY, double rangeZ) { return this.host.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, this.host.getEntityBoundingBox().expand(rangeX, rangeY, rangeZ), Predicates.and(new Predicate[]{EntitySelectors.CAN_AI_TARGET, this.targetSelector})); <-- Crashes from here } My old eventually to be replaced but still useful TargetSorterNearest: public class TargetSorterNearest implements Comparator { private final Entity host; // ================================================== // Constructor // ================================================== public TargetSorterNearest(Entity setHost) { this.host = setHost; } public int compare(Object objectA, Object objectB) { if(objectA instanceof Entity && objectB instanceof Entity) return this.compareDistanceSq((Entity)objectA, (Entity)objectB); if(objectA instanceof BlockPos && objectB instanceof BlockPos) return this.compareDistanceSq((BlockPos)objectA, (BlockPos)objectB); return 0; } public int compareDistanceSq(Entity targetA, Entity targetB) { double distanceA = this.host.getDistanceSqToEntity(targetA); double distanceB = this.host.getDistanceSqToEntity(targetB); return distanceA < distanceB ? -1 : (distanceA > distanceB ? 1 : 0); } public int compareDistanceSq(BlockPos targetA, BlockPos targetB) { BlockPos hostCoords = new BlockPos((int)this.host.posX, (int)this.host.posY, (int)this.host.posZ); double distanceA = hostCoords.getDistance(targetA.getX(), targetA.getY(), targetA.getZ()); double distanceB = hostCoords.getDistance(targetB.getX(), targetB.getY(), targetB.getZ()); return distanceA < distanceB ? -1 : (distanceA > distanceB ? 1 : 0); } } I think that's all the info I can provide, I'll add similar crashes when they happen, I'm totally stumped though and it only seems to be on my live server which was copied other from my test server on my PC which has no issues, the java builds are the same but the OS changes from Windows (test) to Ubuntu (live).1 point
-
Currently my mob models are in OBJ format. In 1.7.10 I used animate them by having each body part as a separate group (or part as they were called by the importer). I would animate each body part by looping through each group, I would translate and rotate using GL11 functions before rendering that group and moving onto the next. This was instead of just rendering the model as a whole. This also allowed me to hide certain groups when needed, fore example I could just show the head of a model for trophies, some mobs also have destructible parts such as shells. Is there a way to do this in 1.9 using the new OBJ Importer, I'm aware that B3D has animation support but it looks to me like it's for actual frame based animation which would mean I would have a lot of work on my hands due to having around 70 mobs to work on.1 point
-
Hi yes its me again now that I have it up granting I don't have the mod downloaded yet where exactly do I put the mod when I do download it in the Minecraft files and what happens if its not there even though the forge version of Minecraft is there. This is what I am seeing when I go into my files to look for this mod folder unless it isn't meant to be there is there something missing?0 points