Jump to content

Mikul

Members
  • Posts

    7
  • Joined

  • Last visited

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Mikul's Achievements

Tree Puncher

Tree Puncher (2/8)

1

Reputation

  1. I personally create registries using DataPackRegistryEvent.NewRegistry. It's pretty powerful as long as you know how to make codecs. In some class, make a registry key like so: public static final ResourceKey<Registry<MyDataType>> MY_REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(MyMod.MOD_ID, "registry_name")); This will make a registry that holds objects of type "MyDataType". JSON files stored in data/<datapack_namespace>/modid/registryname/ will be parsed and put into this registry. Note that the directory structure has a folder named after your mod inside your datapack directory, so the actual path would look like: data/my_mod/my_mod/registry_name (or if another mod uses your registry: data/their_mod/my_mod/registry_name. To register this registry, subscribe to the DataPackRegistryEvent.NewRegistry event on the MOD event bus and call event.dataPackRegistry() for every registry you have. An example of what I'm doing for my mod (this is in the constructor for the main mod file): IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); bus.addListener((DataPackRegistryEvent.NewRegistry event) -> { event.dataPackRegistry(ModRegistries.INSULATOR_DATA, InsulatorData.CODEC); }); CODEC is a public static field inside the class for the custom data type I am registering. It holds a Codec<InsulatorData> that tells Minecraft how to serialize/deserialize the data. Most of my data so far can be represented by records, so I use RecordCodecBuilder.create() to do this: public static final Codec<InsulatorData> CODEC = RecordCodecBuilder.create(instance -> instance.group( // Yadda yadda ).apply(instance, InsulatorData::new)); What exactly to put here depends on what you're trying to do, so that's up to you. But basically you're just defining a list of codecs that correspond to the parameters of the record (data type). Most primitive data types have records in the Codec class (ex. Codec.INT) that you can use, and other classes like ResourceLocation have their own codecs as a static field (ex. ResourceLocation.CODEC). Hopefully this is what you're looking for, and that this helps.
  2. Making a custom biome modifier worked. I just need a dummy JSON file for the modifier to be loaded, then it injects the spawns according to the config settings. I also added an option to disable this, if the user wanted to define the spawns the normal way. It looks something like this: // This is a generic version of my implementation, without all the stuff specific to my mod @Override public void modify(Holder<Biome> biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { // Ensure proper phase and user is using configs if (phase == Phase.ADD && useConfigs) { // Null check for optional ResourceKey biome.unwrapKey().ifPresent(biomeKey -> { ResourceLocation biomeID = biomeKey.location(); // I have a static map of the user's configured spawn weights parsed from the config Integer weight = MAP_OF_ENTITY_WEIGHTS.get(biomeID); // Weight is null if undefined if (weight != null) { builder.getMobSpawnSettings().addSpawn(MobCategory.CREATURE, new MobSpawnSettings.SpawnerData(MyEntity, weight, 1, 1)); } }); } } This also has no problems with other mods' biomes being present or not, since it's only called for existing biomes in the registry. Thanks for pointing me in the right direction. I needed to take a second look at custom biome modifiers to see how to do this.
  3. I'd recommend using (stack.getEquipmentSlot() == EquipmentSlot.CHEST) instead. All you need to do is check if it's the correct slot, not if the stacks are equal. Also it isn't necessary to do this every tick. Although the logic of the IF statement is pretty simple, Minecraft does a lot of stuff when adding potion effects (mainly syncing the player data). Every 5 ticks or so would be good enough, which you can do by checking if (player.tickCount % 5 == 0).
  4. Alright, then I'll look into making my own. Thank you for the suggestion. If biome modifiers are a Forge construct then I might suggest that optionality be added To the built-in ones.
  5. I think I've misunderstood how data generation works. I thought GatherDataEvent was called at runtime, but I've found that it's only used for generating static JSON files when runData is executed, which are shipped with the mod. It seems to me that it's now impossible to do this in the way that I originally had. And I now have another concern about these data-driven biome modifiers. How is inter-mod compatibility implemented? Say I wanted my entity to spawn in rainforests from Biomes O' Plenty (optional dependency). If I make a file adding the mob to "biomesoplenty:rainforest", datapack loading now fails unless the "biomesoplenty" is loaded. I cannot find any way to make this an "optional" biome modifier, similar to how tags can be optional. Am I missing something?
  6. I understand that it's their intended purpose, and they're definitely much more versatile, but I find them more cumbersome to use than the configs I had set up before, and I think most of my user base would agree. Plus, what I'm attempting to do wouldn't prevent anyone from using a data pack if they want, to my knowledge.
  7. I'm currently updating my mod from 1.18, which previously allowed players to define the spawn weight of my custom entity for any biome via .TOML config files. This was done by subscribing to BiomeLoadingEvent and adding to the spawn list. That event has now been removed in favor of the new data-driven system, which I am still trying to fully grasp. My current idea is to hook into GatherDataEvent and iterate through the list of user-defined biomes from the config, but the issue is that the configs aren't loaded at this stage, and runData crashes because the ForgeConfigSpec isn't initialized yet. Here's what I currently have: @SubscribeEvent public static void gatherData(GatherDataEvent event) { DataGenerator generator = event.getGenerator(); ExistingFileHelper helper = event.getExistingFileHelper(); RegistryOps<JsonElement> registryOps = RegistryOps.create(JsonOps.INSTANCE, RegistryAccess.builtinCopy()); <...> EntityType<ChameleonEntity> chameleon = EntityInit.CHAMELEON.get(); ConfigSettings.CHAMELEON_BIOMES.get().forEach((biomeID, weight) -> { ForgeRegistries.BIOMES.getHolder(biomeID).ifPresent(biomeHolder -> { modifiers.put(new ResourceLocation(ColdSweat.MOD_ID, "chameleon_spawns_" + biomeID.getNamespace() + "_" + biomeID.getPath()), ForgeBiomeModifiers.AddSpawnsBiomeModifier.singleSpawn(HolderSet.direct(biomeHolder), new MobSpawnSettings.SpawnerData(chameleon, weight, 1, 1))); }); }); JsonCodecProvider<BiomeModifier> jsonCodecProvider = JsonCodecProvider.forDatapackRegistry(generator, helper, ColdSweat.MOD_ID, registryOps, ForgeRegistries.Keys.BIOME_MODIFIERS, modifiers); generator.addProvider(event.includeServer(), jsonCodecProvider); } And here's the code on GitHub: https://github.com/Momo-Studios/Cold-Sweat/blob/1.19.x-FG/src/main/java/dev/momostudios/coldsweat/data/ColdSweatData.java Is there a way to access the configs at this stage, or should I be using another way? I'd highly prefer using the configs since they're simpler to edit for users.
×
×
  • Create New...

Important Information

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