Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

izofar

Members
  • Posts

    52
  • Joined

  • Last visited

Posts posted by izofar

  1. I am trying to modify the private static final potion brewing recipe list PotionBrewing.POTION_MIXES with access transformers. MCP bot on discord gave me:

    !mcp -c moj field_185213_a
    forge-bot
    BOT
     — Today at 4:42 PM
    List of MCP -> Mojmap Mappings (Page 1/1):
    
    MC 1.16.5: net/minecraft/world/item/alchemy/PotionBrewing.POTION_MIXES
    Name: a => field_185213_a => POTION_MIXES
    Side: BOTH
    AT: public net.minecraft.potion.PotionBrewing field_185213_a # POTION_MIXES
    Type: java/util/List

    Great. So I add

    public-f net.minecraft.world.item.alchemy.PotionBrewing field_185213_a # POTION_MIXES

    Then I refresh my gradle project, and the field is still private according to my IDE.

    Then I notice, the mcp bot gave the field for net.minecraft.potion.PotionBrewing for version 1.16.5, which makes sense since that's where it was before. How do I get the obfuscated fields for 1.18? Do these change each version?

  2. 1 minute ago, diesieben07 said:

    "minecraft:chest" is not a valid loot modifier registry name.

    I got this from the link above, which says:

    Quote

    Optional type of the loot table. Must be one of empty if the loot table does not generate any loot, entity for loot an entity drops, block for loot a block drops, chest for a treasure chest, fishing for a fishing loot table, gift for a cat or villager gift, advancement_reward if it's used as a reward for an advancement, barter for loot from bartering with piglins, command for /execute, selector for predicate= in selectors, advancement_entity for entity predicates in advancements or generic if none of the above apply.

    If these are not the valid names, then what are?

  3. In 1.16, LootModifierManager#deserializeModifier read:

    private IGlobalLootModifier deserializeModifier(ResourceLocation location, JsonElement element) {
            if (!element.isJsonObject()) return null;
            JsonObject object = element.getAsJsonObject();
            ILootCondition[] lootConditions = GSON_INSTANCE.fromJson(object.get("conditions"), ILootCondition[].class);
    
            // For backward compatibility with the initial implementation, fall back to using the location as the type.
            // TODO: Remove fallback in 1.16
            ResourceLocation serializer = location;
            if (object.has("type"))
            {
                serializer = new ResourceLocation(JSONUtils.getAsString(object, "type"));
            }
    
            return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(serializer).read(location, object, lootConditions);
        }

    Note the if(object.has(type")){} block, which is lacking from the 1.18 version of the class:

    private IGlobalLootModifier deserializeModifier(ResourceLocation location, JsonElement element) {
            if (!element.isJsonObject()) return null;
            JsonObject object = element.getAsJsonObject();
            LootItemCondition[] lootConditions = GSON_INSTANCE.fromJson(object.get("conditions"), LootItemCondition[].class);
    
            ResourceLocation serializer = new ResourceLocation(GsonHelper.getAsString(object, "type"));
    
            return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(serializer).read(location, object, lootConditions);
        }

    So, the "value" tag is required now for loot modifiers... fine. I added this to my loot modifer json files when I kept getting NullPointerExceptions. But when I use a valid "value" tag I get:

    [15:27:02] [Render thread/ERROR]: Couldn't parse loot modifier examplemod:add_structure_loot
    java.lang.NullPointerException: Cannot invoke "net.minecraftforge.common.loot.GlobalLootModifierSerializer.read(net.minecraft.resources.ResourceLocation, com.google.gson.JsonObject, net.minecraft.world.level.storage.loot.predicates.LootItemCondition[])" because the return value of "net.minecraftforge.registries.IForgeRegistry.getValue(net.minecraft.resources.ResourceLocation)" is null
            at net.minecraftforge.common.loot.LootModifierManager.deserializeModifier(LootModifierManager.java:133) ~[forge-1.18-38.0.14_mapped_official_1.18-recomp.jar%2376%2382!:?]
            at net.minecraftforge.common.loot.LootModifierManager.lambda$apply$0(LootModifierManager.java:115) ~[forge-1.18-38.0.14_mapped_official_1.18-recomp.jar%2376%2382!:?]
            at java.util.ArrayList.forEach(ArrayList.java:1511) ~[?:?]
            at net.minecraftforge.common.loot.LootModifierManager.apply(LootModifierManager.java:113) ~[forge-1.18-38.0.14_mapped_official_1.18-recomp.jar%2376%2382!:?]
            at net.minecraftforge.common.loot.LootModifierManager.apply(LootModifierManager.java:54) ~[forge-1.18-38.0.14_mapped_official_1.18-recomp.jar%2376%2382!:?]

    My json file is:

    {
      "type": "chest",
      "conditions": [
        {
          "condition": "forge:loot_table_id",
          "loot_table_id": "examplemod:chests/modstructure"
        }
      ]
    }

    I tried printing the contents of ForgeRegistries.LOOT_MODIFIER_SERIALIZERS to know which keys I can use, but got:

    [15:26:13] [modloading-worker-0/INFO]: Printing LOOT_MODIFER_SERIALIZERS
    [15:26:13] [modloading-worker-0/INFO]: Printed LOOT_MODIFER_SERIALIZERS

    Is this a bug, given 1.18 is new, or am I not using these classes right?

  4. I have the following subscribe event in my StructureSpawnHandler.java:

    @SubscribeEvent
    	public static void onStructureSpawnListGather(StructureSpawnListGatherEvent event) {
    		if(event.getStructure() instanceof ShipwreckStructure) {
    			ExampleMod.LOGGER.info("\n======\n Found Shipwreck, Adding Drowned\n======\n");
    			event.addEntitySpawn(EntityClassification.MONSTER,  new MobSpawnInfo.Spawners(EntityType.DROWNED, 100, 4, 4));
    		}
    	}

    And I register it as follows in a static block, with my other subscribe class registers:

    MinecraftForge.EVENT_BUS.register(StructureSpawnHandler.class);

    However, Drowned's do not appear to spawn in shipwrecks when I load new worlds. Why might this be? I've read the Forge classes regarding the StructureSpawnListGatherEvent class, and the above should achieve my desired behavior.

  5. 12 minutes ago, diesieben07 said:

    That means you need to create your registry objects in the registry events and you need to use @ObjectHolder to inject them into fields. Your current code is not correct.

    Currently, I have a init package with my ModBlocks, ModItems, ModEntityTypes, etc. abstract classes that initialize the registry objects as class fields. Does it suffice to use @ObjectHolder("modid") above the class name in each class? My runClient has worked so far without these annotations... are these necessary for build, then? All of my registry objects are currently public static. Should I use final on all objects?

    Also, regarding the original topic, I updated my last post with the inheritance issue I am running into.

  6. 14 hours ago, Luis_ST said:

    show where you register your TE

    I plan to move to deferred registries when I port to 1.17, but I am currently working with the registry events approach. My declaration is:

    public static TileEntityType<LimitedMobSpawnerTileEntity> LIMITED_MOB_SPAWNER = (TileEntityType<LimitedMobSpawnerTileEntity>)TileEntityType.Builder.of(LimitedMobSpawnerTileEntity::new, ModBlocks.LIMITED_SPAWNER).build(null).setRegistryName("mob_spawner");

    In which I register it here:

    @SubscribeEvent
        public static void onTileEntitiesRegistry(final RegistryEvent.Register<TileEntityType<?>> tileEntityRegistryEvent) {
            tileEntityRegistryEvent.getRegistry().registerAll(
            		
            		ModTileEntityTypes.LIMITED_MOB_SPAWNER
            		
            );
        }

    EDIT:

    Using the above code, I just get a bunch of empty spawners. When I change the TE registration to "minecraft:mob_spawner" then I get the mapping error again. I think this is closer to what I want, but I may be missing a step. Looking at the mapping error I get, I traced it to my TileEntity#save override, in which the error comes from the check:

    private CompoundNBT saveMetadata(CompoundNBT p_189516_1_) {
          ResourceLocation resourcelocation = TileEntityType.getKey(this.getType());
          if (resourcelocation == null) {
             throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
          } else {
             ...
             return p_189516_1_;
          }
       }

    The TileEntityType.getKey method uses depreciated methods, so I'm not sure how to bug fix that, but I believe it is just looking for the name to which I registered the TE.  

    EDIT:

    I figured out that because my LimitedSpawnerTileEntity was extending SpawnerTileEntity, that the constructor was passing TileEntityType.MOB_SPAWNER to TileEntity through super, even thought I should have passed ModTileEntityType.LIMITED_MOB_SPAWNER. Once I did that, and removed the SpawnerTileEntity extension and extended TileEntity directly, the mapping was resolved. I still have an issue with modifying the existing spawner behavior, because now when dungeons feature checks if the spawner is an instance of SpawnerTileEntity, it returns false. I know that Java inheritence doesn't allow for a way to access the super of the super (intending to pass the modded TE type instead), how else should I best do this?

  7. Update: I resolved the mapping issue by registering with .setRegistryName("mob_spawner") instead of  .setRegistryName("minecraft", "mob_spawner"). I still get the following errors, and the spawner blocks that spawn are empty:

    [15:26:03] [Render thread/WARN] [minecraft/ClientPlayNetHandler]: Received passengers for unknown entity
    [15:26:03] [Server thread/WARN] [minecraft/TileEntity]: Block entity invalid: minecraft:mob_spawner @ BlockPos{x=651, y=69, z=-10735}

    I've tracked down that the TileEntity messages comes from isValid(), which checks if it is in the Set of valid blocks, determined by:

    public TileEntityType(Supplier<? extends T> p_i51497_1_, Set<Block> p_i51497_2_, Type<?> p_i51497_3_) {
          this.factory = p_i51497_1_;
          this.validBlocks = p_i51497_2_;
          this.dataType = p_i51497_3_;
       }

    But, shouldn't this be handled by the TileEntityType registry?

  8. I've created my own spawner block, called LimitedSpawnerBlock (extending SpawnerBlock), which returns a LimitedMobSpawnerTileEntity (extending MobSpawnerTileEntity) upon calling the overriden LimitedSpawnerBlock#createTileEntity, which owns a LimitedAbstractSpawner (extending AbstractSpawner)--- set up just like the Vanilla code...

    My goal is for the spawner block to break after so many spawns (like how RLCraft spawners have health). The LimitedMobSpawnerTileEntity stores health, which decrements on spawn, and calls for the LimitedSpawnerBlock to be deleted from the world when health reaches zero.

    I've registered the LimitedSpawnerBlock as "minecraft:spawner" and the TileEntityType<LimitedMobSpawnerTileEntity> as "minecraft:mob_spawner". 

    I've read the docs on tile entities and yet get this error, crashing my game when I place a spawner, and not loading chunks that should have a spawner:

    Spoiler
    [15:15:58] [Render thread/WARN] [minecraft/ClientPlayNetHandler]: Received passengers for unknown entity
    [15:16:08] [Server thread/ERROR] [minecraft/Chunk]: A TileEntity type com.izofar.izomod.tileentity.LimitedMobSpawnerTileEntity has thrown an exception trying to write state. It will not persist, Report this to the mod author
    java.lang.RuntimeException: class com.izofar.izomod.tileentity.LimitedMobSpawnerTileEntity is missing a mapping! This is a bug!
            at net.minecraft.tileentity.TileEntity.saveMetadata(TileEntity.java:64) ~[forge:?] {re:classloading}
            at net.minecraft.tileentity.TileEntity.save(TileEntity.java:58) ~[forge:?] {re:classloading}
            at net.minecraft.tileentity.MobSpawnerTileEntity.save(MobSpawnerTileEntity.java:47) ~[forge:?] {re:classloading}
            at com.izofar.izomod.tileentity.LimitedMobSpawnerTileEntity.save(LimitedMobSpawnerTileEntity.java:52) ~[?:?] {re:classloading}
            at net.minecraft.world.chunk.Chunk.getBlockEntityNbtForSaving(Chunk.java:427) ~[forge:?] {re:classloading}
            at net.minecraft.world.chunk.storage.ChunkSerializer.write(ChunkSerializer.java:287) ~[forge:?] {re:classloading}
            at net.minecraft.world.server.ChunkManager.save(ChunkManager.java:682) ~[forge:?] {re:classloading}
            at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174) ~[?:1.8.0_291] {}
            at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_291] {}
            at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_291] {}
            at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384) ~[?:1.8.0_291] {}
            at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[?:1.8.0_291] {}
            at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[?:1.8.0_291] {}
            at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:1.8.0_291] {}
            at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:1.8.0_291] {}
            at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_291] {}
            at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_291] {}
            at net.minecraft.world.server.ChunkManager.saveAllChunks(ChunkManager.java:337) ~[forge:?] {re:classloading}
            at net.minecraft.world.server.ServerChunkProvider.save(ServerChunkProvider.java:307) ~[forge:?] {re:classloading,pl:accesstransformer:B}
            at net.minecraft.world.server.ServerWorld.save(ServerWorld.java:698) ~[forge:?] {re:classloading}
            at net.minecraft.server.MinecraftServer.saveAllChunks(MinecraftServer.java:532) ~[forge:?] {re:classloading,pl:accesstransformer:B}
            at net.minecraft.server.MinecraftServer.stopServer(MinecraftServer.java:568) ~[forge:?] {re:classloading,pl:accesstransformer:B}
            at net.minecraft.server.integrated.IntegratedServer.stopServer(IntegratedServer.java:167) ~[forge:?] {re:classloading,pl:runtimedistcleaner:A}
            at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:679) ~[forge:?] {re:classloading,pl:accesstransformer:B}
            at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:232) ~[forge:?] {re:classloading,pl:accesstransformer:B}
            at java.lang.Thread.run(Thread.java:748) [?:1.8.0_291] {}

    This is my LimitedMobSpawnerTileEntity class:

    Spoiler
    public class LimitedMobSpawnerTileEntity extends MobSpawnerTileEntity {
    
    	private AbstractSpawner spawner;
    	
    	public LimitedMobSpawnerTileEntity() {
    		super();
    		this.spawner = new LimitedAbstractSpawner(this) {
    			public void broadcastEvent(int p_98267_1_) {
    				LimitedMobSpawnerTileEntity.this.level.blockEvent(LimitedMobSpawnerTileEntity.this.worldPosition, ModBlocks.LIMITED_SPAWNER, p_98267_1_, 0);		
    			}
    
    			public World getLevel() {
    				return LimitedMobSpawnerTileEntity.this.level;
    			}
    
    			public BlockPos getPos() {
    				return LimitedMobSpawnerTileEntity.this.worldPosition;
    			}
    			
    			public void setNextSpawnData(WeightedSpawnerEntity p_184993_1_) {
    		        super.setNextSpawnData(p_184993_1_);
    		        if (this.getLevel() != null) {
    		           BlockState blockstate = this.getLevel().getBlockState(this.getPos());
    		           this.getLevel().sendBlockUpdated(LimitedMobSpawnerTileEntity.this.worldPosition, blockstate, blockstate, 4);
    		        }
    		     }
    		};
    	}
    	
    	public void destroy(World world) {
    		world.removeBlockEntity(this.getBlockPos());
    	}
    	
    	@Override
    	public CompoundNBT save(CompoundNBT nbt) {
    		return super.save(nbt);
    	}
    
    	@Override
    	public void load(BlockState state, CompoundNBT nbt) {
    		super.load(state, nbt);
    	}
    }

    I'm not sure what is wrong with the mapping?

  9. I am making a modded armor item that replaces itself with another tier of armor on break. The replacement tier is used to craft the modded armor. I want the replacement armor to have the same durability as the ingredient did when it was used in crafting the modded armor. Is there a way to get the damage value in the json? Do I have to mod my own recipe class? Where would I store this damage value, in preparation for break, a modded itemstack class?

     

    In addition, I want the durability of the armor on crafting to be proportional to that of the durability of of the ingredient. Currently, the modded armor has less durability, but is stronger than the ingredient. So, crafting with an almost-broken ingredient gives negative durability to the modded armor.

     

    Not sure the best way to approach this, thanks!

  10. I may have posted this prematurely... I came across the WorldTickEvent hook through which I can access the ServerWorld. 

    I'd still appreciate any feedback from more knowledgeable modders... would my implementation with WorldTickEvent be equivalent according to my specification in my original post?

    Otherwise, I hope this is useful reference to anyone experiencing the same problem.

  11. So I am trying to invoke a custom siege (rather than a zombie siege). I want this event to be independent of zombie sieges (ruling out cancelling the zombie siege event hook). The following code in ServerWorld#tickCustomSpawners loops through the ISpecialSpawners, one of which is a net.minecraft.village.VillageSiege:

    public void tickCustomSpawners(boolean p_241123_1_, boolean p_241123_2_) {
          for(ISpecialSpawner ispecialspawner : this.customSpawners) {
             ispecialspawner.tick(this, p_241123_1_, p_241123_2_);
          }
       }

    I've written my own Siege class... almost identical to VillageSiege for now... and I want it to tick on the ServerWorld with siegeObject.tick(serverWorld, bool1, bool2). However, I can't access the ServerWorld of a ServerTickEvent. Is there a static ServerWorld I can access for my purposes? Or is there a better event hook I can use that will offer up the ServerWorld object?

  12. 20 hours ago, ChampionAsh5357 said:

    check if the chunk is loaded at the position of spawning

    The Chunk#isLoaded seems to be depreciated, nor is there a ChunkLoader#chunkExists (my research)... what's the new way of doing this? The Chunk#loaded field is private, and the Chunk#getStatus method always returns ChunkStatus.FULL... I can get the chunk with entity.level.getChunk(entity.getBlockPosition()), but what then? Must I use reflection for this? Surely there's a cleaner way.

    What was previously isChunkLoaded (which Jabelar said World#isAreaLoaded utilizes) seems to be hasChunksAt, which is marked depreciated. Any guidance on this?

  13. 3 hours ago, ChampionAsh5357 said:

    Reading the javadoc on the event tells you: "Note:  This event may be called before the underlying Chunk is promoted to ChunkStatus#FULL. You will cause chunk loading deadlocks if you don't delay your world interactions."

    As such, you should probably keep a queue of entities added along with the world and position you would like it to spawn at. Then, on the next tick in probably WorldTickEvent, check if the chunk is loaded at the position of spawning and if so spawn the entity. Otherwise, recycle into the queue until next tick.

    Is there an easier way to do this? How would the iron golem have spawned in the first place without chunk deadlocks? Is it easier to modify the villager behavior to spawn the modded entity instead?

  14. Goal

    My goal is to replace naturally spawning iron golems with my modded clay golems, but still allowing for players to build their own iron golems. I have the following SubscribeEvent:

    Code

    @SubscribeEvent
    public static void onIronGolemJoinWorld(EntityJoinWorldEvent event) {
    		if(event.getEntity() instanceof IronGolemEntity) {
    			if(event.getWorld() instanceof ServerWorld) {
    				IronGolemEntity entity = (IronGolemEntity) event.getEntity();
    				ServerWorld world = (ServerWorld)event.getWorld();
    				if(!entity.isPlayerCreated()) {
    					ExampleMod.LOGGER.info("Iron Golem Found!");
    					ModEntities.CLAY_GOLEM.spawn(world, null, null, entity.blockPosition(), SpawnReason.MOB_SUMMONED, false, false);
    					ExampleMod.LOGGER.info("Spawned Clay Golem");
    				
    				}
    			}
    			event.setCanceled(true);
    			ExampleMod.LOGGER.info("Removed Iron Golem");
    		}
    	}

    Context

    I Hope This Isn't a Duplicate Question, I have read the link but still do not understand what I've done wrong. I have read the vanilla code and understand that in order to call the private World#addEntity, I must call ServerWorld#addFreshEntity (true for spawning golems with pumpkins, and silverfish blocks, etc.). Alternatively, spawn eggs call EntityType<?>#spawn, but check that the world parameter is a ServerWorld.

    The result of the code above is the same as when I use:

    ClayGolemEntity claygolementity = ModEntities.CLAY_GOLEM.create(world);
    ExampleMod.LOGGER.info("Created Clay Golem");
    claygolementity.moveTo(entity.position());
    ExampleMod.LOGGER.info("Moved Clay Golem");
    world.addFreshEntity(claygolementity);
    ExampleMod.LOGGER.info("Spawned Clay Golem");

    Results

    My issue is that the following occurs:

    (1) using /summon examplemod:iron_golem spawns in a clay golem. Not ideal, but I'm fine with this at the moment.

    (2) Constructing Iron Golems constructs and iron golem, as intended

    (3) Any naturally spawning golems in villages lags out the game to the point of needing to force quit.

    (4) using /summon to spawn an iron golem (with the event.canceled(true) commented out) and then reloading the world lags out as well.

    The last print statement is either "Iron Golem Found" as in the first code example, or "Moved Clay Golem" as in the second code example.

    I appreciate the help. I haven't yet been able to spawn an entity in the world in code yet.

  15. 6 hours ago, diesieben07 said:

    You override this method in your item class.

    The IForgeItem method ends up being called in the following snippet by makesPiglingsNeutral:

    public static boolean isWearingGold(LivingEntity p_234460_0_) {
          for(ItemStack itemstack : p_234460_0_.getArmorSlots()) {
             Item item = itemstack.getItem();
             if (itemstack.makesPiglinsNeutral(p_234460_0_)) {
                return true;
             }
          }
    
          return false;
       }

    And the default IForgeItemStack method is:

    default boolean makesPiglinsNeutral(LivingEntity wearer)
        {
            return getStack().getItem().makesPiglinsNeutral(getStack(), wearer);
        }

    Will getItem().makesPiglingsNeutral return my overridden method? Or the default, since getItem() will return type Item rather than my ModdedArmorItem class?

  16. Part 1) I want to add an armor material that piglins won't attack. I've traced a single line of code... if only I could modify! In IForgeItem#makesPiglinsNeutral, the input is checked that it is of gold material. How do I add my custom Armor material to this? Do I need reflection, or does forge allow an easier way to achieve/override this?

    This method is called by IForgeItemStack#makesPiglinsNeutral, which is called by entity.monster.piglin.PiglinTasks#isWearingGold, called by PiglinMobSensor#doTick to update MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD

    Part 2) I want to extend this behavior to piglin brutes. This likely requires an exponentially more difficult workaround. Any insight to this, and generally overriding vanilla mob features that aren't represented in Forge events?

  17. 6 minutes ago, diesieben07 said:

    generics in this case

    I'm familiar with generics, just not its use in function definitions. I appreciate your patience.

    6 minutes ago, diesieben07 said:

    How does one use the Consumer<T> input?

    I at first failed to notice that this is a Java-specific concept not attributable to Forge. I apologize for the Java questions. Thank you for your help.

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.