Jump to content

CAS_ual_TY

Members
  • Posts

    72
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by CAS_ual_TY

  1. Hi, the mod I am working on downloads textures at runtime (used for Screen, not Items/Blocks ofc). This must be done in seperate threads, as otherwise the game freezes for the duration. Now, I have some experience with Multithreading, I know how to make things thread safe and all the basics you need to know for that. My goal is to use a Thread Pools like implementation, as there are multiple tasks todo (Download, Resize, Modify image entirely ...), and sometimes they need to be done in a specific order. The main question would be: What to do when Minecraft shuts down. All the tasks are short, so ideally I would like to wait for them to finish, the task queue can just be discarded in that case. There are some tasks which I do not want to see interrupted in some circumstances (eg. while writing to a file). I dont know of any MC functionality that I can use to ensure that. So I did some research and might go for a Shutdown Hook. This leads me to my 2nd question: Would it be bad practice in this specific scenario to have the shutdown hook thread just wait for the worker threads to finish (with a max wait time ofc)? If there are better ways of accomplishing what I am trying to do, please let me know Thanks!
  2. Afaik There is an event that gets fired when an item gets dropped and the item entity is spawned. Cancel it and spawn your own item entity that does what you want. Assuming my 1st assumption is true
  3. https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials#Episode_2:_The_First_Block.2C_Capabilities.2C_Container.2C_Gui Containers dont really require anything special in constructor in regards to tile entities. You are not forced to open it on right click of a tile entity. You can also just open the container when right clicking an item etc.. Just depends on where you call the NetworkHooks method to open it. Most minecraft containers require the player or player inventory as parameter (in constructor) because they access said inventory. But you are free to do whatever you want. So ye. Kinda trying to answer you where there isnt much to talk about. You can re-use the same container and containerscreen classes for different container types. Just keep that in mind (this is done eg. with the vanilla chests)
  4. 1st: In 1.15 the 2nd parameter of RayTraceContext#new was not a direction, but rather another position. If that is still the case, then in your case you would have to do something like: new RayTraceContext(eyePos, eyePos.add(player.getLookVec().scale(RANGE)), RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player) 2nd: Out of curiosity: Why are you using ItemStack#isItemEqual instead of just comparing the items? Is NBT important here?
  5. In 1.15 there was World#rayTraceBlocks Which was pretty straightforward. Maybe that is still a thing in 1.16
  6. (also you should add a gitignore file to your repo. The default one found in the mdk is pretty good)
  7. FMLServerStartingEvent & FMLServerStoppedEvent & FMLPlayerLoggedInEvent = Server Only RenderWorldLastEvent & Minecraft.getInstance() = Client Only Mixing "Server Only" and "Client Only" = Very Bad, Not Working You could take a look at EntityJoinTheWorldEvent and use a flag. I personally dont know the best Client Side event for this
  8. What you just gave me doesnt help me at all. I dont know what renderPlayerInfo does. I also dont know where you register all of this (when its fired). So until you show more context Ill just give you some general stuff: There is 2 different buses: - mod bus, for "mod construction" events (eg. FMLCommonSetupEvent, TextureStichEvent, ModelRegistryEvent, ModConfigEvent etc.) - forge bus, for general minecraft events (eg. RenderGameOverlay, EntityJoinedTheWorld...) And there is different methods of registering. This sums it up:
  9. Did you make a blockstate json file? Recheck it to make sure.
  10. You would have to make your own ItemGroup class which overrides the "fill" method in which you add your items to the list in any order you want.
  11. RenderGameOverlayEvent is correct. Just the bus is not. Register to MinecraftForge.EVENT_BUS
  12. I solved it this way: https://github.com/CAS-ual-TY/YgoDuelingMod/blob/7486e325beef23462248371b028b552080f7b450/src/main/java/de/cas_ual_ty/ydm/client/ClientProxy.java#L131 I had similar problems and switched to this. Basically you could only render when player!=null and screen==null. Just a last resort "solution". I will follow this thread in case there is a better one.
  13. shootingEntity might be null on client side (havent checked). Extend your entity with IEntityAdditionalSpawnData if that is the case.
  14. Blocks.COAL_BLOCK Would probably be better for your example
  15. You probably register the villagerTrades method wrongly.
  16. EDIT: Created a pull request https://github.com/MinecraftForge/MinecraftForge/pull/6609 -------------------------------------------------------------------- Not sure if I found a forge bug. Ill just elaborate: - The Vanilla Effect class implements the Forge IForgeEffect interface - IForgeEffect interface has a method "getCurativeItems" which returns a list of item stacks which cure the effect - This has a default implementation containing only the milk bucket - The MilkBucketItem class then appropriately calls the method which checks if it cures each effect and then removes it only if applicable - So far so good - Now here is the problem: In the same method it also calls a method which removes all potion effects regardless, kinda negating everything from above. Latest 1.15.2 version of forge The code mentioned: Inside MilkBucketItem::onItemUseFinish Correct first call: LivingEntity::curePotionEffects Unnecessary (I guess) call: LivingEntity::clearActivePotions
  17. Got some raytrace examples here. Maybe this helps https://github.com/CAS-ual-TY/GunCus/blob/20ca31de7850b0183e7454ba9c3d8e307ce6112a/src/main/java/de/cas_ual_ty/guncus/client/ProxyClient.java#L717
  18. - NoodleOre (Block) needs a registry name (noodle_ore) - The public static field NOODLE_ORE (ModBlocks class) will always be null because afaik ObjectHolder pupulates only PSF fields, not PS (so make it final) Not sure about the 2nd point though, check the ObjectHolder class, I think its explained in there EDIT: NVM just seen that you set the registry name inside the constructor.
  19. Going to bump this one time (I could not find forum rules on bumping, but I dont intend to do it anymore here anyways). Some (new) things: - Still could not find a way to do it without reflection. Forge will probably have to step in there (Idk Im too afraid to ask or ping anyone). But I totally forgot about the reflection helper, so you should probably change the reflection fix to use the following (this already does the setAccessible(true) call, so just get the method using this): blockStatesInjector = ObfuscationReflectionHelper.findMethod(PointOfInterestType.class, "func_221052_a", PointOfInterestType.class); - There is a more modern way to register stuff which you probably wanna use. I have not known about it (like most others) so I will just put that here for the sake of progress:
  20. 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(); } }
  21. Just subscribe to the general Event class once and do all your handling and cancelling from there, eg. by having an array list of event classes you want to cancel. Something like ArrayList<Class> list ... void event(Event event) { for(Class c : list) if(c.equals(event.getClass())) event.setCanceled(true); }
  22. Hello, Basically I have a folder which contains multiple sub-folders which are 1.14 mdks. The head folder is also the eclipse workspace and the sub-folders are eclipse projects each. In sub-folder 1 I am creating an API mod I intend to use for another mod, created in sub-folder 2. The API is open source, but it is on github (no maven). Now, what is the best way to now setup the mod workspace (folder 2) which needs the API (folder 1)? Can I just build a source jar of the api (folder 1) and then simply put it into a dependency folder for the mod (folder 2)? If yes, how? I tried lots of googling already, but I havent really found a solution where you have everything locally already. The topics I found pretty much all involved APIs from someone else, published online.
×
×
  • Create New...

Important Information

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