From ff0722f6509bf3cd6b371e2a89dbe7706b75f841 Mon Sep 17 00:00:00 2001 From: noeppi_noeppi Date: Sun, 26 Jan 2025 18:40:35 +0100 Subject: [PATCH] LibX 1.21 --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +- .github/workflows/docs-deploy.yml | 10 +- .github/workflows/test-prs.yml | 8 +- build.gradle | 99 +++-- gradle/wrapper/gradle-wrapper.properties | 2 +- mod.properties | 26 +- settings.gradle | 8 + .../libx/annotation/processor/Classes.java | 15 +- .../annotation/processor/ProcessorEnv.java | 2 +- ...gsProcessor.java => NullityProcessor.java} | 6 +- .../annotation/processor/modinit/ModInit.java | 14 +- .../register/RegisterClassProcessor.java | 2 +- .../registration/RegisterClass.java | 2 +- .../javax.annotation.processing.Processor | 2 +- src/coremods/cache | 5 - src/coremods/coremods/holder_serialize.js | 28 -- src/coremods/coremods/holder_serialize.ts | 42 -- src/coremods/coremods/interact.js | 38 -- src/coremods/coremods/interact.ts | 52 --- src/coremods/coremods/level_load.ts | 36 -- src/coremods/coremods/registry_load.ts | 41 -- .../moddingx/libx/vanilla/TemplatePools.java | 329 ++++++++------ .../impl_all_hanging_signs.json | 0 .../tags/{blocks => block}/impl_buttons.json | 0 .../impl_ceiling_hanging_signs.json | 0 .../tags/{blocks => block}/impl_doors.json | 0 .../{blocks => block}/impl_fence_gates.json | 0 .../tags/{blocks => block}/impl_fences.json | 0 .../tags/{blocks => block}/impl_logs.json | 0 .../impl_logs_that_burn.json | 0 .../impl_pressure_plates.json | 0 .../tags/{blocks => block}/impl_signs.json | 0 .../tags/{blocks => block}/impl_slabs.json | 0 .../tags/{blocks => block}/impl_stairs.json | 0 .../impl_standing_signs.json | 0 .../{blocks => block}/impl_stone_buttons.json | 0 .../impl_stone_pressure_plates.json | 0 .../{blocks => block}/impl_trapdoors.json | 0 .../impl_wall_hanging_signs.json | 0 .../{blocks => block}/impl_wall_signs.json | 0 .../tags/{blocks => block}/impl_walls.json | 0 .../impl_wooden_buttons.json | 0 .../{blocks => block}/impl_wooden_doors.json | 0 .../{blocks => block}/impl_wooden_fences.json | 0 .../impl_wooden_pressure_plates.json | 0 .../{blocks => block}/impl_wooden_slabs.json | 0 .../{blocks => block}/impl_wooden_stairs.json | 0 .../impl_wooden_trapdoors.json | 0 .../tags/{items => item}/impl_buttons.json | 0 .../libx/tags/{items => item}/impl_doors.json | 0 .../{items => item}/impl_fence_gates.json | 0 .../tags/{items => item}/impl_fences.json | 0 .../{items => item}/impl_hanging_signs.json | 0 .../libx/tags/{items => item}/impl_logs.json | 0 .../{items => item}/impl_logs_that_burn.json | 0 .../libx/tags/{items => item}/impl_signs.json | 0 .../libx/tags/{items => item}/impl_slabs.json | 0 .../tags/{items => item}/impl_stairs.json | 0 .../{items => item}/impl_stone_buttons.json | 0 .../tags/{items => item}/impl_trapdoors.json | 0 .../libx/tags/{items => item}/impl_walls.json | 0 .../{items => item}/impl_wooden_buttons.json | 0 .../{items => item}/impl_wooden_doors.json | 0 .../{items => item}/impl_wooden_fences.json | 0 .../impl_wooden_pressure_plates.json | 0 .../{items => item}/impl_wooden_slabs.json | 0 .../{items => item}/impl_wooden_stairs.json | 0 .../impl_wooden_trapdoors.json | 0 .../{blocks => block}/all_hanging_signs.json | 0 .../tags/{blocks => block}/buttons.json | 0 .../ceiling_hanging_signs.json | 0 .../tags/{blocks => block}/doors.json | 0 .../tags/{blocks => block}/fence_gates.json | 0 .../tags/{blocks => block}/fences.json | 0 .../tags/{blocks => block}/logs.json | 0 .../{blocks => block}/logs_that_burn.json | 0 .../{blocks => block}/pressure_plates.json | 0 .../tags/{blocks => block}/signs.json | 0 .../tags/{blocks => block}/slabs.json | 0 .../tags/{blocks => block}/stairs.json | 0 .../{blocks => block}/standing_signs.json | 0 .../tags/{blocks => block}/stone_buttons.json | 0 .../stone_pressure_plates.json | 0 .../tags/{blocks => block}/trapdoors.json | 0 .../{blocks => block}/wall_hanging_signs.json | 0 .../tags/{blocks => block}/wall_signs.json | 0 .../tags/{blocks => block}/walls.json | 0 .../{blocks => block}/wooden_buttons.json | 0 .../tags/{blocks => block}/wooden_doors.json | 0 .../tags/{blocks => block}/wooden_fences.json | 0 .../wooden_pressure_plates.json | 0 .../tags/{blocks => block}/wooden_slabs.json | 0 .../tags/{blocks => block}/wooden_stairs.json | 0 .../{blocks => block}/wooden_trapdoors.json | 0 .../tags/{items => item}/buttons.json | 0 .../minecraft/tags/{items => item}/doors.json | 0 .../tags/{items => item}/fence_gates.json | 0 .../tags/{items => item}/fences.json | 0 .../tags/{items => item}/hanging_signs.json | 0 .../minecraft/tags/{items => item}/logs.json | 0 .../tags/{items => item}/logs_that_burn.json | 0 .../minecraft/tags/{items => item}/signs.json | 0 .../minecraft/tags/{items => item}/slabs.json | 0 .../tags/{items => item}/stairs.json | 0 .../tags/{items => item}/stone_buttons.json | 0 .../tags/{items => item}/trapdoors.json | 0 .../minecraft/tags/{items => item}/walls.json | 0 .../tags/{items => item}/wooden_buttons.json | 0 .../tags/{items => item}/wooden_doors.json | 0 .../tags/{items => item}/wooden_fences.json | 0 .../wooden_pressure_plates.json | 0 .../tags/{items => item}/wooden_slabs.json | 0 .../tags/{items => item}/wooden_stairs.json | 0 .../{items => item}/wooden_trapdoors.json | 0 .../java/org/moddingx/libx/CommonNetwork.java | 12 +- src/main/java/org/moddingx/libx/LibX.java | 86 ++-- .../org/moddingx/libx/annotation/ForMod.java | 2 +- .../moddingx/libx/annotation/api/Codecs.java | 10 +- .../annotation/impl/ProcessorInterface.java | 90 ++-- .../org/moddingx/libx/base/BlockBase.java | 26 +- .../org/moddingx/libx/base/FluidBase.java | 371 ++++++++-------- .../org/moddingx/libx/base/ItemInventory.java | 102 +---- .../org/moddingx/libx/base/MenuBlock.java | 26 +- .../libx/base/decoration/DecoratedBlock.java | 10 +- .../base/decoration/DecorationContext.java | 12 +- .../base/decoration/DecorationMaterial.java | 12 +- .../libx/base/decoration/DecorationType.java | 3 +- .../org/moddingx/libx/base/tile/BlockBE.java | 34 +- .../libx/base/tile/BlockEntityBase.java | 46 +- .../libx/base/tile/GameEventBlock.java | 3 +- .../moddingx/libx/base/tile/MenuBlockBE.java | 29 +- .../libx/capability/ItemCapabilities.java | 100 ----- .../libx/capability/SimpleProvider.java | 70 --- .../org/moddingx/libx/codec/CodecHelper.java | 14 - .../org/moddingx/libx/codec/CodecOps.java | 106 ----- .../org/moddingx/libx/codec/MoreCodecs.java | 57 +-- .../moddingx/libx/codec/MoreStreamCodecs.java | 121 ++++++ ...ment2.java => EnumArgumentIgnoreCase.java} | 26 +- .../moddingx/libx/config/ConfigManager.java | 129 ++++-- .../moddingx/libx/config/gui/EditorOps.java | 15 +- .../config/mapper/GenericValueMapper.java | 21 +- .../libx/config/mapper/ValueMapper.java | 23 +- .../libx/crafting/IngredientStack.java | 56 +-- .../moddingx/libx/crafting/RecipeHelper.java | 58 +-- .../crafting/ingredient/EffectIngredient.java | 230 +++------- .../libx/creativetab/CreativeTabX.java | 24 +- .../moddingx/libx/datagen/DatagenContext.java | 2 +- .../moddingx/libx/datagen/DatagenSystem.java | 62 ++- .../libx/datagen/RegistryProvider.java | 14 + .../moddingx/libx/datagen/RegistrySet.java | 2 +- .../libx/datagen/loot/LootBuilders.java | 6 +- .../provider/AdvancementProviderBase.java | 293 +++++++------ .../provider/DamageTypeProviderBase.java | 2 +- .../provider/EnchantmentProviderBase.java | 410 ++++++++++++++++++ .../provider/RegistryProviderBase.java | 31 +- .../provider/SoundDefinitionProviderBase.java | 22 +- .../provider/loot/BlockLootProviderBase.java | 58 +-- .../provider/loot/EntityLootProviderBase.java | 29 +- .../provider/loot/GlobalLootProviderBase.java | 11 +- .../provider/loot/LootProviderBase.java | 92 ++-- .../model/BlockStateProviderBase.java | 125 +++--- .../provider/model/ItemModelProviderBase.java | 89 ++-- .../provider/patchouli/EntryBuilder.java | 10 +- .../patchouli/PatchouliProviderBase.java | 6 +- .../provider/patchouli/page/PageJson.java | 41 +- .../provider/recipe/DefaultExtension.java | 4 +- .../provider/recipe/RecipeExtension.java | 41 +- .../provider/recipe/RecipeProviderBase.java | 51 +-- .../provider/recipe/RemovalExtension.java | 2 +- .../provider/recipe/SmeltingExtension.java | 16 +- .../provider/recipe/SmithingExtension.java | 6 +- .../recipe/StoneCuttingExtension.java | 10 +- .../recipe/crafting/CompressionExtension.java | 8 +- .../recipe/crafting/ToolExtension.java | 40 +- .../sandbox/AnyTemplateProviderBase.java | 28 +- .../sandbox/BiomeModifierProviderBase.java | 25 +- .../sandbox/DimensionTypeProviderBase.java | 2 +- .../provider/sandbox/NoiseProviderBase.java | 8 +- .../sandbox/StructureProviderBase.java | 51 ++- .../provider/sandbox/SurfaceProviderBase.java | 4 +- .../provider/tags/CommonTagsProviderBase.java | 17 +- .../provider/texture/TextureBuilder.java | 4 +- .../provider/texture/TextureProviderBase.java | 24 +- .../datagen/provider/texture/Textures.java | 4 +- .../moddingx/libx/datapack/DataLoader.java | 11 +- .../libx/datapack/DatapackHelper.java | 23 +- .../moddingx/libx/datapack/DynamicPacks.java | 6 +- .../libx/event/ConfigLoadedEvent.java | 2 +- .../event/InteractBlockEmptyHandEvent.java | 12 +- .../org/moddingx/libx/event/package-info.java | 4 +- .../libx/impl/BlockEntityUpdateQueue.java | 25 +- .../org/moddingx/libx/impl/ModInternal.java | 49 ++- .../libx/impl/RendererOnDataGenException.java | 11 - .../impl/base/decoration/BaseMaterial.java | 59 ++- .../base/decoration/BlockDecorationType.java | 3 +- .../impl/base/decoration/DecorationTypes.java | 4 +- .../decoration/blocks/DecoratedButton.java | 5 +- .../decoration/blocks/DecoratedDoorBlock.java | 5 +- .../blocks/DecoratedFenceBlock.java | 5 +- .../blocks/DecoratedFenceGateBlock.java | 5 +- .../blocks/DecoratedHangingSign.java | 17 +- .../blocks/DecoratedPressurePlate.java | 9 +- .../base/decoration/blocks/DecoratedSign.java | 15 +- .../decoration/blocks/DecoratedSlabBlock.java | 5 +- .../blocks/DecoratedStairBlock.java | 5 +- .../blocks/DecoratedTrapdoorBlock.java | 5 +- .../decoration/blocks/DecoratedWallBlock.java | 5 +- .../decoration/blocks/DecoratedWoodBlock.java | 15 +- .../impl/base/fluid/DefaultBucketItem.java | 47 ++ .../base/fluid/DefaultClientExtensions.java | 14 +- .../libx/impl/base/fluid/FluidTypeBase.java | 24 - .../moddingx/libx/impl/codec/EnumCodec.java | 4 +- .../moddingx/libx/impl/codec/FixedCodec.java | 3 +- .../libx/impl/codec/MapDispatchedCodec.java | 12 +- .../moddingx/libx/impl/codec/OptionCodec.java | 3 +- .../libx/impl/codec/TypeMappedCodec.java | 4 +- .../client/ClientCommandsImpl.java | 4 +- .../client/ModListCommand.java | 8 +- .../client/ReloadClientCommand.java | 2 +- .../common/CommandsImpl.java | 9 +- .../common/EntityDataCommand.java | 6 +- .../common/HandCommand.java | 49 +-- .../common/ReloadCommonCommand.java | 10 +- .../libx/impl/config/ConfigEvents.java | 20 +- .../moddingx/libx/impl/config/ConfigImpl.java | 38 +- .../moddingx/libx/impl/config/ConfigKey.java | 4 + .../libx/impl/config/ConfigState.java | 3 +- .../moddingx/libx/impl/config/ModMappers.java | 47 +- .../impl/config/gui/ModConfigGuiAdapter.java | 12 +- .../impl/config/gui/editor/CheckEditor.java | 32 +- .../impl/config/gui/editor/OptionEditor.java | 17 +- .../config/gui/screen/ConfigBaseScreen.java | 22 +- .../screen/content/ResourceListContent.java | 4 +- .../content/component/ComponentContent.java | 19 +- .../component/type/TextComponentType.java | 9 +- .../config/mappers/SimpleValueMappers.java | 78 +--- .../advanced/ComponentValueMapper.java | 9 +- .../advanced/IngredientStackValueMapper.java | 55 --- .../advanced/IngredientValueMapper.java | 55 --- .../advanced/ResourceListValueMapper.java | 27 +- .../mappers/advanced/ResourceValueMapper.java | 18 +- .../mappers/advanced/UidValueMapper.java | 18 +- .../mappers/generic/ListValueMapper.java | 23 +- .../mappers/generic/MapValueMapper.java | 25 +- .../mappers/generic/OptionValueMapper.java | 24 +- .../mappers/generic/SetValueMapper.java | 23 +- ...ValueMappers.java => EnumValueMapper.java} | 57 ++- .../mappers/special/PairValueMapper.java | 19 +- .../mappers/special/RecordValueMapper.java | 101 +++-- .../mappers/special/TripleValueMapper.java | 22 +- .../config/wrapper/JsonTypesafeMapper.java | 14 +- .../impl/config/wrapper/TypesafeMapper.java | 19 +- .../config/wrapper/WrappedGenericMapper.java | 14 +- .../impl/crafting/recipe/EmptyRecipe.java | 101 ++--- .../impl/datagen/load/DatagenFontLoader.java | 18 +- .../libx/impl/datagen/load/DatagenLoader.java | 2 +- .../datagen/load/DatagenRegistryLoader.java | 34 +- .../libx/impl/datagen/loot/LootData.java | 10 +- .../model/TypedBlockModelProvider.java | 16 +- .../patchouli/content/EntityContent.java | 4 +- .../datagen/recipe/DecorationRecipes.java | 8 +- .../datagen/recipe/ObjectCraftingBuilder.java | 12 +- .../datagen/registries/DatagenRegistry.java | 14 +- .../registries/DatagenRegistrySet.java | 54 ++- .../datagen/resource/ResourceLocator.java | 4 +- .../impl/datagen/tags/DecorationTags.java | 2 +- .../impl/datapack/DynamicPackLocator.java | 44 +- .../moddingx/libx/impl/datapack/LibXPack.java | 90 ++-- .../inventory/AdvancedItemHandlerHelper.java | 55 +++ .../libx/impl/libxcore/CoreInteract.java | 4 +- .../moddingx/libx/impl/loot/AllLootEntry.java | 14 +- .../loot/CopyBlockEntityDataFunction.java | 101 +++++ .../loot/modifier/AdditionLootModifier.java | 31 +- .../loot/modifier/RemovalLootModifier.java | 16 +- ...GenericContainerSlotValidationWrapper.java | 67 --- .../libx/impl/menu/screen/GenericScreen.java | 46 -- .../libx/impl/network/BeRequestHandler.java | 43 ++ .../libx/impl/network/BeRequestMessage.java | 53 --- .../libx/impl/network/BeUpdateHandler.java | 56 +++ .../libx/impl/network/BeUpdateMessage.java | 61 --- .../impl/network/ConfigShadowHandler.java | 77 ++++ .../impl/network/ConfigShadowMessage.java | 78 ---- .../libx/impl/network/NetworkImpl.java | 86 ++-- .../libx/impl/reflect/ReflectionHacks.java | 53 --- .../registration/BuiltinRegistryHelper.java | 30 ++ .../registration/RegistrationDispatcher.java | 93 ++-- .../CapabilityRegistrationHandler.java | 65 +++ .../ClientExtensionRegistrationHandler.java | 98 +++++ .../handler/SpecialRegistrationHandler.java | 27 ++ .../registration/tracking/TrackingData.java | 187 -------- .../tracking/TrackingInstance.java | 40 -- .../impl/render/BlockOverlayQuadCache.java | 2 +- .../libx/impl/render/JobRenderer.java | 19 +- .../libx/impl/sandbox/EmptySurfaceRule.java | 5 +- .../libx/impl/sandbox/FakeHolder.java | 8 +- .../sandbox/layer/NoiseLayerSelector.java | 2 +- .../libx/impl/screen/text/SimpleLayout.java | 2 +- .../libx/inventory/BaseItemStackHandler.java | 54 +-- .../libx/inventory/FilterItemHandler.java | 67 +++ .../libx/inventory/IAdvancedItemHandler.java | 50 +-- .../IAdvancedItemHandlerModifiable.java | 2 +- .../libx/inventory/StackItemHandler.java | 145 +++++++ .../libx/inventory/VanillaWrapper.java | 2 +- .../moddingx/libx/inventory/package-info.java | 4 +- .../moddingx/libx/menu/BlockEntityMenu.java | 4 +- .../org/moddingx/libx/menu/BlockMenu.java | 58 +-- .../org/moddingx/libx/menu/DefaultMenu.java | 2 +- .../org/moddingx/libx/menu/EntityMenu.java | 58 +-- .../org/moddingx/libx/menu/GenericMenu.java | 240 ---------- .../java/org/moddingx/libx/menu/MenuBase.java | 8 +- .../org/moddingx/libx/menu/package-info.java | 2 +- .../org/moddingx/libx/menu/slot/BaseSlot.java | 4 +- .../moddingx/libx/menu/slot/OutputSlot.java | 4 +- .../libx/menu/type/AdvancedMenuFactory.java | 21 + .../libx/menu/type/AdvancedMenuType.java | 134 ++++++ src/main/java/org/moddingx/libx/mod/ModX.java | 18 +- .../moddingx/libx/mod/ModXRegistration.java | 11 +- .../libx/network/EnumDataSerializer.java | 19 +- .../libx/network/LoginPacketSerializer.java | 50 --- .../org/moddingx/libx/network/NetworkX.java | 237 ++++------ .../moddingx/libx/network/PacketHandler.java | 80 ++-- .../libx/network/PacketSerializer.java | 24 - .../moddingx/libx/network/RemoteModList.java | 37 -- .../libx/registration/Registerable.java | 50 +-- .../registration/RegistrationBuilder.java | 15 +- .../tracking/RegistryTracker.java | 115 ----- .../registration/util/CapabilityInfo.java | 71 +++ .../util/ClientExtensionInfo.java | 78 ++++ .../libx/registration/util/EnumObjects.java | 20 +- .../libx/render/ClientTickHandler.java | 8 +- .../libx/render/FilterGuiGraphics.java | 101 +++-- .../libx/render/ItemStackRenderer.java | 55 +-- .../moddingx/libx/render/RenderHelper.java | 10 +- .../libx/render/RenderHelperBlock.java | 18 +- .../libx/render/RenderHelperFluid.java | 4 +- .../libx/render/RenderHelperLevel.java | 11 +- .../ExtendedNoiseChunkGenerator.java | 13 +- .../sandbox/generator/LayeredBiomeSource.java | 6 +- .../placement/HeightPlacementFilter.java | 4 +- .../placement/InvertPlacementFilter.java | 4 +- .../org/moddingx/libx/screen/ColorPicker.java | 26 +- .../java/org/moddingx/libx/screen/Panel.java | 11 +- .../moddingx/libx/screen/text/TextScreen.java | 6 +- .../java/org/moddingx/libx/util/Misc.java | 2 +- .../moddingx/libx/util/data/ResourceList.java | 15 +- .../libx/util/game/ComponentUtil.java | 73 +++- .../libx/util/game/LongAmountToIntUtil.java | 3 +- .../game}/LongEnergyStorage.java | 5 +- .../moddingx/libx/util/lazy/LazyValue.java | 9 - .../libx/util/math/DoublePolynomial.java | 8 + .../libx/util/math/IntPolynomial.java | 8 + .../resources/META-INF/accesstransformer.cfg | 70 ++- src/main/resources/META-INF/coremods.json | 6 + .../{mods.toml => neoforge.mods.toml} | 14 +- .../resources/assets/libx/lang/de_de.json | 8 +- .../resources/assets/libx/lang/en_us.json | 8 +- .../resources/assets/libx/lang/pt_br.json | 8 +- .../resources/coremods/holder_serialize.js | 37 ++ src/main/resources/coremods/interact.js | 47 ++ .../resources}/coremods/level_load.js | 25 +- .../resources}/coremods/registry_load.js | 29 +- .../libx/sourcegen/LibXSourceGen.java | 12 +- .../libx/sourcegen/RegistryKeyProvider.java | 6 +- src/sourcegen/resources/META-INF/mods.toml | 8 - .../libx/test/AccessTransformerTest.java | 28 +- .../libx/test/FilterGuiGraphicsTest.java | 4 +- .../libx/test/ReflectionHacksTest.java | 54 +-- .../moddingx/libx/test/ResourcePackTest.java | 31 -- .../org/moddingx/libx/test/util/Mappings.java | 42 -- 369 files changed, 4823 insertions(+), 5207 deletions(-) rename src/ap/java/org/moddingx/libx/annotation/processor/misc/{FindBugsProcessor.java => NullityProcessor.java} (85%) delete mode 100644 src/coremods/cache delete mode 100644 src/coremods/coremods/holder_serialize.js delete mode 100644 src/coremods/coremods/holder_serialize.ts delete mode 100644 src/coremods/coremods/interact.js delete mode 100644 src/coremods/coremods/interact.ts delete mode 100644 src/coremods/coremods/level_load.ts delete mode 100644 src/coremods/coremods/registry_load.ts rename src/generated/resources/data/libx/tags/{blocks => block}/impl_all_hanging_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_buttons.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_ceiling_hanging_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_doors.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_fence_gates.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_fences.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_logs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_logs_that_burn.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_pressure_plates.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_slabs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_stairs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_standing_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_stone_buttons.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_stone_pressure_plates.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_trapdoors.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wall_hanging_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wall_signs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_walls.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_buttons.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_doors.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_fences.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_pressure_plates.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_slabs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_stairs.json (100%) rename src/generated/resources/data/libx/tags/{blocks => block}/impl_wooden_trapdoors.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_buttons.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_doors.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_fence_gates.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_fences.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_hanging_signs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_logs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_logs_that_burn.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_signs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_slabs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_stairs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_stone_buttons.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_trapdoors.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_walls.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_buttons.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_doors.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_fences.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_pressure_plates.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_slabs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_stairs.json (100%) rename src/generated/resources/data/libx/tags/{items => item}/impl_wooden_trapdoors.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/all_hanging_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/ceiling_hanging_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/doors.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/fence_gates.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/fences.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/logs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/logs_that_burn.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/pressure_plates.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/slabs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/stairs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/standing_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/stone_buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/stone_pressure_plates.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/trapdoors.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wall_hanging_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wall_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/walls.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_doors.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_fences.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_pressure_plates.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_slabs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_stairs.json (100%) rename src/generated/resources/data/minecraft/tags/{blocks => block}/wooden_trapdoors.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/doors.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/fence_gates.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/fences.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/hanging_signs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/logs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/logs_that_burn.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/signs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/slabs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/stairs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/stone_buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/trapdoors.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/walls.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_buttons.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_doors.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_fences.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_pressure_plates.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_slabs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_stairs.json (100%) rename src/generated/resources/data/minecraft/tags/{items => item}/wooden_trapdoors.json (100%) delete mode 100644 src/main/java/org/moddingx/libx/capability/ItemCapabilities.java delete mode 100644 src/main/java/org/moddingx/libx/capability/SimpleProvider.java delete mode 100644 src/main/java/org/moddingx/libx/codec/CodecOps.java create mode 100644 src/main/java/org/moddingx/libx/codec/MoreStreamCodecs.java rename src/main/java/org/moddingx/libx/command/{EnumArgument2.java => EnumArgumentIgnoreCase.java} (83%) create mode 100644 src/main/java/org/moddingx/libx/datagen/provider/EnchantmentProviderBase.java delete mode 100644 src/main/java/org/moddingx/libx/impl/RendererOnDataGenException.java create mode 100644 src/main/java/org/moddingx/libx/impl/base/fluid/DefaultBucketItem.java delete mode 100644 src/main/java/org/moddingx/libx/impl/base/fluid/FluidTypeBase.java rename src/main/java/org/moddingx/libx/impl/{commands => command}/client/ClientCommandsImpl.java (83%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/client/ModListCommand.java (89%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/client/ReloadClientCommand.java (92%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/common/CommandsImpl.java (73%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/common/EntityDataCommand.java (88%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/common/HandCommand.java (52%) rename src/main/java/org/moddingx/libx/impl/{commands => command}/common/ReloadCommonCommand.java (68%) delete mode 100644 src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientStackValueMapper.java delete mode 100644 src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientValueMapper.java rename src/main/java/org/moddingx/libx/impl/config/mappers/special/{EnumValueMappers.java => EnumValueMapper.java} (63%) create mode 100644 src/main/java/org/moddingx/libx/impl/inventory/AdvancedItemHandlerHelper.java create mode 100644 src/main/java/org/moddingx/libx/impl/loot/CopyBlockEntityDataFunction.java delete mode 100644 src/main/java/org/moddingx/libx/impl/menu/GenericContainerSlotValidationWrapper.java delete mode 100644 src/main/java/org/moddingx/libx/impl/menu/screen/GenericScreen.java create mode 100644 src/main/java/org/moddingx/libx/impl/network/BeRequestHandler.java delete mode 100644 src/main/java/org/moddingx/libx/impl/network/BeRequestMessage.java create mode 100644 src/main/java/org/moddingx/libx/impl/network/BeUpdateHandler.java delete mode 100644 src/main/java/org/moddingx/libx/impl/network/BeUpdateMessage.java create mode 100644 src/main/java/org/moddingx/libx/impl/network/ConfigShadowHandler.java delete mode 100644 src/main/java/org/moddingx/libx/impl/network/ConfigShadowMessage.java create mode 100644 src/main/java/org/moddingx/libx/impl/registration/BuiltinRegistryHelper.java create mode 100644 src/main/java/org/moddingx/libx/impl/registration/handler/CapabilityRegistrationHandler.java create mode 100644 src/main/java/org/moddingx/libx/impl/registration/handler/ClientExtensionRegistrationHandler.java create mode 100644 src/main/java/org/moddingx/libx/impl/registration/handler/SpecialRegistrationHandler.java delete mode 100644 src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingData.java delete mode 100644 src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingInstance.java create mode 100644 src/main/java/org/moddingx/libx/inventory/FilterItemHandler.java create mode 100644 src/main/java/org/moddingx/libx/inventory/StackItemHandler.java delete mode 100644 src/main/java/org/moddingx/libx/menu/GenericMenu.java create mode 100644 src/main/java/org/moddingx/libx/menu/type/AdvancedMenuFactory.java create mode 100644 src/main/java/org/moddingx/libx/menu/type/AdvancedMenuType.java delete mode 100644 src/main/java/org/moddingx/libx/network/LoginPacketSerializer.java delete mode 100644 src/main/java/org/moddingx/libx/network/PacketSerializer.java delete mode 100644 src/main/java/org/moddingx/libx/network/RemoteModList.java delete mode 100644 src/main/java/org/moddingx/libx/registration/tracking/RegistryTracker.java create mode 100644 src/main/java/org/moddingx/libx/registration/util/CapabilityInfo.java create mode 100644 src/main/java/org/moddingx/libx/registration/util/ClientExtensionInfo.java rename src/main/java/org/moddingx/libx/{capability => util/game}/LongEnergyStorage.java (86%) create mode 100644 src/main/resources/META-INF/coremods.json rename src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (71%) create mode 100644 src/main/resources/coremods/holder_serialize.js create mode 100644 src/main/resources/coremods/interact.js rename src/{coremods => main/resources}/coremods/level_load.js (54%) rename src/{coremods => main/resources}/coremods/registry_load.js (50%) delete mode 100644 src/sourcegen/resources/META-INF/mods.toml delete mode 100644 src/test/java/org/moddingx/libx/test/ResourcePackTest.java delete mode 100644 src/test/java/org/moddingx/libx/test/util/Mappings.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7b715e81..84c92b47 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -15,9 +15,9 @@ body: validations: required: true - type: input - id: forge-version + id: neoforge-version attributes: - label: Forge version + label: Neoforge version validations: required: true - type: input diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 54ce36dc..e04648bc 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -2,7 +2,7 @@ name: 'Deploy Javadoc 📖' on: push: branches: - - '1.20' + - '1.21' jobs: deploy: @@ -13,18 +13,16 @@ jobs: uses: 'actions/checkout@v3' with: persist-credentials: false - - name: 'Install Java 🍵' - uses: 'actions/setup-java@v3' + uses: 'actions/setup-java@v4' with: distribution: 'temurin' - java-version: '17' - + java-version: '21' - name: 'Install and Build 🔧' run: './gradlew javadoc' - name: 'Deploy 🚀' - uses: 'JamesIves/github-pages-deploy-action@v4.4.1' + uses: 'JamesIves/github-pages-deploy-action@15de0f09300eea763baee31dff6c6184995c5f6a' with: branch: gh-pages folder: 'build/docs/javadoc' diff --git a/.github/workflows/test-prs.yml b/.github/workflows/test-prs.yml index df6f67c9..17bafcc0 100644 --- a/.github/workflows/test-prs.yml +++ b/.github/workflows/test-prs.yml @@ -2,7 +2,7 @@ name: 'Test pull request 📋' on: pull_request: branches: - - '1.20' + - '1.21' jobs: test: @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout 🛎️' - uses: 'actions/checkout@v3' + uses: 'actions/checkout@v4' with: persist-credentials: false - name: 'Install Java 🍵' - uses: 'actions/setup-java@v3' + uses: 'actions/setup-java@v4' with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: 'Run tests 📋' run: './gradlew test' diff --git a/build.gradle b/build.gradle index 7c3a561b..4d270869 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,8 @@ -buildscript { - apply from: 'https://moddingx.github.io/ModUtils/v5/buildscript.gradle', to: buildscript +plugins { + id 'org.moddingx.modgradle.meta' version '5.0.0' + id 'org.moddingx.modgradle.javadoc' version '5.0.0' } -apply from: 'https://moddingx.github.io/ModUtils/v5/mod.gradle' - -apply plugin: 'org.moddingx.modgradle.javadoc' -apply plugin: 'org.moddingx.modgradle.coremods' - configurations { apCompileOnly apCompileOnlyResolvable.extendsFrom apCompileOnly @@ -17,39 +13,72 @@ dependencies { } sourceSets { - ap { - compileClasspath = configurations.apCompileOnlyResolvable + ap { compileClasspath = configurations.apCompileOnlyResolvable } + sourcegen { compileClasspath = configurations.compileClasspath } + main { java.srcDirs += [ file('./src/generated/java') ] } +} + +mod.configure { + modid 'libx' + group 'org.moddingx' + versioning { + base '6.0' + maven 'https://maven.moddingx.org/release' } - sourcegen { - compileClasspath = configurations.compileClasspath + + neoforge '21.1.97' + extraModSource sourceSets.ap + + license 'The Apache License, Version 2.0' + github 'ModdingX/LibX' + + runs { + data { + modSource sourceSets.sourcegen + } + } + + artifacts { + sources { + publishToRepositories() + uploadToModHostingSites() + } + javadoc {} + } + + publishing { + maven { + name 'moddingx' + url 'https://maven.moddingx.org/release' + credentials(PasswordCredentials) + } } - main { - java.srcDirs += [ file('./src/generated/java') ] + + upload { + curseforge { + projectId 412525 + } + modrinth { + projectId 'qEH6GYul' + } } } -mod.run.sourceSet(sourceSets.ap) - dependencies { annotationProcessor sourceSets.ap.output implementation sourceSets.ap.output - coremods 'org.moddingx:CoreModTypes:5.0.2-2' - - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' - testImplementation 'net.minecraftforge:srgutils:0.4.13' - testImplementation 'com.moandjiezana.toml:toml4j:0.7.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.2' } compileJava.options.compilerArgs += [ '-Amod.properties.strict_onlyin=true', '-Amod.properties.strict_super=true', - '-Amod.properties.force_findbugs=true' + '-Amod.properties.javax_nullity=true' ] test { - dependsOn createSrgToMcp // Needed, so the tests can load mappings useJUnitPlatform() } @@ -57,12 +86,7 @@ jar { from sourceSets.ap.output } -sourceJarConfigure { - sourceSets.ap.java.srcDirs.forEach { additionalSourceDir it } -} - javadocConfigure { - from sourceSets.ap.java.sourceDirectories exclude '**.impl.*?' exclude '**.annotation.processor.*?' } @@ -70,9 +94,9 @@ javadocConfigure { javadoc { options.addStringOption('Xdoclint:none', '-quiet') options.destinationDirectory(file("build/docs/javadoc")) - title("LibX ${mod.base_version} JavaDoc") - options.windowTitle("LibX ${mod.base_version} JavaDoc") - options.header('

Wiki' \ + title("LibX ${mod.setup.minecraft} JavaDoc") + options.windowTitle("LibX ${mod.setup.minecraft} JavaDoc") + options.header('

Wiki' \ + '      ' \ + 'GitHub

') options.memberLevel = JavadocMemberLevel.PROTECTED @@ -81,21 +105,10 @@ javadoc { // Performs checks for releases task release { finalizedBy compileJava - + doFirst { compileJava.options.compilerArgs += [ '-Amod.properties.release=true' ] } } - -minecraft { - runs { data { - mods { - "${mod.modid}_sourcegen" { - source sourceSets.sourcegen - } - } - args '--flat', '--mod', "${mod.modid}_sourcegen" - }} -} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6985c875..c619e22e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip diff --git a/mod.properties b/mod.properties index a9dd296f..b0523582 100644 --- a/mod.properties +++ b/mod.properties @@ -1,18 +1,18 @@ -modid=libx -group=org.moddingx -base_version=5.0 +#modid=libx +#group=org.moddingx +#base_version=5.0 # Do not change forge version (keep NeoForge compatibility on this version of minecraft) -forge_version=1.20.1-47.1.3 -mappings=sugarcane_2023.07.09-1.20.1 +#forge_version=1.20.1-47.1.3 +#mappings=sugarcane_2023.07.09-1.20.1 -sources=true +#sources=true -local_maven=/var/www/moddingx/maven -changelog_repository=https://github.com/ModdingX/LibX/commit/%H +#local_maven=/var/www/moddingx/maven +#changelog_repository=https://github.com/ModdingX/LibX/commit/%H -license=The Apache License, Version 2.0 -license_url=https://www.apache.org/licenses/LICENSE-2.0.txt +#license=The Apache License, Version 2.0 +#license_url=https://www.apache.org/licenses/LICENSE-2.0.txt -curse_project=412525 -modrinth_project=qEH6GYul -upload_versions=1.20.1 +#curse_project=412525 +#modrinth_project=qEH6GYul +#upload_versions=1.20.1 diff --git a/settings.gradle b/settings.gradle index 0b222c38..2dec6741 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url = 'https://maven.neoforged.net/releases' } + maven { url = 'https://maven.moddingx.org/release' } + } +} + rootProject.name= 'LibX' diff --git a/src/ap/java/org/moddingx/libx/annotation/processor/Classes.java b/src/ap/java/org/moddingx/libx/annotation/processor/Classes.java index 56608528..2afe67aa 100644 --- a/src/ap/java/org/moddingx/libx/annotation/processor/Classes.java +++ b/src/ap/java/org/moddingx/libx/annotation/processor/Classes.java @@ -4,12 +4,11 @@ public class Classes { public static final String MODX = "org.moddingx.libx.mod.ModX"; public static final String MODX_REGISTRATION = "org.moddingx.libx.mod.ModXRegistration"; - public static final String MOD = "net.minecraftforge.fml.common.Mod"; + public static final String MOD = "net.neoforged.fml.common.Mod"; public static final String FOR_MOD = "org.moddingx.libx.annotation.ForMod"; - public static final String DIST = "net.minecraftforge.api.distmarker.Dist"; - public static final String ONLY_IN = "net.minecraftforge.api.distmarker.OnlyIn"; - public static final String ONLY_INS = "net.minecraftforge.api.distmarker.OnlyIns"; - public static final String DIST_EXECUTOR = "net.minecraftforge.fml.DistExecutor"; + public static final String DIST = "net.neoforged.api.distmarker.Dist"; + public static final String ONLY_IN = "net.neoforged.api.distmarker.OnlyIn"; + public static final String ONLY_INS = "net.neoforged.api.distmarker.OnlyIns"; public static final String PROCESSOR_INTERFACE = "org.moddingx.libx.annotation.impl.ProcessorInterface"; public static final String LAZY_MAP_BUILDER = "org.moddingx.libx.annotation.impl.LazyMapBuilder"; @@ -24,11 +23,11 @@ public class Classes { public static final String REGISTRY = "net.minecraft.core.Registry"; public static final String REGISTRIES = "net.minecraft.core.registries.Registries"; public static final String RESOURCE_KEY = "net.minecraft.resources.ResourceKey"; - public static final String FORGE_KEYS = "net.minecraftforge.registries.ForgeRegistries$Keys"; + public static final String NEOFORGE_KEYS = "net.neoforged.neoforge.registries.NeoForgeRegistries$Keys"; public static final String BAKED_MODEL = "net.minecraft.client.resources.model.BakedModel"; - public static final String MODEL_REGISTRY_EVENT = "net.minecraftforge.client.event.ModelEvent$RegisterAdditional"; - public static final String MODEL_BAKE_EVENT = "net.minecraftforge.client.event.ModelEvent$BakingCompleted"; + public static final String MODEL_REGISTRY_EVENT = "net.neoforged.neoforge.client.event.ModelEvent$RegisterAdditional"; + public static final String MODEL_BAKE_EVENT = "net.neoforged.neoforge.client.event.ModelEvent$BakingCompleted"; public static final String CODEC = "com.mojang.serialization.Codec"; public static final String MAP_CODEC = "com.mojang.serialization.MapCodec"; public static final String RECORD_CODEC_BUILDER = "com.mojang.serialization.codecs.RecordCodecBuilder"; diff --git a/src/ap/java/org/moddingx/libx/annotation/processor/ProcessorEnv.java b/src/ap/java/org/moddingx/libx/annotation/processor/ProcessorEnv.java index 6477871c..77cbda6e 100644 --- a/src/ap/java/org/moddingx/libx/annotation/processor/ProcessorEnv.java +++ b/src/ap/java/org/moddingx/libx/annotation/processor/ProcessorEnv.java @@ -19,7 +19,7 @@ public interface ProcessorEnv { - SourceVersion TARGET = SourceVersion.RELEASE_17; + SourceVersion TARGET = SourceVersion.RELEASE_21; Types types(); Elements elements(); diff --git a/src/ap/java/org/moddingx/libx/annotation/processor/misc/FindBugsProcessor.java b/src/ap/java/org/moddingx/libx/annotation/processor/misc/NullityProcessor.java similarity index 85% rename from src/ap/java/org/moddingx/libx/annotation/processor/misc/FindBugsProcessor.java rename to src/ap/java/org/moddingx/libx/annotation/processor/misc/NullityProcessor.java index 5c1cdcd9..b01a289d 100644 --- a/src/ap/java/org/moddingx/libx/annotation/processor/misc/FindBugsProcessor.java +++ b/src/ap/java/org/moddingx/libx/annotation/processor/misc/NullityProcessor.java @@ -10,7 +10,7 @@ import java.util.HashSet; import java.util.Set; -public class FindBugsProcessor extends Processor { +public class NullityProcessor extends Processor { @Override public Class[] getTypes() { @@ -28,13 +28,13 @@ public Set getSupportedAnnotationTypes() { @Override public Set getSupportedOptions() { Set set = new HashSet<>(super.getSupportedAnnotationTypes()); - set.add("mod.properties.force_findbugs"); + set.add("mod.properties.javax_nullity"); return set; } @Override public void run(Set annotations, RoundEnvironment roundEnv) { - if (!this.options().containsKey("mod.properties.force_findbugs") || !Boolean.parseBoolean(this.options().get("mod.properties.force_findbugs"))) return; + if (!this.options().containsKey("mod.properties.javax_nullity") || !Boolean.parseBoolean(this.options().get("mod.properties.javax_nullity"))) return; for (Element element : roundEnv.getElementsAnnotatedWith(this.typeElement(Classes.JETBRAINS_NOTNULL))) { this.messager().printMessage(Diagnostic.Kind.ERROR, "This should use javax.annotation.Nonnull.", element); } diff --git a/src/ap/java/org/moddingx/libx/annotation/processor/modinit/ModInit.java b/src/ap/java/org/moddingx/libx/annotation/processor/modinit/ModInit.java index 2751e09a..6a706c72 100644 --- a/src/ap/java/org/moddingx/libx/annotation/processor/modinit/ModInit.java +++ b/src/ap/java/org/moddingx/libx/annotation/processor/modinit/ModInit.java @@ -141,28 +141,32 @@ public void write(Filer filer, Messager messager) { writer.write("((" + Classes.sourceName(Classes.MODX_REGISTRATION) + ")mod).addRegistrationHandler(" + this.modClass.getSimpleName() + "$::register);"); } if (!this.models.isEmpty()) { - writer.write(Classes.sourceName(Classes.DIST_EXECUTOR) + ".unsafeRunWhenOn(" + Classes.sourceName(Classes.DIST) + ".CLIENT,()->()->{"); - writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".addModListener(" + Classes.sourceName(Classes.MODEL_REGISTRY_EVENT) + ".class," + this.modClass.getSimpleName() + "$::registerModels);"); - writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".addLowModListener(" + Classes.sourceName(Classes.MODEL_BAKE_EVENT) + ".class," + this.modClass.getSimpleName() + "$::bakeModels);"); - writer.write("});"); + writer.write("if(" + Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".isDistClient()){registerClientOnlyEventListeners();}"); } writer.write("}"); if (!allReg.isEmpty()) { writer.write("private static void register(){"); writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".runUnchecked(()->{"); for (RegistrationEntry entry : allReg) { - writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".register(mod," + (entry.registryFqn() == null ? "null" : entry.registryFqn()) + "," + quote(entry.name()) + "," + entry.fieldClassFqn() + "." + entry.fieldName() + ",()->{return " + entry.fieldClassFqn() + ".class.getDeclaredField(" + quote(entry.fieldName()) + ");});"); + writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".register(mod," + (entry.registryFqn() == null ? "null" : entry.registryFqn()) + "," + quote(entry.name()) + "," + entry.fieldClassFqn() + "." + entry.fieldName() + ");"); } writer.write("});"); writer.write("}"); } if (!this.models.isEmpty()) { + // Not OnlyIn + writer.write("private static void registerClientOnlyEventListeners(){"); + writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".addModListener(mod," + Classes.sourceName(Classes.MODEL_REGISTRY_EVENT) + ".class," + this.modClass.getSimpleName() + "$::registerModels);"); + writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".addLowModListener(mod," + Classes.sourceName(Classes.MODEL_BAKE_EVENT) + ".class," + this.modClass.getSimpleName() + "$::bakeModels);"); + writer.write("}"); + writer.write("@" + Classes.sourceName(Classes.ONLY_IN) + "(" + Classes.sourceName(Classes.DIST) + ".CLIENT)"); writer.write("private static void registerModels(" + Classes.sourceName(Classes.MODEL_REGISTRY_EVENT) + " event){"); for (LoadableModel model : this.models) { writer.write(Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".addSpecialModel(event," + Classes.sourceName(Classes.PROCESSOR_INTERFACE) + ".newRL(" + quote(model.modelNamespace()) + "," + quote(model.modelPath()) + "));"); } writer.write("}"); + writer.write("@" + Classes.sourceName(Classes.ONLY_IN) + "(" + Classes.sourceName(Classes.DIST) + ".CLIENT)"); writer.write("private static void bakeModels(" + Classes.sourceName(Classes.MODEL_BAKE_EVENT) + " event){"); for (LoadableModel model : this.models) { diff --git a/src/ap/java/org/moddingx/libx/annotation/processor/modinit/register/RegisterClassProcessor.java b/src/ap/java/org/moddingx/libx/annotation/processor/modinit/register/RegisterClassProcessor.java index d2aaa51a..83c86993 100644 --- a/src/ap/java/org/moddingx/libx/annotation/processor/modinit/register/RegisterClassProcessor.java +++ b/src/ap/java/org/moddingx/libx/annotation/processor/modinit/register/RegisterClassProcessor.java @@ -55,7 +55,7 @@ private static TargetRegistry resolveRegistry(Element classElem, RegisterClass c TypeMirror registryClass = env.classType(classAnnotation::registryClass); if (registryClass.getKind() == TypeKind.VOID) { classesToCheck = List.of( - env.typeElement(Classes.FORGE_KEYS), + env.typeElement(Classes.NEOFORGE_KEYS), env.typeElement(Classes.REGISTRIES) ); } else { diff --git a/src/ap/java/org/moddingx/libx/annotation/registration/RegisterClass.java b/src/ap/java/org/moddingx/libx/annotation/registration/RegisterClass.java index b70c4be8..dbd31199 100644 --- a/src/ap/java/org/moddingx/libx/annotation/registration/RegisterClass.java +++ b/src/ap/java/org/moddingx/libx/annotation/registration/RegisterClass.java @@ -8,7 +8,7 @@ * The registry is resolved by taking the value from {@link #registryClass()} and looking for a * {@code public static final} field with the name from {@link #registry()} that holds a * {@code ResourceKey>} that links to the registry to use. If {@link #registryClass()} is not given, - * {@code ForgeRegistries.Keys} and {@code Registries} are searched. + * {@code NeoForgeRegistries.Keys} and {@code Registries} are searched. * * To ignore a field add {@link Reg.Exclude @Exclude} to it. * diff --git a/src/ap/resources/META-INF/services/javax.annotation.processing.Processor b/src/ap/resources/META-INF/services/javax.annotation.processing.Processor index 55240955..71ff21cc 100644 --- a/src/ap/resources/META-INF/services/javax.annotation.processing.Processor +++ b/src/ap/resources/META-INF/services/javax.annotation.processing.Processor @@ -2,7 +2,7 @@ org.moddingx.libx.annotation.processor.meta.ExperimentalProcessor org.moddingx.libx.annotation.processor.meta.RemoveInProcessor org.moddingx.libx.annotation.processor.meta.SuperProcessor org.moddingx.libx.annotation.processor.misc.ConfigProcessor -org.moddingx.libx.annotation.processor.misc.FindBugsProcessor +org.moddingx.libx.annotation.processor.misc.NullityProcessor org.moddingx.libx.annotation.processor.modinit.ModInitProcessor org.moddingx.libx.annotation.processor.modinit.register.RegisterClassModifyProcessor org.moddingx.libx.annotation.processor.onlyin.OnlyInProcessor diff --git a/src/coremods/cache b/src/coremods/cache deleted file mode 100644 index cd888b20..00000000 --- a/src/coremods/cache +++ /dev/null @@ -1,5 +0,0 @@ -96328CF62EBA7D9C9D2727204D28CBE9B11D7D31 coremods/holder_serialize.ts -39C205256CB9F39746521AFAA45ABE1B0D6B354A coremods/interact.ts -4107C75A6D7B70470E65C17AE9ED1AAAA384FD44 coremods/level_load.ts -AC5D777B95B722DEC43D95FA91682F7C2D0C4372 coremods/registry_load.ts - diff --git a/src/coremods/coremods/holder_serialize.js b/src/coremods/coremods/holder_serialize.js deleted file mode 100644 index 5bfa2584..00000000 --- a/src/coremods/coremods/holder_serialize.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var coremods_1 = require("coremods"); -function initializeCoreMod() { - return { - 'holder_serialize': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.core.Holder$Reference', - 'methodName': 'm_203401_', - 'methodDesc': '(Lnet/minecraft/core/HolderOwner;)Z' - }, - 'transformer': function (method) { - var label = new coremods_1.LabelNode(); - var target = new coremods_1.InsnList(); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 0)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 1)); - target.add(coremods_1.ASMAPI.buildMethodCall('org/moddingx/libx/impl/libxcore/CoreHolderSerialize', 'forceSerializeIn', '(Lnet/minecraft/core/Holder$Reference;Lnet/minecraft/core/HolderOwner;)Z', coremods_1.ASMAPI.MethodType.STATIC)); - target.add(new coremods_1.JumpInsnNode(coremods_1.Opcodes.IFEQ, label)); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.ICONST_1)); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.IRETURN)); - target.add(label); - method.instructions.insert(target); - return method; - } - } - }; -} diff --git a/src/coremods/coremods/holder_serialize.ts b/src/coremods/coremods/holder_serialize.ts deleted file mode 100644 index 37fe607b..00000000 --- a/src/coremods/coremods/holder_serialize.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - ASMAPI, - CoreMods, - InsnList, - InsnNode, - JumpInsnNode, - LabelNode, - MethodNode, - Opcodes, - VarInsnNode -} from "coremods"; - -function initializeCoreMod(): CoreMods { - return { - 'holder_serialize': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.core.Holder$Reference', - 'methodName': 'm_203401_', - 'methodDesc': '(Lnet/minecraft/core/HolderOwner;)Z' - }, - 'transformer': (method: MethodNode) => { - const label = new LabelNode(); - const target = new InsnList(); - target.add(new VarInsnNode(Opcodes.ALOAD, 0)); - target.add(new VarInsnNode(Opcodes.ALOAD, 1)); - target.add(ASMAPI.buildMethodCall( - 'org/moddingx/libx/impl/libxcore/CoreHolderSerialize', - 'forceSerializeIn', '(Lnet/minecraft/core/Holder$Reference;Lnet/minecraft/core/HolderOwner;)Z', - ASMAPI.MethodType.STATIC - )); - target.add(new JumpInsnNode(Opcodes.IFEQ, label)); - target.add(new InsnNode(Opcodes.ICONST_1)) - target.add(new InsnNode(Opcodes.IRETURN)); - target.add(label); - - method.instructions.insert(target); - return method; - } - } - } -} diff --git a/src/coremods/coremods/interact.js b/src/coremods/coremods/interact.js deleted file mode 100644 index 6005d186..00000000 --- a/src/coremods/coremods/interact.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var coremods_1 = require("coremods"); -function initializeCoreMod() { - return { - 'interact': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.server.level.ServerPlayerGameMode', - 'methodName': 'm_7179_', - 'methodDesc': '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;' - }, - 'transformer': function (method) { - var label = new coremods_1.LabelNode(); - var target = new coremods_1.InsnList(); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 1)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 2)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 3)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 4)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 5)); - target.add(coremods_1.ASMAPI.buildMethodCall('org/moddingx/libx/impl/libxcore/CoreInteract', 'useItemOn', '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;', coremods_1.ASMAPI.MethodType.STATIC)); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.DUP)); - target.add(new coremods_1.JumpInsnNode(coremods_1.Opcodes.IFNULL, label)); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.ARETURN)); - target.add(label); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.POP)); - for (var i = method.instructions.size() - 1; i >= 0; i--) { - var inst = method.instructions.get(i); - if (inst != null && inst.getOpcode() == coremods_1.Opcodes.ARETURN) { - method.instructions.insertBefore(inst, target); - return method; - } - } - throw new Error("Failed to patch ServerPlayerGameMode.class"); - } - } - }; -} diff --git a/src/coremods/coremods/interact.ts b/src/coremods/coremods/interact.ts deleted file mode 100644 index ed7774a3..00000000 --- a/src/coremods/coremods/interact.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - ASMAPI, - CoreMods, - InsnList, - InsnNode, - JumpInsnNode, - LabelNode, - MethodNode, - Opcodes, - VarInsnNode -} from "coremods"; - -function initializeCoreMod(): CoreMods { - return { - 'interact': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.server.level.ServerPlayerGameMode', - 'methodName': 'm_7179_', - 'methodDesc': '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;' - }, - 'transformer': (method: MethodNode) => { - const label = new LabelNode(); - const target = new InsnList(); - target.add(new VarInsnNode(Opcodes.ALOAD, 1)); - target.add(new VarInsnNode(Opcodes.ALOAD, 2)); - target.add(new VarInsnNode(Opcodes.ALOAD, 3)); - target.add(new VarInsnNode(Opcodes.ALOAD, 4)); - target.add(new VarInsnNode(Opcodes.ALOAD, 5)); - target.add(ASMAPI.buildMethodCall( - 'org/moddingx/libx/impl/libxcore/CoreInteract', - 'useItemOn', '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;', - ASMAPI.MethodType.STATIC - )); - target.add(new InsnNode(Opcodes.DUP)); - target.add(new JumpInsnNode(Opcodes.IFNULL, label)); - target.add(new InsnNode(Opcodes.ARETURN)); - target.add(label); - target.add(new InsnNode(Opcodes.POP)); - - for (let i = method.instructions.size() - 1; i >= 0; i--) { - const inst = method.instructions.get(i); - if (inst != null && inst.getOpcode() == Opcodes.ARETURN) { - method.instructions.insertBefore(inst, target) - return method; - } - } - throw new Error("Failed to patch ServerPlayerGameMode.class"); - } - } - } -} diff --git a/src/coremods/coremods/level_load.ts b/src/coremods/coremods/level_load.ts deleted file mode 100644 index 2f7f5c61..00000000 --- a/src/coremods/coremods/level_load.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AbstractInsnNode, ASMAPI, CoreMods, InsnList, InsnNode, MethodInsnNode, MethodNode, Opcodes, VarInsnNode } from "coremods"; - -function initializeCoreMod(): CoreMods { - return { - 'level_load': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.server.level.ServerLevel', - 'methodName': '', - 'methodDesc': '(Lnet/minecraft/server/MinecraftServer;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lnet/minecraft/world/level/storage/ServerLevelData;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/level/dimension/LevelStem;Lnet/minecraft/server/level/progress/ChunkProgressListener;ZJLjava/util/List;ZLnet/minecraft/world/RandomSequences;)V' - }, - 'transformer': (method: MethodNode) => { - const target = new InsnList(); - target.add(new InsnNode(Opcodes.DUP)) - target.add(new VarInsnNode(Opcodes.ALOAD, 1)) - target.add(new MethodInsnNode(Opcodes.INVOKESTATIC, - 'org/moddingx/libx/impl/libxcore/CoreLevelLoad', - 'startLevelLoad', '(Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/MinecraftServer;)V' - )) - - for (let i = 0; i < method.instructions.size(); i++) { - const node = method.instructions.get(i) as AbstractInsnNode; - if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) { - const methodNode = node as MethodInsnNode; - if (methodNode.owner == 'net/minecraft/world/level/dimension/LevelStem' && methodNode.name == ASMAPI.mapField('f_63976_') /* record method */ && methodNode.desc == '()Lnet/minecraft/world/level/chunk/ChunkGenerator;') { - method.instructions.insert(node, target); - return method; - } - } - } - - throw new Error('Failed to patch ServerLevel.class'); - } - } - } -} diff --git a/src/coremods/coremods/registry_load.ts b/src/coremods/coremods/registry_load.ts deleted file mode 100644 index 4ad62b69..00000000 --- a/src/coremods/coremods/registry_load.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { AbstractInsnNode, ASMAPI, CoreMods, FieldInsnNode, InsnList, InsnNode, MethodInsnNode, MethodNode, Opcodes } from "coremods"; - -function initializeCoreMod(): CoreMods { - return { - 'registry_load': { - 'target': { - 'type': 'METHOD', - 'class': 'net.minecraft.server.WorldLoader', - 'methodName': 'm_214362_', - 'methodDesc': '(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;' - }, - 'transformer': (method: MethodNode) => { - const target = new InsnList(); - target.add(new InsnNode(Opcodes.DUP)) - target.add(new MethodInsnNode(Opcodes.INVOKESTATIC, - 'org/moddingx/libx/impl/libxcore/CoreRegistryLoad', - 'afterWorldGenLayerLoad', '(Lnet/minecraft/core/LayeredRegistryAccess;)V' - )) - - let foundWorldGenField = false - for (let i = 0; i < method.instructions.size(); i++) { - const node = method.instructions.get(i) as AbstractInsnNode; - if (node.getOpcode() == Opcodes.GETSTATIC && !foundWorldGenField) { - const fieldNode = node as FieldInsnNode - if (fieldNode.owner == 'net/minecraft/server/RegistryLayer' && fieldNode.name == 'WORLDGEN') { - foundWorldGenField = true - } - } else if (node.getOpcode() == Opcodes.INVOKESTATIC && foundWorldGenField) { - const methodNode = node as MethodInsnNode; - if (methodNode.owner == 'net/minecraft/server/WorldLoader' && methodNode.name == ASMAPI.mapMethod('m_245736_') && methodNode.desc == '(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/LayeredRegistryAccess;Lnet/minecraft/server/RegistryLayer;Ljava/util/List;)Lnet/minecraft/core/LayeredRegistryAccess;') { - method.instructions.insert(node, target); - return method; - } - } - } - - throw new Error('Failed to patch WorldLoader.class'); - } - } - } -} diff --git a/src/generated/java/org/moddingx/libx/vanilla/TemplatePools.java b/src/generated/java/org/moddingx/libx/vanilla/TemplatePools.java index ca896e73..3ca07fea 100644 --- a/src/generated/java/org/moddingx/libx/vanilla/TemplatePools.java +++ b/src/generated/java/org/moddingx/libx/vanilla/TemplatePools.java @@ -9,147 +9,192 @@ public class TemplatePools { private TemplatePools() {} - private static final ResourceKey> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation("minecraft","worldgen/template_pool")); + private static final ResourceKey> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath("minecraft","worldgen/template_pool")); - public static final ResourceKey ANCIENT_CITY_CITY_ENTRANCE = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/city/entrance")); - public static final ResourceKey ANCIENT_CITY_CITY_CENTER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/city_center")); - public static final ResourceKey ANCIENT_CITY_CITY_CENTER_WALLS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/city_center/walls")); - public static final ResourceKey ANCIENT_CITY_SCULK = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/sculk")); - public static final ResourceKey ANCIENT_CITY_STRUCTURES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/structures")); - public static final ResourceKey ANCIENT_CITY_WALLS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/walls")); - public static final ResourceKey ANCIENT_CITY_WALLS_NO_CORNERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","ancient_city/walls/no_corners")); - public static final ResourceKey BASTION_BLOCKS_GOLD = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/blocks/gold")); - public static final ResourceKey BASTION_BRIDGE_BRIDGE_PIECES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/bridge_pieces")); - public static final ResourceKey BASTION_BRIDGE_CONNECTORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/connectors")); - public static final ResourceKey BASTION_BRIDGE_LEGS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/legs")); - public static final ResourceKey BASTION_BRIDGE_RAMPART_PLATES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/rampart_plates")); - public static final ResourceKey BASTION_BRIDGE_RAMPARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/ramparts")); - public static final ResourceKey BASTION_BRIDGE_STARTING_PIECES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/starting_pieces")); - public static final ResourceKey BASTION_BRIDGE_WALLS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/bridge/walls")); - public static final ResourceKey BASTION_HOGLIN_STABLE_CONNECTORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/connectors")); - public static final ResourceKey BASTION_HOGLIN_STABLE_LARGE_STABLES_INNER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/large_stables/inner")); - public static final ResourceKey BASTION_HOGLIN_STABLE_LARGE_STABLES_OUTER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/large_stables/outer")); - public static final ResourceKey BASTION_HOGLIN_STABLE_MIRRORED_STARTING_PIECES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/mirrored_starting_pieces")); - public static final ResourceKey BASTION_HOGLIN_STABLE_POSTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/posts")); - public static final ResourceKey BASTION_HOGLIN_STABLE_RAMPART_PLATES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/rampart_plates")); - public static final ResourceKey BASTION_HOGLIN_STABLE_RAMPARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/ramparts")); - public static final ResourceKey BASTION_HOGLIN_STABLE_SMALL_STABLES_INNER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/small_stables/inner")); - public static final ResourceKey BASTION_HOGLIN_STABLE_SMALL_STABLES_OUTER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/small_stables/outer")); - public static final ResourceKey BASTION_HOGLIN_STABLE_STAIRS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/stairs")); - public static final ResourceKey BASTION_HOGLIN_STABLE_STARTING_PIECES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/starting_pieces")); - public static final ResourceKey BASTION_HOGLIN_STABLE_WALL_BASES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/wall_bases")); - public static final ResourceKey BASTION_HOGLIN_STABLE_WALLS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/hoglin_stable/walls")); - public static final ResourceKey BASTION_MOBS_HOGLIN = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/mobs/hoglin")); - public static final ResourceKey BASTION_MOBS_PIGLIN = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/mobs/piglin")); - public static final ResourceKey BASTION_MOBS_PIGLIN_MELEE = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/mobs/piglin_melee")); - public static final ResourceKey BASTION_STARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/starts")); - public static final ResourceKey BASTION_TREASURE_BASES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/bases")); - public static final ResourceKey BASTION_TREASURE_BASES_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/bases/centers")); - public static final ResourceKey BASTION_TREASURE_BRAINS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/brains")); - public static final ResourceKey BASTION_TREASURE_CONNECTORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/connectors")); - public static final ResourceKey BASTION_TREASURE_CORNERS_BOTTOM = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/corners/bottom")); - public static final ResourceKey BASTION_TREASURE_CORNERS_EDGES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/corners/edges")); - public static final ResourceKey BASTION_TREASURE_CORNERS_MIDDLE = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/corners/middle")); - public static final ResourceKey BASTION_TREASURE_CORNERS_TOP = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/corners/top")); - public static final ResourceKey BASTION_TREASURE_ENTRANCES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/entrances")); - public static final ResourceKey BASTION_TREASURE_EXTENSIONS_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/extensions/houses")); - public static final ResourceKey BASTION_TREASURE_EXTENSIONS_LARGE_POOL = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/extensions/large_pool")); - public static final ResourceKey BASTION_TREASURE_EXTENSIONS_SMALL_POOL = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/extensions/small_pool")); - public static final ResourceKey BASTION_TREASURE_RAMPARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/ramparts")); - public static final ResourceKey BASTION_TREASURE_ROOFS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/roofs")); - public static final ResourceKey BASTION_TREASURE_STAIRS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/stairs")); - public static final ResourceKey BASTION_TREASURE_WALLS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/walls")); - public static final ResourceKey BASTION_TREASURE_WALLS_BOTTOM = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/walls/bottom")); - public static final ResourceKey BASTION_TREASURE_WALLS_MID = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/walls/mid")); - public static final ResourceKey BASTION_TREASURE_WALLS_OUTER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/walls/outer")); - public static final ResourceKey BASTION_TREASURE_WALLS_TOP = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/treasure/walls/top")); - public static final ResourceKey BASTION_UNITS_CENTER_PIECES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/center_pieces")); - public static final ResourceKey BASTION_UNITS_EDGE_WALL_UNITS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/edge_wall_units")); - public static final ResourceKey BASTION_UNITS_EDGES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/edges")); - public static final ResourceKey BASTION_UNITS_FILLERS_STAGE_0 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/fillers/stage_0")); - public static final ResourceKey BASTION_UNITS_LARGE_RAMPARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/large_ramparts")); - public static final ResourceKey BASTION_UNITS_PATHWAYS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/pathways")); - public static final ResourceKey BASTION_UNITS_RAMPART_PLATES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/rampart_plates")); - public static final ResourceKey BASTION_UNITS_RAMPARTS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/ramparts")); - public static final ResourceKey BASTION_UNITS_STAGES_ROT_STAGE_1 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/stages/rot/stage_1")); - public static final ResourceKey BASTION_UNITS_STAGES_STAGE_0 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/stages/stage_0")); - public static final ResourceKey BASTION_UNITS_STAGES_STAGE_1 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/stages/stage_1")); - public static final ResourceKey BASTION_UNITS_STAGES_STAGE_2 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/stages/stage_2")); - public static final ResourceKey BASTION_UNITS_STAGES_STAGE_3 = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/stages/stage_3")); - public static final ResourceKey BASTION_UNITS_WALL_UNITS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/wall_units")); - public static final ResourceKey BASTION_UNITS_WALLS_WALL_BASES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","bastion/units/walls/wall_bases")); - public static final ResourceKey EMPTY = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","empty")); - public static final ResourceKey PILLAGER_OUTPOST_BASE_PLATES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","pillager_outpost/base_plates")); - public static final ResourceKey PILLAGER_OUTPOST_FEATURE_PLATES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","pillager_outpost/feature_plates")); - public static final ResourceKey PILLAGER_OUTPOST_FEATURES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","pillager_outpost/features")); - public static final ResourceKey PILLAGER_OUTPOST_TOWERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","pillager_outpost/towers")); - public static final ResourceKey TRAIL_RUINS_BUILDINGS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/buildings")); - public static final ResourceKey TRAIL_RUINS_BUILDINGS_GROUPED = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/buildings/grouped")); - public static final ResourceKey TRAIL_RUINS_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/decor")); - public static final ResourceKey TRAIL_RUINS_ROADS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/roads")); - public static final ResourceKey TRAIL_RUINS_TOWER = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/tower")); - public static final ResourceKey TRAIL_RUINS_TOWER_ADDITIONS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/tower/additions")); - public static final ResourceKey TRAIL_RUINS_TOWER_TOWER_TOP = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","trail_ruins/tower/tower_top")); - public static final ResourceKey VILLAGE_COMMON_ANIMALS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/animals")); - public static final ResourceKey VILLAGE_COMMON_BUTCHER_ANIMALS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/butcher_animals")); - public static final ResourceKey VILLAGE_COMMON_CATS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/cats")); - public static final ResourceKey VILLAGE_COMMON_IRON_GOLEM = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/iron_golem")); - public static final ResourceKey VILLAGE_COMMON_SHEEP = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/sheep")); - public static final ResourceKey VILLAGE_COMMON_WELL_BOTTOMS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/common/well_bottoms")); - public static final ResourceKey VILLAGE_DESERT_CAMEL = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/camel")); - public static final ResourceKey VILLAGE_DESERT_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/decor")); - public static final ResourceKey VILLAGE_DESERT_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/houses")); - public static final ResourceKey VILLAGE_DESERT_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/streets")); - public static final ResourceKey VILLAGE_DESERT_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/terminators")); - public static final ResourceKey VILLAGE_DESERT_TOWN_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/town_centers")); - public static final ResourceKey VILLAGE_DESERT_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/villagers")); - public static final ResourceKey VILLAGE_DESERT_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/zombie/decor")); - public static final ResourceKey VILLAGE_DESERT_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/zombie/houses")); - public static final ResourceKey VILLAGE_DESERT_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/zombie/streets")); - public static final ResourceKey VILLAGE_DESERT_ZOMBIE_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/zombie/terminators")); - public static final ResourceKey VILLAGE_DESERT_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/desert/zombie/villagers")); - public static final ResourceKey VILLAGE_PLAINS_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/decor")); - public static final ResourceKey VILLAGE_PLAINS_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/houses")); - public static final ResourceKey VILLAGE_PLAINS_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/streets")); - public static final ResourceKey VILLAGE_PLAINS_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/terminators")); - public static final ResourceKey VILLAGE_PLAINS_TOWN_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/town_centers")); - public static final ResourceKey VILLAGE_PLAINS_TREES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/trees")); - public static final ResourceKey VILLAGE_PLAINS_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/villagers")); - public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/zombie/decor")); - public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/zombie/houses")); - public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/zombie/streets")); - public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/plains/zombie/villagers")); - public static final ResourceKey VILLAGE_SAVANNA_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/decor")); - public static final ResourceKey VILLAGE_SAVANNA_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/houses")); - public static final ResourceKey VILLAGE_SAVANNA_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/streets")); - public static final ResourceKey VILLAGE_SAVANNA_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/terminators")); - public static final ResourceKey VILLAGE_SAVANNA_TOWN_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/town_centers")); - public static final ResourceKey VILLAGE_SAVANNA_TREES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/trees")); - public static final ResourceKey VILLAGE_SAVANNA_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/villagers")); - public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/zombie/decor")); - public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/zombie/houses")); - public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/zombie/streets")); - public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/zombie/terminators")); - public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/savanna/zombie/villagers")); - public static final ResourceKey VILLAGE_SNOWY_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/decor")); - public static final ResourceKey VILLAGE_SNOWY_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/houses")); - public static final ResourceKey VILLAGE_SNOWY_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/streets")); - public static final ResourceKey VILLAGE_SNOWY_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/terminators")); - public static final ResourceKey VILLAGE_SNOWY_TOWN_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/town_centers")); - public static final ResourceKey VILLAGE_SNOWY_TREES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/trees")); - public static final ResourceKey VILLAGE_SNOWY_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/villagers")); - public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/zombie/decor")); - public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/zombie/houses")); - public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/zombie/streets")); - public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/snowy/zombie/villagers")); - public static final ResourceKey VILLAGE_TAIGA_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/decor")); - public static final ResourceKey VILLAGE_TAIGA_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/houses")); - public static final ResourceKey VILLAGE_TAIGA_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/streets")); - public static final ResourceKey VILLAGE_TAIGA_TERMINATORS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/terminators")); - public static final ResourceKey VILLAGE_TAIGA_TOWN_CENTERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/town_centers")); - public static final ResourceKey VILLAGE_TAIGA_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/villagers")); - public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/zombie/decor")); - public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/zombie/houses")); - public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/zombie/streets")); - public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, new ResourceLocation("minecraft","village/taiga/zombie/villagers")); + public static final ResourceKey ANCIENT_CITY_CITY_ENTRANCE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/city/entrance")); + public static final ResourceKey ANCIENT_CITY_CITY_CENTER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/city_center")); + public static final ResourceKey ANCIENT_CITY_CITY_CENTER_WALLS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/city_center/walls")); + public static final ResourceKey ANCIENT_CITY_SCULK = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/sculk")); + public static final ResourceKey ANCIENT_CITY_STRUCTURES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/structures")); + public static final ResourceKey ANCIENT_CITY_WALLS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/walls")); + public static final ResourceKey ANCIENT_CITY_WALLS_NO_CORNERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","ancient_city/walls/no_corners")); + public static final ResourceKey BASTION_BLOCKS_GOLD = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/blocks/gold")); + public static final ResourceKey BASTION_BRIDGE_BRIDGE_PIECES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/bridge_pieces")); + public static final ResourceKey BASTION_BRIDGE_CONNECTORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/connectors")); + public static final ResourceKey BASTION_BRIDGE_LEGS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/legs")); + public static final ResourceKey BASTION_BRIDGE_RAMPART_PLATES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/rampart_plates")); + public static final ResourceKey BASTION_BRIDGE_RAMPARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/ramparts")); + public static final ResourceKey BASTION_BRIDGE_STARTING_PIECES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/starting_pieces")); + public static final ResourceKey BASTION_BRIDGE_WALLS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/bridge/walls")); + public static final ResourceKey BASTION_HOGLIN_STABLE_CONNECTORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/connectors")); + public static final ResourceKey BASTION_HOGLIN_STABLE_LARGE_STABLES_INNER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/large_stables/inner")); + public static final ResourceKey BASTION_HOGLIN_STABLE_LARGE_STABLES_OUTER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/large_stables/outer")); + public static final ResourceKey BASTION_HOGLIN_STABLE_MIRRORED_STARTING_PIECES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/mirrored_starting_pieces")); + public static final ResourceKey BASTION_HOGLIN_STABLE_POSTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/posts")); + public static final ResourceKey BASTION_HOGLIN_STABLE_RAMPART_PLATES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/rampart_plates")); + public static final ResourceKey BASTION_HOGLIN_STABLE_RAMPARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/ramparts")); + public static final ResourceKey BASTION_HOGLIN_STABLE_SMALL_STABLES_INNER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/small_stables/inner")); + public static final ResourceKey BASTION_HOGLIN_STABLE_SMALL_STABLES_OUTER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/small_stables/outer")); + public static final ResourceKey BASTION_HOGLIN_STABLE_STAIRS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/stairs")); + public static final ResourceKey BASTION_HOGLIN_STABLE_STARTING_PIECES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/starting_pieces")); + public static final ResourceKey BASTION_HOGLIN_STABLE_WALL_BASES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/wall_bases")); + public static final ResourceKey BASTION_HOGLIN_STABLE_WALLS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/hoglin_stable/walls")); + public static final ResourceKey BASTION_MOBS_HOGLIN = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/mobs/hoglin")); + public static final ResourceKey BASTION_MOBS_PIGLIN = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/mobs/piglin")); + public static final ResourceKey BASTION_MOBS_PIGLIN_MELEE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/mobs/piglin_melee")); + public static final ResourceKey BASTION_STARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/starts")); + public static final ResourceKey BASTION_TREASURE_BASES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/bases")); + public static final ResourceKey BASTION_TREASURE_BASES_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/bases/centers")); + public static final ResourceKey BASTION_TREASURE_BRAINS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/brains")); + public static final ResourceKey BASTION_TREASURE_CONNECTORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/connectors")); + public static final ResourceKey BASTION_TREASURE_CORNERS_BOTTOM = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/corners/bottom")); + public static final ResourceKey BASTION_TREASURE_CORNERS_EDGES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/corners/edges")); + public static final ResourceKey BASTION_TREASURE_CORNERS_MIDDLE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/corners/middle")); + public static final ResourceKey BASTION_TREASURE_CORNERS_TOP = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/corners/top")); + public static final ResourceKey BASTION_TREASURE_ENTRANCES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/entrances")); + public static final ResourceKey BASTION_TREASURE_EXTENSIONS_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/extensions/houses")); + public static final ResourceKey BASTION_TREASURE_EXTENSIONS_LARGE_POOL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/extensions/large_pool")); + public static final ResourceKey BASTION_TREASURE_EXTENSIONS_SMALL_POOL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/extensions/small_pool")); + public static final ResourceKey BASTION_TREASURE_RAMPARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/ramparts")); + public static final ResourceKey BASTION_TREASURE_ROOFS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/roofs")); + public static final ResourceKey BASTION_TREASURE_STAIRS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/stairs")); + public static final ResourceKey BASTION_TREASURE_WALLS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/walls")); + public static final ResourceKey BASTION_TREASURE_WALLS_BOTTOM = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/walls/bottom")); + public static final ResourceKey BASTION_TREASURE_WALLS_MID = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/walls/mid")); + public static final ResourceKey BASTION_TREASURE_WALLS_OUTER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/walls/outer")); + public static final ResourceKey BASTION_TREASURE_WALLS_TOP = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/treasure/walls/top")); + public static final ResourceKey BASTION_UNITS_CENTER_PIECES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/center_pieces")); + public static final ResourceKey BASTION_UNITS_EDGE_WALL_UNITS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/edge_wall_units")); + public static final ResourceKey BASTION_UNITS_EDGES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/edges")); + public static final ResourceKey BASTION_UNITS_FILLERS_STAGE_0 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/fillers/stage_0")); + public static final ResourceKey BASTION_UNITS_LARGE_RAMPARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/large_ramparts")); + public static final ResourceKey BASTION_UNITS_PATHWAYS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/pathways")); + public static final ResourceKey BASTION_UNITS_RAMPART_PLATES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/rampart_plates")); + public static final ResourceKey BASTION_UNITS_RAMPARTS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/ramparts")); + public static final ResourceKey BASTION_UNITS_STAGES_ROT_STAGE_1 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/stages/rot/stage_1")); + public static final ResourceKey BASTION_UNITS_STAGES_STAGE_0 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/stages/stage_0")); + public static final ResourceKey BASTION_UNITS_STAGES_STAGE_1 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/stages/stage_1")); + public static final ResourceKey BASTION_UNITS_STAGES_STAGE_2 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/stages/stage_2")); + public static final ResourceKey BASTION_UNITS_STAGES_STAGE_3 = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/stages/stage_3")); + public static final ResourceKey BASTION_UNITS_WALL_UNITS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/wall_units")); + public static final ResourceKey BASTION_UNITS_WALLS_WALL_BASES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","bastion/units/walls/wall_bases")); + public static final ResourceKey EMPTY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","empty")); + public static final ResourceKey PILLAGER_OUTPOST_BASE_PLATES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","pillager_outpost/base_plates")); + public static final ResourceKey PILLAGER_OUTPOST_FEATURE_PLATES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","pillager_outpost/feature_plates")); + public static final ResourceKey PILLAGER_OUTPOST_FEATURES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","pillager_outpost/features")); + public static final ResourceKey PILLAGER_OUTPOST_TOWERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","pillager_outpost/towers")); + public static final ResourceKey TRAIL_RUINS_BUILDINGS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/buildings")); + public static final ResourceKey TRAIL_RUINS_BUILDINGS_GROUPED = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/buildings/grouped")); + public static final ResourceKey TRAIL_RUINS_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/decor")); + public static final ResourceKey TRAIL_RUINS_ROADS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/roads")); + public static final ResourceKey TRAIL_RUINS_TOWER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/tower")); + public static final ResourceKey TRAIL_RUINS_TOWER_ADDITIONS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/tower/additions")); + public static final ResourceKey TRAIL_RUINS_TOWER_TOWER_TOP = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trail_ruins/tower/tower_top")); + public static final ResourceKey TRIAL_CHAMBERS_ATRIUM = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/atrium")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_ADDON = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/addon")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_ASSEMBLY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/assembly")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_END = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/end")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_ENTRANCE_CAP = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/entrance_cap")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_ERUPTION = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/eruption")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_PEDESTAL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/pedestal")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBER_SLANTED = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chamber/slanted")); + public static final ResourceKey TRIAL_CHAMBERS_CHAMBERS_END = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chambers/end")); + public static final ResourceKey TRIAL_CHAMBERS_CHESTS_CONTENTS_SUPPLY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chests/contents/supply")); + public static final ResourceKey TRIAL_CHAMBERS_CHESTS_SUPPLY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/chests/supply")); + public static final ResourceKey TRIAL_CHAMBERS_CORRIDOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/corridor")); + public static final ResourceKey TRIAL_CHAMBERS_CORRIDOR_SLICES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/corridor/slices")); + public static final ResourceKey TRIAL_CHAMBERS_CORRIDORS_ADDON_LOWER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/corridors/addon/lower")); + public static final ResourceKey TRIAL_CHAMBERS_CORRIDORS_ADDON_MIDDLE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/corridors/addon/middle")); + public static final ResourceKey TRIAL_CHAMBERS_CORRIDORS_ADDON_MIDDLE_UPPER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/corridors/addon/middle_upper")); + public static final ResourceKey TRIAL_CHAMBERS_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/decor")); + public static final ResourceKey TRIAL_CHAMBERS_DECOR_CHAMBER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/decor/chamber")); + public static final ResourceKey TRIAL_CHAMBERS_DISPENSERS_CHAMBER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/dispensers/chamber")); + public static final ResourceKey TRIAL_CHAMBERS_ENTRANCE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/entrance")); + public static final ResourceKey TRIAL_CHAMBERS_HALLWAY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/hallway")); + public static final ResourceKey TRIAL_CHAMBERS_HALLWAY_FALLBACK = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/hallway/fallback")); + public static final ResourceKey TRIAL_CHAMBERS_REWARD_ALL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/reward/all")); + public static final ResourceKey TRIAL_CHAMBERS_REWARD_CONTENTS_DEFAULT = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/reward/contents/default")); + public static final ResourceKey TRIAL_CHAMBERS_REWARD_OMINOUS_VAULT = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/reward/ominous_vault")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_ALL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/all")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_BREEZE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/breeze")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_CONTENTS_BREEZE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/contents/breeze")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_MELEE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/melee")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_MELEE_HUSK = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/melee/husk")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_MELEE_SPIDER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/melee/spider")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_MELEE_ZOMBIE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/melee/zombie")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_RANGED = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/ranged")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_RANGED_POISON_SKELETON = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/ranged/poison_skeleton")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_RANGED_SKELETON = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/ranged/skeleton")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_RANGED_STRAY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/ranged/stray")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SLOW_RANGED = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/slow_ranged")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SLOW_RANGED_POISON_SKELETON = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/slow_ranged/poison_skeleton")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SLOW_RANGED_SKELETON = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/slow_ranged/skeleton")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SLOW_RANGED_STRAY = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/slow_ranged/stray")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SMALL_MELEE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/small_melee")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SMALL_MELEE_BABY_ZOMBIE = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/small_melee/baby_zombie")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SMALL_MELEE_CAVE_SPIDER = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/small_melee/cave_spider")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SMALL_MELEE_SILVERFISH = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/small_melee/silverfish")); + public static final ResourceKey TRIAL_CHAMBERS_SPAWNER_SMALL_MELEE_SLIME = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","trial_chambers/spawner/small_melee/slime")); + public static final ResourceKey VILLAGE_COMMON_ANIMALS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/animals")); + public static final ResourceKey VILLAGE_COMMON_BUTCHER_ANIMALS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/butcher_animals")); + public static final ResourceKey VILLAGE_COMMON_CATS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/cats")); + public static final ResourceKey VILLAGE_COMMON_IRON_GOLEM = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/iron_golem")); + public static final ResourceKey VILLAGE_COMMON_SHEEP = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/sheep")); + public static final ResourceKey VILLAGE_COMMON_WELL_BOTTOMS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/common/well_bottoms")); + public static final ResourceKey VILLAGE_DESERT_CAMEL = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/camel")); + public static final ResourceKey VILLAGE_DESERT_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/decor")); + public static final ResourceKey VILLAGE_DESERT_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/houses")); + public static final ResourceKey VILLAGE_DESERT_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/streets")); + public static final ResourceKey VILLAGE_DESERT_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/terminators")); + public static final ResourceKey VILLAGE_DESERT_TOWN_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/town_centers")); + public static final ResourceKey VILLAGE_DESERT_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/villagers")); + public static final ResourceKey VILLAGE_DESERT_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/zombie/decor")); + public static final ResourceKey VILLAGE_DESERT_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/zombie/houses")); + public static final ResourceKey VILLAGE_DESERT_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/zombie/streets")); + public static final ResourceKey VILLAGE_DESERT_ZOMBIE_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/zombie/terminators")); + public static final ResourceKey VILLAGE_DESERT_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/desert/zombie/villagers")); + public static final ResourceKey VILLAGE_PLAINS_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/decor")); + public static final ResourceKey VILLAGE_PLAINS_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/houses")); + public static final ResourceKey VILLAGE_PLAINS_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/streets")); + public static final ResourceKey VILLAGE_PLAINS_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/terminators")); + public static final ResourceKey VILLAGE_PLAINS_TOWN_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/town_centers")); + public static final ResourceKey VILLAGE_PLAINS_TREES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/trees")); + public static final ResourceKey VILLAGE_PLAINS_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/villagers")); + public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/zombie/decor")); + public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/zombie/houses")); + public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/zombie/streets")); + public static final ResourceKey VILLAGE_PLAINS_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/plains/zombie/villagers")); + public static final ResourceKey VILLAGE_SAVANNA_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/decor")); + public static final ResourceKey VILLAGE_SAVANNA_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/houses")); + public static final ResourceKey VILLAGE_SAVANNA_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/streets")); + public static final ResourceKey VILLAGE_SAVANNA_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/terminators")); + public static final ResourceKey VILLAGE_SAVANNA_TOWN_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/town_centers")); + public static final ResourceKey VILLAGE_SAVANNA_TREES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/trees")); + public static final ResourceKey VILLAGE_SAVANNA_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/villagers")); + public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/zombie/decor")); + public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/zombie/houses")); + public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/zombie/streets")); + public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/zombie/terminators")); + public static final ResourceKey VILLAGE_SAVANNA_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/savanna/zombie/villagers")); + public static final ResourceKey VILLAGE_SNOWY_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/decor")); + public static final ResourceKey VILLAGE_SNOWY_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/houses")); + public static final ResourceKey VILLAGE_SNOWY_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/streets")); + public static final ResourceKey VILLAGE_SNOWY_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/terminators")); + public static final ResourceKey VILLAGE_SNOWY_TOWN_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/town_centers")); + public static final ResourceKey VILLAGE_SNOWY_TREES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/trees")); + public static final ResourceKey VILLAGE_SNOWY_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/villagers")); + public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/zombie/decor")); + public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/zombie/houses")); + public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/zombie/streets")); + public static final ResourceKey VILLAGE_SNOWY_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/snowy/zombie/villagers")); + public static final ResourceKey VILLAGE_TAIGA_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/decor")); + public static final ResourceKey VILLAGE_TAIGA_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/houses")); + public static final ResourceKey VILLAGE_TAIGA_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/streets")); + public static final ResourceKey VILLAGE_TAIGA_TERMINATORS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/terminators")); + public static final ResourceKey VILLAGE_TAIGA_TOWN_CENTERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/town_centers")); + public static final ResourceKey VILLAGE_TAIGA_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/villagers")); + public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_DECOR = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/zombie/decor")); + public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_HOUSES = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/zombie/houses")); + public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_STREETS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/zombie/streets")); + public static final ResourceKey VILLAGE_TAIGA_ZOMBIE_VILLAGERS = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath("minecraft","village/taiga/zombie/villagers")); } diff --git a/src/generated/resources/data/libx/tags/blocks/impl_all_hanging_signs.json b/src/generated/resources/data/libx/tags/block/impl_all_hanging_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_all_hanging_signs.json rename to src/generated/resources/data/libx/tags/block/impl_all_hanging_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_buttons.json b/src/generated/resources/data/libx/tags/block/impl_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_buttons.json rename to src/generated/resources/data/libx/tags/block/impl_buttons.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_ceiling_hanging_signs.json b/src/generated/resources/data/libx/tags/block/impl_ceiling_hanging_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_ceiling_hanging_signs.json rename to src/generated/resources/data/libx/tags/block/impl_ceiling_hanging_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_doors.json b/src/generated/resources/data/libx/tags/block/impl_doors.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_doors.json rename to src/generated/resources/data/libx/tags/block/impl_doors.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_fence_gates.json b/src/generated/resources/data/libx/tags/block/impl_fence_gates.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_fence_gates.json rename to src/generated/resources/data/libx/tags/block/impl_fence_gates.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_fences.json b/src/generated/resources/data/libx/tags/block/impl_fences.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_fences.json rename to src/generated/resources/data/libx/tags/block/impl_fences.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_logs.json b/src/generated/resources/data/libx/tags/block/impl_logs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_logs.json rename to src/generated/resources/data/libx/tags/block/impl_logs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_logs_that_burn.json b/src/generated/resources/data/libx/tags/block/impl_logs_that_burn.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_logs_that_burn.json rename to src/generated/resources/data/libx/tags/block/impl_logs_that_burn.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_pressure_plates.json b/src/generated/resources/data/libx/tags/block/impl_pressure_plates.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_pressure_plates.json rename to src/generated/resources/data/libx/tags/block/impl_pressure_plates.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_signs.json b/src/generated/resources/data/libx/tags/block/impl_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_signs.json rename to src/generated/resources/data/libx/tags/block/impl_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_slabs.json b/src/generated/resources/data/libx/tags/block/impl_slabs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_slabs.json rename to src/generated/resources/data/libx/tags/block/impl_slabs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_stairs.json b/src/generated/resources/data/libx/tags/block/impl_stairs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_stairs.json rename to src/generated/resources/data/libx/tags/block/impl_stairs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_standing_signs.json b/src/generated/resources/data/libx/tags/block/impl_standing_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_standing_signs.json rename to src/generated/resources/data/libx/tags/block/impl_standing_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_stone_buttons.json b/src/generated/resources/data/libx/tags/block/impl_stone_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_stone_buttons.json rename to src/generated/resources/data/libx/tags/block/impl_stone_buttons.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_stone_pressure_plates.json b/src/generated/resources/data/libx/tags/block/impl_stone_pressure_plates.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_stone_pressure_plates.json rename to src/generated/resources/data/libx/tags/block/impl_stone_pressure_plates.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_trapdoors.json b/src/generated/resources/data/libx/tags/block/impl_trapdoors.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_trapdoors.json rename to src/generated/resources/data/libx/tags/block/impl_trapdoors.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wall_hanging_signs.json b/src/generated/resources/data/libx/tags/block/impl_wall_hanging_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wall_hanging_signs.json rename to src/generated/resources/data/libx/tags/block/impl_wall_hanging_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wall_signs.json b/src/generated/resources/data/libx/tags/block/impl_wall_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wall_signs.json rename to src/generated/resources/data/libx/tags/block/impl_wall_signs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_walls.json b/src/generated/resources/data/libx/tags/block/impl_walls.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_walls.json rename to src/generated/resources/data/libx/tags/block/impl_walls.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_buttons.json b/src/generated/resources/data/libx/tags/block/impl_wooden_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_buttons.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_buttons.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_doors.json b/src/generated/resources/data/libx/tags/block/impl_wooden_doors.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_doors.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_doors.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_fences.json b/src/generated/resources/data/libx/tags/block/impl_wooden_fences.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_fences.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_fences.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_pressure_plates.json b/src/generated/resources/data/libx/tags/block/impl_wooden_pressure_plates.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_pressure_plates.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_pressure_plates.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_slabs.json b/src/generated/resources/data/libx/tags/block/impl_wooden_slabs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_slabs.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_slabs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_stairs.json b/src/generated/resources/data/libx/tags/block/impl_wooden_stairs.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_stairs.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_stairs.json diff --git a/src/generated/resources/data/libx/tags/blocks/impl_wooden_trapdoors.json b/src/generated/resources/data/libx/tags/block/impl_wooden_trapdoors.json similarity index 100% rename from src/generated/resources/data/libx/tags/blocks/impl_wooden_trapdoors.json rename to src/generated/resources/data/libx/tags/block/impl_wooden_trapdoors.json diff --git a/src/generated/resources/data/libx/tags/items/impl_buttons.json b/src/generated/resources/data/libx/tags/item/impl_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_buttons.json rename to src/generated/resources/data/libx/tags/item/impl_buttons.json diff --git a/src/generated/resources/data/libx/tags/items/impl_doors.json b/src/generated/resources/data/libx/tags/item/impl_doors.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_doors.json rename to src/generated/resources/data/libx/tags/item/impl_doors.json diff --git a/src/generated/resources/data/libx/tags/items/impl_fence_gates.json b/src/generated/resources/data/libx/tags/item/impl_fence_gates.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_fence_gates.json rename to src/generated/resources/data/libx/tags/item/impl_fence_gates.json diff --git a/src/generated/resources/data/libx/tags/items/impl_fences.json b/src/generated/resources/data/libx/tags/item/impl_fences.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_fences.json rename to src/generated/resources/data/libx/tags/item/impl_fences.json diff --git a/src/generated/resources/data/libx/tags/items/impl_hanging_signs.json b/src/generated/resources/data/libx/tags/item/impl_hanging_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_hanging_signs.json rename to src/generated/resources/data/libx/tags/item/impl_hanging_signs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_logs.json b/src/generated/resources/data/libx/tags/item/impl_logs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_logs.json rename to src/generated/resources/data/libx/tags/item/impl_logs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_logs_that_burn.json b/src/generated/resources/data/libx/tags/item/impl_logs_that_burn.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_logs_that_burn.json rename to src/generated/resources/data/libx/tags/item/impl_logs_that_burn.json diff --git a/src/generated/resources/data/libx/tags/items/impl_signs.json b/src/generated/resources/data/libx/tags/item/impl_signs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_signs.json rename to src/generated/resources/data/libx/tags/item/impl_signs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_slabs.json b/src/generated/resources/data/libx/tags/item/impl_slabs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_slabs.json rename to src/generated/resources/data/libx/tags/item/impl_slabs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_stairs.json b/src/generated/resources/data/libx/tags/item/impl_stairs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_stairs.json rename to src/generated/resources/data/libx/tags/item/impl_stairs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_stone_buttons.json b/src/generated/resources/data/libx/tags/item/impl_stone_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_stone_buttons.json rename to src/generated/resources/data/libx/tags/item/impl_stone_buttons.json diff --git a/src/generated/resources/data/libx/tags/items/impl_trapdoors.json b/src/generated/resources/data/libx/tags/item/impl_trapdoors.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_trapdoors.json rename to src/generated/resources/data/libx/tags/item/impl_trapdoors.json diff --git a/src/generated/resources/data/libx/tags/items/impl_walls.json b/src/generated/resources/data/libx/tags/item/impl_walls.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_walls.json rename to src/generated/resources/data/libx/tags/item/impl_walls.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_buttons.json b/src/generated/resources/data/libx/tags/item/impl_wooden_buttons.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_buttons.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_buttons.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_doors.json b/src/generated/resources/data/libx/tags/item/impl_wooden_doors.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_doors.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_doors.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_fences.json b/src/generated/resources/data/libx/tags/item/impl_wooden_fences.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_fences.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_fences.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_pressure_plates.json b/src/generated/resources/data/libx/tags/item/impl_wooden_pressure_plates.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_pressure_plates.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_pressure_plates.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_slabs.json b/src/generated/resources/data/libx/tags/item/impl_wooden_slabs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_slabs.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_slabs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_stairs.json b/src/generated/resources/data/libx/tags/item/impl_wooden_stairs.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_stairs.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_stairs.json diff --git a/src/generated/resources/data/libx/tags/items/impl_wooden_trapdoors.json b/src/generated/resources/data/libx/tags/item/impl_wooden_trapdoors.json similarity index 100% rename from src/generated/resources/data/libx/tags/items/impl_wooden_trapdoors.json rename to src/generated/resources/data/libx/tags/item/impl_wooden_trapdoors.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/all_hanging_signs.json b/src/generated/resources/data/minecraft/tags/block/all_hanging_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/all_hanging_signs.json rename to src/generated/resources/data/minecraft/tags/block/all_hanging_signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/buttons.json b/src/generated/resources/data/minecraft/tags/block/buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/buttons.json rename to src/generated/resources/data/minecraft/tags/block/buttons.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/ceiling_hanging_signs.json b/src/generated/resources/data/minecraft/tags/block/ceiling_hanging_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/ceiling_hanging_signs.json rename to src/generated/resources/data/minecraft/tags/block/ceiling_hanging_signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/doors.json b/src/generated/resources/data/minecraft/tags/block/doors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/doors.json rename to src/generated/resources/data/minecraft/tags/block/doors.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/fence_gates.json b/src/generated/resources/data/minecraft/tags/block/fence_gates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/fence_gates.json rename to src/generated/resources/data/minecraft/tags/block/fence_gates.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/fences.json b/src/generated/resources/data/minecraft/tags/block/fences.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/fences.json rename to src/generated/resources/data/minecraft/tags/block/fences.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/logs.json b/src/generated/resources/data/minecraft/tags/block/logs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/logs.json rename to src/generated/resources/data/minecraft/tags/block/logs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/logs_that_burn.json b/src/generated/resources/data/minecraft/tags/block/logs_that_burn.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/logs_that_burn.json rename to src/generated/resources/data/minecraft/tags/block/logs_that_burn.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/pressure_plates.json b/src/generated/resources/data/minecraft/tags/block/pressure_plates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/pressure_plates.json rename to src/generated/resources/data/minecraft/tags/block/pressure_plates.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/signs.json b/src/generated/resources/data/minecraft/tags/block/signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/signs.json rename to src/generated/resources/data/minecraft/tags/block/signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/slabs.json b/src/generated/resources/data/minecraft/tags/block/slabs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/slabs.json rename to src/generated/resources/data/minecraft/tags/block/slabs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/stairs.json b/src/generated/resources/data/minecraft/tags/block/stairs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/stairs.json rename to src/generated/resources/data/minecraft/tags/block/stairs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/standing_signs.json b/src/generated/resources/data/minecraft/tags/block/standing_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/standing_signs.json rename to src/generated/resources/data/minecraft/tags/block/standing_signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/stone_buttons.json b/src/generated/resources/data/minecraft/tags/block/stone_buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/stone_buttons.json rename to src/generated/resources/data/minecraft/tags/block/stone_buttons.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/stone_pressure_plates.json b/src/generated/resources/data/minecraft/tags/block/stone_pressure_plates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/stone_pressure_plates.json rename to src/generated/resources/data/minecraft/tags/block/stone_pressure_plates.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/trapdoors.json b/src/generated/resources/data/minecraft/tags/block/trapdoors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/trapdoors.json rename to src/generated/resources/data/minecraft/tags/block/trapdoors.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wall_hanging_signs.json b/src/generated/resources/data/minecraft/tags/block/wall_hanging_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wall_hanging_signs.json rename to src/generated/resources/data/minecraft/tags/block/wall_hanging_signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wall_signs.json b/src/generated/resources/data/minecraft/tags/block/wall_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wall_signs.json rename to src/generated/resources/data/minecraft/tags/block/wall_signs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/walls.json b/src/generated/resources/data/minecraft/tags/block/walls.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/walls.json rename to src/generated/resources/data/minecraft/tags/block/walls.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_buttons.json b/src/generated/resources/data/minecraft/tags/block/wooden_buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_buttons.json rename to src/generated/resources/data/minecraft/tags/block/wooden_buttons.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json b/src/generated/resources/data/minecraft/tags/block/wooden_doors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json rename to src/generated/resources/data/minecraft/tags/block/wooden_doors.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_fences.json b/src/generated/resources/data/minecraft/tags/block/wooden_fences.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_fences.json rename to src/generated/resources/data/minecraft/tags/block/wooden_fences.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_pressure_plates.json b/src/generated/resources/data/minecraft/tags/block/wooden_pressure_plates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_pressure_plates.json rename to src/generated/resources/data/minecraft/tags/block/wooden_pressure_plates.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_slabs.json b/src/generated/resources/data/minecraft/tags/block/wooden_slabs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_slabs.json rename to src/generated/resources/data/minecraft/tags/block/wooden_slabs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_stairs.json b/src/generated/resources/data/minecraft/tags/block/wooden_stairs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_stairs.json rename to src/generated/resources/data/minecraft/tags/block/wooden_stairs.json diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_trapdoors.json b/src/generated/resources/data/minecraft/tags/block/wooden_trapdoors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/blocks/wooden_trapdoors.json rename to src/generated/resources/data/minecraft/tags/block/wooden_trapdoors.json diff --git a/src/generated/resources/data/minecraft/tags/items/buttons.json b/src/generated/resources/data/minecraft/tags/item/buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/buttons.json rename to src/generated/resources/data/minecraft/tags/item/buttons.json diff --git a/src/generated/resources/data/minecraft/tags/items/doors.json b/src/generated/resources/data/minecraft/tags/item/doors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/doors.json rename to src/generated/resources/data/minecraft/tags/item/doors.json diff --git a/src/generated/resources/data/minecraft/tags/items/fence_gates.json b/src/generated/resources/data/minecraft/tags/item/fence_gates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/fence_gates.json rename to src/generated/resources/data/minecraft/tags/item/fence_gates.json diff --git a/src/generated/resources/data/minecraft/tags/items/fences.json b/src/generated/resources/data/minecraft/tags/item/fences.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/fences.json rename to src/generated/resources/data/minecraft/tags/item/fences.json diff --git a/src/generated/resources/data/minecraft/tags/items/hanging_signs.json b/src/generated/resources/data/minecraft/tags/item/hanging_signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/hanging_signs.json rename to src/generated/resources/data/minecraft/tags/item/hanging_signs.json diff --git a/src/generated/resources/data/minecraft/tags/items/logs.json b/src/generated/resources/data/minecraft/tags/item/logs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/logs.json rename to src/generated/resources/data/minecraft/tags/item/logs.json diff --git a/src/generated/resources/data/minecraft/tags/items/logs_that_burn.json b/src/generated/resources/data/minecraft/tags/item/logs_that_burn.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/logs_that_burn.json rename to src/generated/resources/data/minecraft/tags/item/logs_that_burn.json diff --git a/src/generated/resources/data/minecraft/tags/items/signs.json b/src/generated/resources/data/minecraft/tags/item/signs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/signs.json rename to src/generated/resources/data/minecraft/tags/item/signs.json diff --git a/src/generated/resources/data/minecraft/tags/items/slabs.json b/src/generated/resources/data/minecraft/tags/item/slabs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/slabs.json rename to src/generated/resources/data/minecraft/tags/item/slabs.json diff --git a/src/generated/resources/data/minecraft/tags/items/stairs.json b/src/generated/resources/data/minecraft/tags/item/stairs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/stairs.json rename to src/generated/resources/data/minecraft/tags/item/stairs.json diff --git a/src/generated/resources/data/minecraft/tags/items/stone_buttons.json b/src/generated/resources/data/minecraft/tags/item/stone_buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/stone_buttons.json rename to src/generated/resources/data/minecraft/tags/item/stone_buttons.json diff --git a/src/generated/resources/data/minecraft/tags/items/trapdoors.json b/src/generated/resources/data/minecraft/tags/item/trapdoors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/trapdoors.json rename to src/generated/resources/data/minecraft/tags/item/trapdoors.json diff --git a/src/generated/resources/data/minecraft/tags/items/walls.json b/src/generated/resources/data/minecraft/tags/item/walls.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/walls.json rename to src/generated/resources/data/minecraft/tags/item/walls.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_buttons.json b/src/generated/resources/data/minecraft/tags/item/wooden_buttons.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_buttons.json rename to src/generated/resources/data/minecraft/tags/item/wooden_buttons.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_doors.json b/src/generated/resources/data/minecraft/tags/item/wooden_doors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_doors.json rename to src/generated/resources/data/minecraft/tags/item/wooden_doors.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_fences.json b/src/generated/resources/data/minecraft/tags/item/wooden_fences.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_fences.json rename to src/generated/resources/data/minecraft/tags/item/wooden_fences.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_pressure_plates.json b/src/generated/resources/data/minecraft/tags/item/wooden_pressure_plates.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_pressure_plates.json rename to src/generated/resources/data/minecraft/tags/item/wooden_pressure_plates.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_slabs.json b/src/generated/resources/data/minecraft/tags/item/wooden_slabs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_slabs.json rename to src/generated/resources/data/minecraft/tags/item/wooden_slabs.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_stairs.json b/src/generated/resources/data/minecraft/tags/item/wooden_stairs.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_stairs.json rename to src/generated/resources/data/minecraft/tags/item/wooden_stairs.json diff --git a/src/generated/resources/data/minecraft/tags/items/wooden_trapdoors.json b/src/generated/resources/data/minecraft/tags/item/wooden_trapdoors.json similarity index 100% rename from src/generated/resources/data/minecraft/tags/items/wooden_trapdoors.json rename to src/generated/resources/data/minecraft/tags/item/wooden_trapdoors.json diff --git a/src/main/java/org/moddingx/libx/CommonNetwork.java b/src/main/java/org/moddingx/libx/CommonNetwork.java index f7faf05a..8aac4981 100644 --- a/src/main/java/org/moddingx/libx/CommonNetwork.java +++ b/src/main/java/org/moddingx/libx/CommonNetwork.java @@ -1,7 +1,9 @@ package org.moddingx.libx; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import org.moddingx.libx.base.tile.BlockEntityBase; @@ -20,18 +22,18 @@ public class CommonNetwork { } /** - * Sends the nbt tag retrieved from {@link BlockEntity#getUpdateTag()} from the block entity at the given - * position to all clients tracking the chunk. On the client the tag is passed - * to {@link BlockEntity#handleUpdateTag(CompoundTag)}. Does nothing when called on the client. + * Sends the nbt tag retrieved from {@link BlockEntity#getUpdateTag(HolderLookup.Provider)} from the block entity + * at the given position to all clients tracking the chunk. On the client the tag is passed + * to {@link BlockEntity#handleUpdateTag(CompoundTag, HolderLookup.Provider)}. Does nothing when called on the client. */ - public void updateBE(Level level, BlockPos pos) { + public void updateBE(ServerLevel level, BlockPos pos) { this.network.updateBE(level, pos); } /** * Requests the block entity at the given position from the server. This is automatically done when * a {@link BlockEntityBase} is loaded. The server will - * send an update packet as described in {@link #updateBE(Level, BlockPos)} to the client. + * send an update packet as described in {@link #updateBE(ServerLevel, BlockPos)} to the client. * Does nothing when called on the server. */ public void requestBE(Level level, BlockPos pos) { diff --git a/src/main/java/org/moddingx/libx/LibX.java b/src/main/java/org/moddingx/libx/LibX.java index 9b464dff..6ae2e689 100644 --- a/src/main/java/org/moddingx/libx/LibX.java +++ b/src/main/java/org/moddingx/libx/LibX.java @@ -1,39 +1,39 @@ package org.moddingx.libx; -import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.advancements.Advancement; import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.core.registries.Registries; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DataPackRegistryEvent; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegisterEvent; -import org.moddingx.libx.command.EnumArgument2; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.storage.loot.LootTable; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.registries.DataPackRegistryEvent; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import net.neoforged.neoforge.registries.RegisterEvent; +import org.moddingx.libx.command.EnumArgumentIgnoreCase; import org.moddingx.libx.crafting.ingredient.EffectIngredient; import org.moddingx.libx.datagen.DatagenSystem; import org.moddingx.libx.impl.BlockEntityUpdateQueue; import org.moddingx.libx.impl.InternalDataGen; -import org.moddingx.libx.impl.commands.client.ClientCommandsImpl; -import org.moddingx.libx.impl.commands.common.CommandsImpl; +import org.moddingx.libx.impl.command.client.ClientCommandsImpl; +import org.moddingx.libx.impl.command.common.CommandsImpl; import org.moddingx.libx.impl.config.ConfigEvents; import org.moddingx.libx.impl.crafting.recipe.EmptyRecipe; import org.moddingx.libx.impl.datapack.DynamicPackLocator; import org.moddingx.libx.impl.loot.AllLootEntry; +import org.moddingx.libx.impl.loot.CopyBlockEntityDataFunction; import org.moddingx.libx.impl.loot.modifier.AdditionLootModifier; import org.moddingx.libx.impl.loot.modifier.RemovalLootModifier; -import org.moddingx.libx.impl.menu.screen.GenericScreen; import org.moddingx.libx.impl.network.NetworkImpl; import org.moddingx.libx.impl.render.BlockOverlayQuadCache; import org.moddingx.libx.impl.sandbox.EmptySurfaceRule; import org.moddingx.libx.impl.sandbox.density.*; -import org.moddingx.libx.menu.GenericMenu; +import org.moddingx.libx.inventory.StackItemHandler; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.render.ClientTickHandler; import org.moddingx.libx.sandbox.SandBox; @@ -59,46 +59,48 @@ public final class LibX extends ModX { private static LibX instance; private static CommonNetwork networkWrapper; - public LibX() { + public LibX(IEventBus modBus) { instance = this; NetworkImpl network = new NetworkImpl(this); networkWrapper = new CommonNetwork(network); // level stem needs to be in extension phase, so it can reference surface data. DatagenSystem.registerExtensionRegistry(Registries.LEVEL_STEM); - DatagenSystem.registerExtensionRegistry(ForgeRegistries.Keys.BIOME_MODIFIERS); - DatagenSystem.registerExtensionRegistry(ForgeRegistries.Keys.STRUCTURE_MODIFIERS); + DatagenSystem.registerExtensionRegistry(NeoForgeRegistries.Keys.BIOME_MODIFIERS); + DatagenSystem.registerExtensionRegistry(NeoForgeRegistries.Keys.STRUCTURE_MODIFIERS); DatagenSystem.registerExtensionRegistry(SandBox.BIOME_SURFACE); DatagenSystem.registerExtensionRegistry(SandBox.SURFACE_RULE_SET); DatagenSystem.registerExtensionRegistry(SandBox.TEMPLATE_POOL_EXTENSION); + DatagenSystem.defineDatagenRegistry(Registries.LOOT_TABLE, LootTable.DIRECT_CODEC); + DatagenSystem.defineDatagenRegistry(Registries.RECIPE, Recipe.CODEC); + DatagenSystem.defineDatagenRegistry(Registries.ADVANCEMENT, Advancement.CODEC); InternalDataGen.init(); - FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.LOW, DynamicPackLocator::locatePacks); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::createRegistries); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::registerStuff); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(BlockOverlayQuadCache::resourcesReload)); + modBus.addListener(EventPriority.LOW, DynamicPackLocator::locatePacks); + modBus.addListener(this::createRegistries); + modBus.addListener(this::registerStuff); + if (FMLLoader.getDist().isClient()) { + modBus.addListener(BlockOverlayQuadCache::resourcesReload); + } - MinecraftForge.EVENT_BUS.addListener(ClientTickHandler::tick); - MinecraftForge.EVENT_BUS.addListener(BlockEntityUpdateQueue::tick); - MinecraftForge.EVENT_BUS.addListener(CommandsImpl::registerCommands); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.addListener(ClientCommandsImpl::registerClientCommands)); - MinecraftForge.EVENT_BUS.register(new ConfigEvents()); - - CraftingHelper.register(this.resource("effect"), EffectIngredient.Serializer.INSTANCE); + NeoForge.EVENT_BUS.addListener(ClientTickHandler::tick); + NeoForge.EVENT_BUS.addListener(BlockEntityUpdateQueue::tick); + NeoForge.EVENT_BUS.addListener(CommandsImpl::registerCommands); + NeoForge.EVENT_BUS.register(new ConfigEvents()); + if (FMLLoader.getDist().isClient()) { + NeoForge.EVENT_BUS.addListener(ClientCommandsImpl::registerClientCommands); + } } @Override protected void setup(FMLCommonSetupEvent event) { //noinspection unchecked,rawtypes - ArgumentTypeInfos.registerByClass((Class) EnumArgument2.class, EnumArgument2.Info.INSTANCE); + ArgumentTypeInfos.registerByClass((Class) EnumArgumentIgnoreCase.class, EnumArgumentIgnoreCase.Info.INSTANCE); } @Override protected void clientSetup(FMLClientSetupEvent event) { - //noinspection CodeBlock2Expr - event.enqueueWork(() -> { - MenuScreens.register(GenericMenu.TYPE, GenericScreen::new); - }); + // } /** @@ -124,12 +126,13 @@ private void createRegistries(DataPackRegistryEvent.NewRegistry event) { private void registerStuff(RegisterEvent event) { event.register(Registries.LOOT_POOL_ENTRY_TYPE, AllLootEntry.ID, () -> AllLootEntry.TYPE); - event.register(Registries.MENU, this.resource("generic"), () -> GenericMenu.TYPE); + event.register(Registries.LOOT_FUNCTION_TYPE, CopyBlockEntityDataFunction.ID, () -> CopyBlockEntityDataFunction.TYPE); + event.register(NeoForgeRegistries.Keys.INGREDIENT_TYPES, this.resource("effect"), () -> EffectIngredient.TYPE); event.register(Registries.RECIPE_TYPE, EmptyRecipe.ID, () -> EmptyRecipe.TYPE); event.register(Registries.RECIPE_SERIALIZER, EmptyRecipe.ID, () -> EmptyRecipe.Serializer.INSTANCE); - event.register(Registries.COMMAND_ARGUMENT_TYPE, this.resource("enum"), () -> EnumArgument2.Info.INSTANCE); - event.register(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, this.resource("addition"), () -> AdditionLootModifier.CODEC); - event.register(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, this.resource("removal"), () -> RemovalLootModifier.CODEC); + event.register(Registries.COMMAND_ARGUMENT_TYPE, this.resource("enum"), () -> EnumArgumentIgnoreCase.Info.INSTANCE); + event.register(NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, this.resource("addition"), () -> AdditionLootModifier.CODEC); + event.register(NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, this.resource("removal"), () -> RemovalLootModifier.CODEC); event.register(Registries.MATERIAL_RULE, this.resource("empty"), () -> EmptySurfaceRule.CODEC); event.register(Registries.CHUNK_GENERATOR, this.resource("noise"), () -> ExtendedNoiseChunkGenerator.CODEC); event.register(Registries.BIOME_SOURCE, this.resource("layered"), () -> LayeredBiomeSource.CODEC); @@ -140,5 +143,6 @@ private void registerStuff(RegisterEvent event) { event.register(Registries.DENSITY_FUNCTION_TYPE, this.resource("debug"), DensityDebug.CODEC::codec); event.register(Registries.DENSITY_FUNCTION_TYPE, this.resource("lerp"), DensityLerp.CODEC::codec); event.register(Registries.DENSITY_FUNCTION_TYPE, this.resource("clamp"), DensityClamp.CODEC::codec); + event.register(Registries.DATA_COMPONENT_TYPE, this.resource("inventory"), () -> StackItemHandler.INVENTORY_DATA); } } diff --git a/src/main/java/org/moddingx/libx/annotation/ForMod.java b/src/main/java/org/moddingx/libx/annotation/ForMod.java index 68af88a4..8b80b014 100644 --- a/src/main/java/org/moddingx/libx/annotation/ForMod.java +++ b/src/main/java/org/moddingx/libx/annotation/ForMod.java @@ -1,6 +1,6 @@ package org.moddingx.libx.annotation; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.fml.common.Mod; import org.moddingx.libx.mod.ModX; import java.lang.annotation.Documented; diff --git a/src/main/java/org/moddingx/libx/annotation/api/Codecs.java b/src/main/java/org/moddingx/libx/annotation/api/Codecs.java index 23dffd3e..74cc14f1 100644 --- a/src/main/java/org/moddingx/libx/annotation/api/Codecs.java +++ b/src/main/java/org/moddingx/libx/annotation/api/Codecs.java @@ -9,23 +9,23 @@ /** * Class to retrieve generated {@link Codec codecs}. They should normally be assigned to a - * {@code public static final} field in the class that the codec is for. + * {@code public static final} field in the class that the streamCodec is for. */ public class Codecs { /** - * Gets a codec created by the use of the {@link PrimaryConstructor} annotation. + * Gets a streamCodec created by the use of the {@link PrimaryConstructor} annotation. * Should be assigned to a {@code public static final} field named {@code CODEC} in the same file. * * @param mod Your mods' class - * @param clazz The class of which the codec was created + * @param clazz The class of which the streamCodec was created */ public static Codec get(Class mod, Class clazz) { Map, Codec> map = ModInternal.get(mod).getCodecMap(); if (map == null) { - throw new IllegalStateException("Can't get codec for " + clazz + ": No generated codecs for mod " + mod + "."); + throw new IllegalStateException("Can't get streamCodec for " + clazz + ": No generated codecs for mod " + mod + "."); } else if (!map.containsKey(clazz)) { - throw new IllegalStateException("Can't get codec for " + clazz + ": No codec found."); + throw new IllegalStateException("Can't get streamCodec for " + clazz + ": No streamCodec found."); } else { //noinspection unchecked return (Codec) map.get(clazz); diff --git a/src/main/java/org/moddingx/libx/annotation/impl/ProcessorInterface.java b/src/main/java/org/moddingx/libx/annotation/impl/ProcessorInterface.java index b593588c..2bfaa687 100644 --- a/src/main/java/org/moddingx/libx/annotation/impl/ProcessorInterface.java +++ b/src/main/java/org/moddingx/libx/annotation/impl/ProcessorInterface.java @@ -2,17 +2,16 @@ import com.mojang.serialization.Codec; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.event.ModelEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.RegistryManager; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.fml.ModList; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.client.event.ModelEvent; import org.moddingx.libx.codec.MoreCodecs; import org.moddingx.libx.config.ConfigManager; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -24,50 +23,44 @@ import org.moddingx.libx.mod.ModXRegistration; import javax.annotation.Nullable; -import java.lang.reflect.Field; import java.util.function.Consumer; public class ProcessorInterface { - public static ResourceLocation newRL(String rl) { - return new ResourceLocation(rl); + public static boolean isDistClient() { + return FMLLoader.getDist() == Dist.CLIENT; } + public static ResourceLocation newRL(String rl) { + return ResourceLocation.parse(rl); + } + public static ResourceLocation newRL(String namespace, String path) { - return new ResourceLocation(namespace, path); + return ResourceLocation.fromNamespaceAndPath(namespace, path); } - + public static void registerConfig(ModX mod, String name, Class configClass, boolean client) { ConfigManager.registerConfig(mod.resource(name), configClass, client); } - + public static void registerConfigMapper(ModX mod, ValueMapper mapper) { ConfigManager.registerValueMapper(mod.modid, mapper); } - + public static void registerConfigMapper(ModX mod, GenericValueMapper mapper) { ConfigManager.registerValueMapper(mod.modid, mapper); } - + public static void registerConfigMapper(ModX mod, MapperFactory mapper) { ConfigManager.registerValueMapperFactory(mod.modid, mapper); } - - public static void register(ModX mod, @Nullable ResourceKey> registryKey, String name, Object value, @Nullable FieldGetter field) throws ReflectiveOperationException { + + public static void register(ModX mod, @Nullable ResourceKey> registryKey, String name, Object value) throws ReflectiveOperationException { if (!(mod instanceof ModXRegistration reg)) throw new IllegalStateException("Can't register to a non-ModXRegistration mod."); //noinspection unchecked reg.register((ResourceKey>) registryKey, name, value); - - // Only directly add registry tracking for actually registered stuff, MultiRegisterable has no real registry - if (registryKey != null && field != null) { - @SuppressWarnings("UnstableApiUsage") - IForgeRegistry forgeRegistry = RegistryManager.ACTIVE.getRegistry(registryKey.location()); - if (forgeRegistry != null) { - ModInternal.get(mod).getRegistrationDispatcher().notifyRegisterField(forgeRegistry, name, field.get()); - } - } } - + // For code with checked exceptions that we know are never thrown public static void runUnchecked(ThrowingRunnable runnable) { try { @@ -76,23 +69,19 @@ public static void runUnchecked(ThrowingRunnable runnable) { ReflectionHacks.throwUnchecked(e); } } - + public static > Codec enumCodec(Class clazz) { return MoreCodecs.enumCodec(clazz); } - - public static void addModListener(Class event, Consumer listener) { - FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.NORMAL, false, event, listener); - } - - public static void addLowModListener(Class event, Consumer listener) { - FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.LOW, false, event, listener); + + public static void addModListener(ModX mod, Class event, Consumer listener) { + ModInternal.get(mod).modEventBus().addListener(EventPriority.NORMAL, false, event, listener); } - - public static void addForgeListener(Class event, Consumer listener) { - MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, event, listener); + + public static void addLowModListener(ModX mod, Class event, Consumer listener) { + ModInternal.get(mod).modEventBus().addListener(EventPriority.LOW, false, event, listener); } - + public static LazyMapBuilder lazyMapBuilder() { return new LazyMapBuilder<>(); } @@ -100,28 +89,23 @@ public static LazyMapBuilder lazyMapBuilder() { public static boolean isModLoaded(String modid) { return ModList.get().isLoaded(modid); } - + public static void addSpecialModel(ModelEvent.RegisterAdditional event, ResourceLocation id) { - event.register(id); + event.register(new ModelResourceLocation(id, ModelResourceLocation.STANDALONE_VARIANT)); } - + public static BakedModel getSpecialModel(ModelEvent.BakingCompleted event, ResourceLocation id) { - if (event.getModels().containsKey(id)) { - return event.getModels().get(id); + ModelResourceLocation modelId = new ModelResourceLocation(id, ModelResourceLocation.STANDALONE_VARIANT); + if (event.getModels().containsKey(modelId)) { + return event.getModels().get(modelId); } else { throw new IllegalStateException("Model not loaded: " + id); } } - + @FunctionalInterface public interface ThrowingRunnable { - + void run() throws Exception; } - - @FunctionalInterface - public interface FieldGetter { - - Field get() throws ReflectiveOperationException; - } } diff --git a/src/main/java/org/moddingx/libx/base/BlockBase.java b/src/main/java/org/moddingx/libx/base/BlockBase.java index fe6e6687..9c5758a8 100644 --- a/src/main/java/org/moddingx/libx/base/BlockBase.java +++ b/src/main/java/org/moddingx/libx/base/BlockBase.java @@ -6,8 +6,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Block; -import net.minecraftforge.client.extensions.common.IClientItemExtensions; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.creativetab.CreativeTabItemProvider; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.mod.ModXRegistration; @@ -17,7 +15,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.OverridingMethodsMustInvokeSuper; -import java.util.function.Consumer; import java.util.stream.Stream; /** @@ -55,14 +52,6 @@ public BlockBase(ModX mod, Properties properties, @Nullable Item.Properties item this.item = new BaseBlockItem(this, itemProperties); } } - - /** - * Called from the item for this block from {@link Item#initializeClient(Consumer)}. - * Can be used to set client extensions for the block item. - */ - public void initializeItemClient(@Nonnull Consumer consumer) { - - } public int getBurnTime(ItemStack stack, @Nullable RecipeType recipeType) { return -1; @@ -80,28 +69,15 @@ public void registerAdditional(RegistrationContext ctx, EntryCollector builder) builder.register(Registries.ITEM, this.item); } } - - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { - if (this.hasItem) { - builder.track(ForgeRegistries.ITEMS, BlockBase.class.getDeclaredField("item")); - } - } private class BaseBlockItem extends BlockItem implements CreativeTabItemProvider { public BaseBlockItem(Block block, Properties itemProperties) { super(block, itemProperties); } - - @Override - public void initializeClient(@Nonnull Consumer consumer) { - BlockBase.this.initializeItemClient(consumer); - } @Override - public int getBurnTime(ItemStack stack, @Nullable RecipeType recipeType) { + public int getBurnTime(@Nonnull ItemStack stack, @Nullable RecipeType recipeType) { return BlockBase.this.getBurnTime(stack, recipeType); } diff --git a/src/main/java/org/moddingx/libx/base/FluidBase.java b/src/main/java/org/moddingx/libx/base/FluidBase.java index 33a83fd8..8fb7c813 100644 --- a/src/main/java/org/moddingx/libx/base/FluidBase.java +++ b/src/main/java/org/moddingx/libx/base/FluidBase.java @@ -1,285 +1,286 @@ package org.moddingx.libx.base; import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.material.FlowingFluid; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidType; -import net.minecraftforge.fluids.ForgeFlowingFluid; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.BaseFlowingFluid; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import org.moddingx.libx.annotation.registration.PlainRegisterable; +import org.moddingx.libx.impl.base.fluid.DefaultBucketItem; import org.moddingx.libx.impl.base.fluid.DefaultClientExtensions; -import org.moddingx.libx.impl.base.fluid.FluidTypeBase; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.RegistrationContext; +import org.moddingx.libx.registration.util.ClientExtensionInfo; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.annotation.OverridingMethodsMustInvokeSuper; -import java.util.Objects; -import java.util.function.Consumer; +import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.Supplier; +import java.util.function.UnaryOperator; /** - * A {@link Registerable} that registers a {@link Fluid fluid}, a flowing fluid, + * A {@link Registerable} that registers a {@link FluidType fluid type}, source and flowing {@link Fluid fluid}, * a {@link LiquidBlock liquid block} and a {@link BucketItem bucket item}. */ -public class FluidBase implements Registerable, ItemLike { - +@PlainRegisterable +public class FluidBase implements ItemLike, Registerable { + protected final ModX mod; - private final Function sourceFactory; - private final Function flowingFactory; - private final FluidType.Properties properties; - - @Nullable - private final Supplier> clientExtensions; - - private boolean initialised; - - private ForgeFlowingFluid.Source source; - private ForgeFlowingFluid.Flowing flowing; - private FluidType type; - private ForgeFlowingFluid.Properties fluidProperties; - private final LiquidBlock block; - private final BucketItem bucket; - - private FluidBase(ModX mod, Function sourceFactory, Function flowingFactory, FluidType.Properties properties, @Nullable Supplier> clientExtensions, BlockBehaviour.Properties blockProperties, Item.Properties itemProperties) { + private final FluidType fluidType; + private final FlowingFluid sourceFluid; + private final FlowingFluid flowingFluid; + private final LiquidBlock liquidBlock; + private final BucketItem bucketItem; + + public FluidBase(ModX mod, Builder fluidBuilder) { this.mod = mod; - this.sourceFactory = sourceFactory; - this.flowingFactory = flowingFactory; - this.properties = properties; - this.clientExtensions = clientExtensions; - - this.initialised = false; - - this.block = new LiquidBlock(this::getSource, blockProperties); - this.bucket = new BucketItem(this::getSource, itemProperties.stacksTo(1)) { - - @Override - public ItemStack getCraftingRemainingItem(ItemStack stack) { - return new ItemStack(Items.BUCKET); - } - - @Nonnull - @Override - protected String getOrCreateDescriptionId() { - return "libx.tooltip.fluidbase.bucket"; - } - - @Nonnull - @Override - public Component getName(@Nonnull ItemStack stack) { - return Component.translatable("libx.tooltip.fluidbase.bucket", FluidBase.this.getFluid().getFluidType().getDescription(new FluidStack(this.getFluid(), FluidType.BUCKET_VOLUME))); - } - - @Nonnull - @Override - public Component getDescription() { - return Component.translatable("libx.tooltip.fluidbase.bucket", FluidBase.this.getFluid().getFluidType().getDescription(new FluidStack(this.getFluid(), FluidType.BUCKET_VOLUME))); - } - }; + BaseFlowingFluid.Properties fluidProperties = fluidBuilder.fluidProperties.apply(new BaseFlowingFluid.Properties(this::getFluidType, this::getSourceFluid, this::getFlowingFluid)); + fluidProperties = fluidProperties.block(this::getLiquidBlock).bucket(this::getBucketItem); + this.fluidType = fluidBuilder.fluidTypeFactory.apply(fluidBuilder.fluidTypeProperties); + this.sourceFluid = fluidBuilder.sourceFluidFactory.apply(fluidProperties); + this.flowingFluid = fluidBuilder.flowingFluidFactory.apply(fluidProperties); + this.liquidBlock = fluidBuilder.liquidBlockFactory.apply(this.sourceFluid, fluidBuilder.blockProperties); + this.bucketItem = fluidBuilder.bucketItemFactory.apply(this.sourceFluid, fluidBuilder.bucketItemProperties); } /** - * Gets the fluid. This should be used in recipes or {@link IFluidHandler fluid handlers}. - * - * @see #getSource() + * Creates the {@link IClientFluidTypeExtensions client extensions} for this fluid. The default + * implementation creates client extensions that have no special properties, use a still texture + * located at {@code [namespace]:block/[path]} and a flowing texture located at + * {@code [namespace]:block/[path]_flowing}. */ - @Nonnull - public Fluid getFluid() { - return this.getSource(); + @OnlyIn(Dist.CLIENT) + protected ClientExtensionInfo.Fluid createClientExtensions(ResourceLocation id) { + ResourceLocation stillTexture = ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath()); + ResourceLocation flowingTexture = ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath() + "_flowing"); + return new ClientExtensionInfo.Fluid(new DefaultClientExtensions(stillTexture, flowingTexture)); + } + + @Override + @OverridingMethodsMustInvokeSuper + public void registerAdditional(RegistrationContext ctx, EntryCollector builder) { + builder.register(NeoForgeRegistries.Keys.FLUID_TYPES, this.fluidType); + builder.register(Registries.FLUID, this.sourceFluid); + builder.registerNamed(Registries.FLUID, "flowing", this.flowingFluid); + builder.register(Registries.BLOCK, this.liquidBlock); + builder.registerNamed(Registries.ITEM, "bucket", this.bucketItem); + } + + @Override + @OnlyIn(Dist.CLIENT) + @OverridingMethodsMustInvokeSuper + public void registerClientAdditional(RegistrationContext ctx, EntryCollector builder) { + builder.register(null, this.createClientExtensions(ctx.id())); } /** - * Gets the source fluid. In most cases you should use {@link #getFluid()}. - * - * @see #getFluid() + * Gets the {@link FluidType fluid type} for this {@link FluidBase}. */ @Nonnull - public ForgeFlowingFluid.Source getSource() { - return Objects.requireNonNull(this.source, "FluidBase has not yet been registered."); + public final FluidType getFluidType() { + return this.fluidType; } - + /** - * Gets the fluid type. + * Gets the {@link Fluid source fluid} for this {@link FluidBase}. This is the same as {@link #getSourceFluid()}. + * One should prefer this method over {@link #getSourceFluid()} when needing a representative for the whole + * {@link FluidType fluid type}, for example when creating {@link FluidStack fluid stacks}. */ @Nonnull - public FluidType getType() { - return Objects.requireNonNull(this.type, "FluidBase has not yet been registered."); + public final Fluid getFluid() { + return this.getSourceFluid(); } - + /** - * Gets the flowing fluid. - * - * @see #getSource() + * Gets the {@link Fluid source fluid} for this {@link FluidBase}. This is the same as {@link #getFluid()}. + * One should prefer this method over {@link #getFluid()} when a distinction between source and flowing fluids + * is to be made. */ @Nonnull - public ForgeFlowingFluid.Flowing getFlowing() { - return Objects.requireNonNull(this.flowing, "FluidBase has not yet been registered."); + public final Fluid getSourceFluid() { + return this.sourceFluid; } /** - * Gets the fluid block for this fluid. + * Gets the {@link Fluid flowing fluid} for this {@link FluidBase}. */ @Nonnull - public LiquidBlock getBlock() { - return Objects.requireNonNull(this.block, "FluidBase has not yet been registered."); + public final Fluid getFlowingFluid() { + return this.flowingFluid; } /** - * Gets the bucket item for this fluid. + * Gets the {@link LiquidBlock liquid block} for this {@link FluidBase}. */ @Nonnull - public BucketItem getBucket() { - return Objects.requireNonNull(this.bucket, "FluidBase has not yet been registered."); + public final LiquidBlock getLiquidBlock() { + return this.liquidBlock; } - + /** - * Gets the properties for this fluid. + * Gets the {@link BucketItem bucket item} for this {@link FluidBase}. */ @Nonnull - public ForgeFlowingFluid.Properties getProperties() { - return Objects.requireNonNull(this.fluidProperties, "FluidBase has not yet been registered."); + public final BucketItem getBucketItem() { + return this.bucketItem; } /** - * Same as {@link #getBucket()} + * This is the same as {@link #getBucketItem()} and allows {@link FluidBase} to be used as an {@link ItemLike}. */ @Nonnull @Override - public Item asItem() { - return this.getBucket(); - } - - @Override - @OverridingMethodsMustInvokeSuper - public void registerAdditional(RegistrationContext ctx, EntryCollector builder) { - this.init(ctx.id()); - builder.register(Registries.FLUID, this.source); - builder.registerNamed(Registries.FLUID, "flowing", this.flowing); - builder.register(Registries.BLOCK, this.block); - builder.registerNamed(Registries.ITEM, "bucket", this.bucket); - builder.registerNamed(ForgeRegistries.Keys.FLUID_TYPES, "type", this.type); - } - - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { - this.init(ctx.id()); - builder.track(ForgeRegistries.FLUIDS, FluidBase.class.getDeclaredField("source")); - builder.trackNamed(ForgeRegistries.FLUIDS, "flowing", FluidBase.class.getDeclaredField("flowing")); - builder.track(ForgeRegistries.BLOCKS, FluidBase.class.getDeclaredField("block")); - builder.trackNamed(ForgeRegistries.ITEMS, "bucket", FluidBase.class.getDeclaredField("bucket")); - builder.trackNamed(ForgeRegistries.ITEMS, "type", FluidBase.class.getDeclaredField("type")); - } - - private synchronized void init(ResourceLocation id) { - if (!this.initialised) { - this.initialised = true; - this.properties.descriptionId("fluid." + id.getNamespace() + "." + id.getPath()); - this.type = new FluidTypeBase(this.properties, this.clientExtensions != null ? this.clientExtensions : () -> () -> new DefaultClientExtensions( - new ResourceLocation(id.getNamespace(), "block/" + id.getPath()) - )); - - this.fluidProperties = new ForgeFlowingFluid.Properties(this::getType, this::getSource, this::getFlowing) - .block(this::getBlock) - .bucket(this::getBucket); - - this.source = this.sourceFactory.apply(this.fluidProperties); - this.flowing = this.flowingFactory.apply(this.fluidProperties); - } + public final Item asItem() { + return this.getBucketItem(); } - public static Builder builder(ModX mod) { - return new Builder(mod); + /** + * Creates a new fluid builder for setting the basic fluid properties to be passed in the constructor. + */ + public static Builder fluidBuilder() { + return new Builder(); } - + public static class Builder { - private final ModX mod; - - private Function sourceFactory; - private Function flowingFactory; - - @Nullable - private Supplier> clientExtensions; - private FluidType.Properties properties; + private Function fluidTypeFactory; + private Function sourceFluidFactory; + private Function flowingFluidFactory; + private BiFunction liquidBlockFactory; + private BiFunction bucketItemFactory; + + private FluidType.Properties fluidTypeProperties; private BlockBehaviour.Properties blockProperties; - private Item.Properties itemProperties; - - private Builder(ModX mod) { - this.mod = mod; - this.sourceFactory = ForgeFlowingFluid.Source::new; - this.flowingFactory = ForgeFlowingFluid.Flowing::new; - this.clientExtensions = null; - this.properties = FluidType.Properties.create(); - this.blockProperties = BlockBehaviour.Properties.copy(Blocks.WATER); - this.itemProperties = new Item.Properties(); + private Item.Properties bucketItemProperties; + private UnaryOperator fluidProperties; + + private Builder() { + this.fluidTypeFactory = FluidType::new; + this.sourceFluidFactory = BaseFlowingFluid.Source::new; + this.flowingFluidFactory = BaseFlowingFluid.Flowing::new; + this.liquidBlockFactory = LiquidBlock::new; + this.bucketItemFactory = DefaultBucketItem::new; + + this.fluidTypeProperties = FluidType.Properties.create(); + this.blockProperties = BlockBehaviour.Properties.ofFullCopy(Blocks.WATER); + this.bucketItemProperties = new Item.Properties().craftRemainder(Items.BUCKET).stacksTo(1); + this.fluidProperties = UnaryOperator.identity(); } - public Builder sourceFactory(Function sourceFactory) { - this.sourceFactory = sourceFactory; + /** + * Provides a custom implementation for {@link FluidType}. + */ + public FluidBase.Builder fluidType(Function fluidTypeFactory) { + this.fluidTypeFactory = fluidTypeFactory; return this; } - public Builder flowingFactory(Function flowingFactory) { - this.flowingFactory = flowingFactory; + /** + * Provides a custom implementation for the {@link FlowingFluid source fluid}. + */ + public FluidBase.Builder sourceFluid(Function sourceFluidFactory) { + this.sourceFluidFactory = sourceFluidFactory; return this; } - public Builder clientExtensions(Supplier> clientExtensions) { - this.clientExtensions = clientExtensions; + /** + * Provides a custom implementation for the {@link FlowingFluid flowing fluid}. + */ + public FluidBase.Builder flowingFluid(Function flowingFluidFactory) { + this.flowingFluidFactory = flowingFluidFactory; return this; } - public Builder properties(FluidType.Properties properties) { - this.properties = properties; + + /** + * Provides a custom implementation for the {@link LiquidBlock liquid block}. + */ + public FluidBase.Builder liquidBlock(BiFunction liquidBlockFactory) { + this.liquidBlockFactory = liquidBlockFactory; return this; } - public Builder properties(Consumer action) { - action.accept(this.properties); + /** + * Provides a custom implementation for the {@link BucketItem bucket item}. + */ + public FluidBase.Builder bucketItem(BiFunction bucketItemFactory) { + this.bucketItemFactory = bucketItemFactory; return this; } - public Builder blockProperties(BlockBehaviour.Properties blockProperties) { + /** + * Sets the {@link FluidType.Properties fluid type properties}. + */ + public FluidBase.Builder properties(FluidType.Properties fluidTypeProperties) { + this.fluidTypeProperties = fluidTypeProperties; + return this; + } + + /** + * Runs an action on the current {@link FluidType.Properties fluid type properties}. + */ + public FluidBase.Builder properties(UnaryOperator fluidTypePropertiesOp) { + this.fluidTypeProperties = fluidTypePropertiesOp.apply(this.fluidTypeProperties); + return this; + } + + /** + * Sets the {@link BlockBehaviour.Properties liquid block properties}. + */ + public FluidBase.Builder blockProperties(BlockBehaviour.Properties blockProperties) { this.blockProperties = blockProperties; return this; } - - public Builder blockProperties(Consumer action) { - action.accept(this.blockProperties); + + /** + * Runs an action on the current {@link BlockBehaviour.Properties liquid block properties}. + */ + public FluidBase.Builder blockProperties(UnaryOperator blockPropertiesOp) { + this.blockProperties = blockPropertiesOp.apply(this.blockProperties); return this; } - - public Builder itemProperties(Item.Properties itemProperties) { - this.itemProperties = itemProperties; + + /** + * Sets the {@link Item.Properties bucket item properties}. + */ + public FluidBase.Builder bucketItemProperties(Item.Properties bucketItemProperties) { + this.bucketItemProperties = bucketItemProperties; return this; } - - public Builder itemProperties(Consumer action) { - action.accept(this.itemProperties); + + /** + * Runs an action on the current {@link Item.Properties bucket item properties}. + */ + public FluidBase.Builder bucketItemProperties(UnaryOperator bucketItemPropertiesOp) { + this.bucketItemProperties = bucketItemPropertiesOp.apply(this.bucketItemProperties); return this; } - public FluidBase build() { - return new FluidBase( - this.mod, this.sourceFactory, this.flowingFactory, this.properties, - this.clientExtensions, this.blockProperties, this.itemProperties - ); + /** + * Runs an action on the current {@link BaseFlowingFluid.Properties fluid properties}. + */ + public FluidBase.Builder fluidProperties(UnaryOperator fluidPropertiesOp) { + this.fluidProperties = compose(this.fluidProperties, fluidPropertiesOp); + return this; + } + + private static UnaryOperator compose(UnaryOperator a, UnaryOperator b) { + return t -> b.apply(a.apply(t)); } } } diff --git a/src/main/java/org/moddingx/libx/base/ItemInventory.java b/src/main/java/org/moddingx/libx/base/ItemInventory.java index 3ad3c813..549b8e4c 100644 --- a/src/main/java/org/moddingx/libx/base/ItemInventory.java +++ b/src/main/java/org/moddingx/libx/base/ItemInventory.java @@ -1,100 +1,40 @@ package org.moddingx.libx.base; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; +import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponentType; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.capabilities.Capabilities; +import org.moddingx.libx.codec.MoreStreamCodecs; +import org.moddingx.libx.inventory.StackItemHandler; import org.moddingx.libx.mod.ModX; +import org.moddingx.libx.registration.Registerable; +import org.moddingx.libx.registration.RegistrationContext; +import org.moddingx.libx.registration.util.CapabilityInfo; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.OverridingMethodsMustInvokeSuper; import java.util.function.Function; /** * Base class for {@link Item items} which have an inventory. This will provide the capability to the item. */ -public class ItemInventory> extends ItemBase { +public class ItemInventory extends ItemBase implements Registerable { - private final Function inventoryFactory; + public static final DataComponentType> INVENTORY_DATA = new DataComponentType.Builder>() + .persistent(NonNullList.codecOf(ItemStack.OPTIONAL_CODEC)) + .networkSynchronized(MoreStreamCodecs.listOf(ItemStack.OPTIONAL_STREAM_CODEC).map(NonNullList::copyOf, Function.identity())) + .build(); + + private final int inventorySize; - /** - * Creates a new item with inventory. - * - * @param inventoryFactory A factory that creates new item handler for an item stack. The runnable - * given to that function should be called in {@code onContentsChanged} - */ - public ItemInventory(ModX mod, Properties properties, Function inventoryFactory) { + public ItemInventory(ModX mod, int inventorySize, Properties properties) { super(mod, properties); - this.inventoryFactory = inventoryFactory; + this.inventorySize = inventorySize; } - @Nullable @Override - public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag capTag) { - ICapabilityProvider parent = super.initCapabilities(stack, capTag); - - LazyOptional inventoryCapability = LazyOptional.of(() -> { - AtomicReference handler = new AtomicReference<>(null); - handler.set(this.inventoryFactory.apply(() -> { - CompoundTag nbt = stack.getOrCreateTag(); - nbt.put("Inventory", handler.get().serializeNBT()); - stack.setTag(nbt); - })); - CompoundTag nbt = stack.getTag(); - if (nbt != null && nbt.contains("Inventory", Tag.TAG_COMPOUND)) { - handler.get().deserializeNBT(nbt.getCompound("Inventory")); - } - return handler.get(); - }); - - return new ICapabilityProvider() { - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (cap == ForgeCapabilities.ITEM_HANDLER) { - return inventoryCapability.cast(); - } else { - return parent == null ? LazyOptional.empty() : parent.getCapability(cap, side); - } - } - }; - } - - /** - * Gets the inventory of an {@link ItemStack} or null if the ItemStack doesn't have the item handler capability - * or the item handler is not an instance of {@link IItemHandlerModifiable}. - */ - @Nullable - public static IItemHandlerModifiable getInventory(ItemStack stack) { - IItemHandler handler = stack.getCapability(ForgeCapabilities.ITEM_HANDLER).resolve().orElse(null); - if (handler instanceof IItemHandlerModifiable modifiable) { - return modifiable; - } else { - return null; - } - } - - /** - * Gets an {@link Optional} containing the inventory of an {@link ItemStack} or an empty optional if the ItemStack - * doesn't have the item handler capability or the item handler is not an instance of {@link IItemHandlerModifiable}. - */ - public static Optional getInventoryOption(ItemStack stack) { - IItemHandler handler = stack.getCapability(ForgeCapabilities.ITEM_HANDLER).resolve().orElse(null); - if (handler instanceof IItemHandlerModifiable modifiable) { - return Optional.of(modifiable); - } else { - return Optional.empty(); - } + @OverridingMethodsMustInvokeSuper + public void registerAdditional(RegistrationContext ctx, EntryCollector builder) { + builder.register(null, new CapabilityInfo.Item<>(this, Capabilities.ItemHandler.ITEM, (stack, ignored) -> new StackItemHandler(this.inventorySize, stack))); } } diff --git a/src/main/java/org/moddingx/libx/base/MenuBlock.java b/src/main/java/org/moddingx/libx/base/MenuBlock.java index b51d2cd8..5700e198 100644 --- a/src/main/java/org/moddingx/libx/base/MenuBlock.java +++ b/src/main/java/org/moddingx/libx/base/MenuBlock.java @@ -2,19 +2,18 @@ import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.menu.BlockMenu; +import org.moddingx.libx.menu.type.AdvancedMenuType; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.RegistrationContext; @@ -34,13 +33,13 @@ */ public class MenuBlock extends BlockBase { - public final MenuType menu; + public final AdvancedMenuType menu; - public MenuBlock(ModX mod, MenuType menu, Properties properties) { + public MenuBlock(ModX mod, AdvancedMenuType menu, Properties properties) { this(mod, menu, properties, new Item.Properties()); } - public MenuBlock(ModX mod, MenuType menu, Properties properties, @Nullable Item.Properties itemProperties) { + public MenuBlock(ModX mod, AdvancedMenuType menu, Properties properties, @Nullable Item.Properties itemProperties) { super(mod, properties, itemProperties); this.menu = menu; } @@ -52,19 +51,12 @@ public void registerAdditional(RegistrationContext ctx, Registerable.EntryCollec builder.register(Registries.MENU, this.menu); } - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { - super.initTracking(ctx, builder); - builder.track(ForgeRegistries.MENU_TYPES, MenuBlock.class.getDeclaredField("menu")); - } - @Nonnull @Override - @SuppressWarnings("deprecation") - public InteractionResult use(@Nonnull BlockState state, @Nonnull Level level, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult hit) { - if (!level.isClientSide && player instanceof ServerPlayer sp) { - BlockMenu.openMenu(sp, this.menu, Component.translatable("screen." + MenuBlock.this.mod.modid + "." + Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(MenuBlock.this)).getPath()), pos); + public InteractionResult useWithoutItem(@Nonnull BlockState state, @Nonnull Level level, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull BlockHitResult hit) { + if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) { + Component title = Component.translatable("screen." + this.mod.modid + "." + Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(this)).getPath()); + this.menu.open(serverPlayer, title, pos); } return InteractionResult.SUCCESS; } diff --git a/src/main/java/org/moddingx/libx/base/decoration/DecoratedBlock.java b/src/main/java/org/moddingx/libx/base/decoration/DecoratedBlock.java index 6e3dc78d..a9f72894 100644 --- a/src/main/java/org/moddingx/libx/base/decoration/DecoratedBlock.java +++ b/src/main/java/org/moddingx/libx/base/decoration/DecoratedBlock.java @@ -1,6 +1,9 @@ package org.moddingx.libx.base.decoration; +import net.minecraft.core.BlockPos; import net.minecraft.world.item.Item; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; import org.moddingx.libx.base.BlockBase; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.registration.Registerable; @@ -45,7 +48,7 @@ public void registerAdditional(RegistrationContext ctx, Registerable.EntryCollec } @Override - public void registerCommon(SetupContext ctx) { + public void setupCommon(SetupContext ctx) { this.init(ctx); //noinspection DataFlowIssue ctx.enqueue(this.materialProperties::register); @@ -95,4 +98,9 @@ public T get(DecorationType type) { throw new NoSuchElementException("Decoration context " + this.context + " has no element of type " + type.name() + ": " + type); } } + + @Override // Widen visibility + public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { + return super.getLightBlock(state, level, pos); + } } diff --git a/src/main/java/org/moddingx/libx/base/decoration/DecorationContext.java b/src/main/java/org/moddingx/libx/base/decoration/DecorationContext.java index ba836c38..8d1505f5 100644 --- a/src/main/java/org/moddingx/libx/base/decoration/DecorationContext.java +++ b/src/main/java/org/moddingx/libx/base/decoration/DecorationContext.java @@ -28,13 +28,13 @@ public class DecorationContext { * Decoration context for wood. Registers {@link DecorationType#SLAB slabs}, * {@link DecorationType#STAIRS stairs}, {@link DecorationType#FENCE fences}, * {@link DecorationType#FENCE_GATE fence gates}, {@link DecorationType#WOOD_BUTTON buttons}, - * {@link DecorationType#WOOD_PRESSURE_PLATE pressure plates}, {@link DecorationType#DOOR doors}, + * {@link DecorationType#PRESSURE_PLATE pressure plates}, {@link DecorationType#DOOR doors}, * {@link DecorationType#TRAPDOOR trapdoors}, {@link DecorationType#SIGN signs} and * {@link DecorationType#HANGING_SIGN hanging signs}. */ public static final DecorationContext WOOD = new DecorationContext("wood", DecorationMaterial.WOOD, DecorationType.BASE, DecorationType.SLAB, DecorationType.STAIRS, DecorationType.FENCE, - DecorationType.FENCE_GATE, DecorationType.WOOD_BUTTON, DecorationType.WOOD_PRESSURE_PLATE, + DecorationType.FENCE_GATE, DecorationType.WOOD_BUTTON, DecorationType.PRESSURE_PLATE, DecorationType.DOOR, DecorationType.TRAPDOOR, DecorationType.SIGN, DecorationType.HANGING_SIGN ); @@ -44,25 +44,25 @@ public class DecorationContext { * {@link DecorationType#STRIPPED_WOOD stripped wood blocks}, {@link DecorationType#SLAB slabs}, * {@link DecorationType#STAIRS stairs}, {@link DecorationType#FENCE fences}, * {@link DecorationType#FENCE_GATE fence gates}, {@link DecorationType#WOOD_BUTTON buttons}, - * {@link DecorationType#WOOD_PRESSURE_PLATE pressure plates}, {@link DecorationType#DOOR doors}, + * {@link DecorationType#PRESSURE_PLATE pressure plates}, {@link DecorationType#DOOR doors}, * {@link DecorationType#TRAPDOOR trapdoors}, {@link DecorationType#SIGN signs} and * {@link DecorationType#HANGING_SIGN hanging signs}. */ public static final DecorationContext PLANKS = new DecorationContext("planks", DecorationMaterial.WOOD, DecorationType.BASE, DecorationType.LOG, DecorationType.STRIPPED_LOG, DecorationType.WOOD, DecorationType.STRIPPED_WOOD, DecorationType.SLAB, DecorationType.STAIRS, DecorationType.FENCE, - DecorationType.FENCE_GATE, DecorationType.WOOD_BUTTON, DecorationType.WOOD_PRESSURE_PLATE, + DecorationType.FENCE_GATE, DecorationType.WOOD_BUTTON, DecorationType.PRESSURE_PLATE, DecorationType.DOOR, DecorationType.TRAPDOOR, DecorationType.SIGN, DecorationType.HANGING_SIGN ); /** * Decoration context for stone blocks. Registers {@link DecorationType#SLAB slabs}, * {@link DecorationType#STAIRS stairs}, {@link DecorationType#WALL walls}, - * {@link DecorationType#STONE_BUTTON buttons} and {@link DecorationType#STONE_PRESSURE_PLATE pressure plates}. + * {@link DecorationType#STONE_BUTTON buttons} and {@link DecorationType#PRESSURE_PLATE pressure plates}. */ public static final DecorationContext STONE = new DecorationContext("stone", DecorationMaterial.STONE, DecorationType.BASE, DecorationType.SLAB, DecorationType.STAIRS, DecorationType.WALL, - DecorationType.STONE_BUTTON, DecorationType.STONE_PRESSURE_PLATE + DecorationType.STONE_BUTTON, DecorationType.PRESSURE_PLATE ); private final String name; diff --git a/src/main/java/org/moddingx/libx/base/decoration/DecorationMaterial.java b/src/main/java/org/moddingx/libx/base/decoration/DecorationMaterial.java index dde9790f..c3e45436 100644 --- a/src/main/java/org/moddingx/libx/base/decoration/DecorationMaterial.java +++ b/src/main/java/org/moddingx/libx/base/decoration/DecorationMaterial.java @@ -22,6 +22,11 @@ public interface DecorationMaterial { */ DecorationMaterial WOOD = BaseMaterial.WOOD; + /** + * A material for nether wood blocks that adds a {@link BlockSetType} and a {@link WoodType}. + */ + DecorationMaterial NETHER_WOOD = BaseMaterial.NETHER_WOOD; + /** * A material for stone blocks that adds a {@link BlockSetType}. */ @@ -30,7 +35,12 @@ public interface DecorationMaterial { /** * A material for metal blocks that adds a {@link BlockSetType}. */ - DecorationMaterial METAL = BaseMaterial.METAL; + DecorationMaterial IRON = BaseMaterial.IRON; + + /** + * A material for copper blocks that adds a {@link BlockSetType}. + */ + DecorationMaterial COPPER = BaseMaterial.COPPER; /** * Gets whether the block is a wood block. diff --git a/src/main/java/org/moddingx/libx/base/decoration/DecorationType.java b/src/main/java/org/moddingx/libx/base/decoration/DecorationType.java index 26533181..b8896294 100644 --- a/src/main/java/org/moddingx/libx/base/decoration/DecorationType.java +++ b/src/main/java/org/moddingx/libx/base/decoration/DecorationType.java @@ -39,8 +39,7 @@ public interface DecorationType { DecorationType FENCE_GATE = DecorationTypes.FENCE_GATE; DecorationType WOOD_BUTTON = DecorationTypes.WOOD_BUTTON; DecorationType STONE_BUTTON = DecorationTypes.STONE_BUTTON; - DecorationType WOOD_PRESSURE_PLATE = DecorationTypes.WOOD_PRESSURE_PLATE; - DecorationType STONE_PRESSURE_PLATE = DecorationTypes.STONE_PRESSURE_PLATE; + DecorationType PRESSURE_PLATE = DecorationTypes.PRESSURE_PLATE; DecorationType DOOR = DecorationTypes.DOOR; DecorationType TRAPDOOR = DecorationTypes.TRAPDOOR; DecorationType SIGN = DecorationTypes.SIGN; diff --git a/src/main/java/org/moddingx/libx/base/tile/BlockBE.java b/src/main/java/org/moddingx/libx/base/tile/BlockBE.java index 2de5c709..8dd0dfcc 100644 --- a/src/main/java/org/moddingx/libx/base/tile/BlockBE.java +++ b/src/main/java/org/moddingx/libx/base/tile/BlockBE.java @@ -1,6 +1,7 @@ package org.moddingx.libx.base.tile; import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.item.ItemEntity; @@ -17,9 +18,8 @@ import net.minecraft.world.level.gameevent.GameEventListener; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandlerModifiable; import org.moddingx.libx.base.BlockBase; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.mod.ModXRegistration; @@ -84,13 +84,6 @@ public void registerAdditional(RegistrationContext ctx, EntryCollector builder) builder.register(Registries.BLOCK_ENTITY_TYPE, this.beType); } - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { - super.initTracking(ctx, builder); - builder.track(ForgeRegistries.BLOCK_ENTITY_TYPES, BlockBE.class.getDeclaredField("beType")); - } - @Nullable @Override public BlockEntity newBlockEntity(@Nonnull BlockPos pos, @Nonnull BlockState state) { @@ -134,7 +127,7 @@ public int getListenerRadius() { } @Override - public boolean handleGameEvent(@Nonnull ServerLevel level, @Nonnull GameEvent gameEvent, @Nonnull GameEvent.Context context, @Nonnull Vec3 pos) { + public boolean handleGameEvent(@Nonnull ServerLevel level, @Nonnull Holder gameEvent, @Nonnull GameEvent.Context context, @Nonnull Vec3 pos) { return eventBlock.notifyGameEvent(level, gameEvent, context, pos); } @@ -150,23 +143,20 @@ public DeliveryMode getDeliveryMode() { } @Override - @SuppressWarnings("deprecation") public void onRemove(@Nonnull BlockState state, @Nonnull Level level, @Nonnull BlockPos pos, @Nonnull BlockState newState, boolean isMoving) { if (!level.isClientSide && (!state.is(newState.getBlock()) || !newState.hasBlockEntity()) && this.shouldDropInventory(level, pos, state)) { BlockEntity be = level.getBlockEntity(pos); if (be != null) { - be.getCapability(ForgeCapabilities.ITEM_HANDLER, null).ifPresent(handler -> { - if (handler instanceof IItemHandlerModifiable modifiable) { - for (int i = 0; i < modifiable.getSlots(); i++) { - ItemStack stack = modifiable.getStackInSlot(i); - if (!stack.isEmpty()) { - ItemEntity entity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.1, pos.getZ() + 0.5, stack.copy()); - level.addFreshEntity(entity); - modifiable.setStackInSlot(i, ItemStack.EMPTY); - } + if (level.getCapability(Capabilities.ItemHandler.BLOCK, pos, null) instanceof IItemHandlerModifiable modifiable) { + for (int i = 0; i < modifiable.getSlots(); i++) { + ItemStack stack = modifiable.getStackInSlot(i); + if (!stack.isEmpty()) { + ItemEntity entity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.1, pos.getZ() + 0.5, stack.copy()); + level.addFreshEntity(entity); + modifiable.setStackInSlot(i, ItemStack.EMPTY); } } - }); + } } } super.onRemove(state, level, pos, newState, isMoving); diff --git a/src/main/java/org/moddingx/libx/base/tile/BlockEntityBase.java b/src/main/java/org/moddingx/libx/base/tile/BlockEntityBase.java index ba8ecec0..1d8cbf2c 100644 --- a/src/main/java/org/moddingx/libx/base/tile/BlockEntityBase.java +++ b/src/main/java/org/moddingx/libx/base/tile/BlockEntityBase.java @@ -1,55 +1,35 @@ package org.moddingx.libx.base.tile; -import com.google.common.collect.ImmutableSet; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; +import net.neoforged.neoforge.capabilities.BlockCapability; import org.moddingx.libx.LibX; import org.moddingx.libx.impl.BlockEntityUpdateQueue; -import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Set; /** * A base class for {@link BlockEntity block entities}. This provides some useful methods. */ public class BlockEntityBase extends BlockEntity { - private final Set> caps; - public BlockEntityBase(BlockEntityType type, BlockPos pos, BlockState state) { - this(type, pos, state, new Capability[0]); - } - - /** - * This constructor accepts some capabilities that this block entity will have. Just make sure that - * the class also implements the required capability types or you might crash the game. - */ - public BlockEntityBase(BlockEntityType type, BlockPos pos, BlockState state, Capability... caps) { super(type, pos, state); - this.caps = ImmutableSet.copyOf(caps); } - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (this.caps.contains(cap)) { - //noinspection unchecked - return LazyOptional.of(() -> (T) this); - } else { - return super.getCapability(cap, side); - } + @Nullable + public final T getCapability(BlockCapability capability, C context) { + if (this.level == null) return null; + return this.level.getCapability(capability, this.getBlockPos(), this.getBlockState(), this, context); } /** * If the block entity is loaded on the logical client, this will update the block entity using - * {@link #getUpdateTag()} and {@link #handleUpdateTag(CompoundTag)}. + * {@link #getUpdateTag(HolderLookup.Provider)} and {@link #handleUpdateTag(CompoundTag, HolderLookup.Provider)}. */ @Override public void onLoad() { @@ -59,10 +39,18 @@ public void onLoad() { } } + @Override + public void setChanged() { + super.setChanged(); + if (this.level != null) { + this.level.invalidateCapabilities(this.getBlockPos()); + } + } + /** * When called on the logical server, this will update the block entity to all clients that are - * tracking it using {@link #getUpdateTag()} and {@link #handleUpdateTag(CompoundTag)} at the end - * of the current tick. + * tracking it using {@link #getUpdateTag(HolderLookup.Provider)} and + * {@link #handleUpdateTag(CompoundTag, HolderLookup.Provider)} at the end of the current tick. */ public void setDispatchable() { if (this.level != null && !this.level.isClientSide) { diff --git a/src/main/java/org/moddingx/libx/base/tile/GameEventBlock.java b/src/main/java/org/moddingx/libx/base/tile/GameEventBlock.java index 07b49dfa..353c248d 100644 --- a/src/main/java/org/moddingx/libx/base/tile/GameEventBlock.java +++ b/src/main/java/org/moddingx/libx/base/tile/GameEventBlock.java @@ -1,5 +1,6 @@ package org.moddingx.libx.base.tile; +import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.gameevent.GameEvent; @@ -24,7 +25,7 @@ default int gameEventRange() { * * @return {@code true} to indicate the event was handled, {@code false} otherwise. */ - boolean notifyGameEvent(ServerLevel level, GameEvent message, GameEvent.Context context, Vec3 pos); + boolean notifyGameEvent(ServerLevel level, Holder message, GameEvent.Context context, Vec3 pos); /** * Gets the delivery mode for this game event listener. diff --git a/src/main/java/org/moddingx/libx/base/tile/MenuBlockBE.java b/src/main/java/org/moddingx/libx/base/tile/MenuBlockBE.java index 5a3c7c32..20a2322c 100644 --- a/src/main/java/org/moddingx/libx/base/tile/MenuBlockBE.java +++ b/src/main/java/org/moddingx/libx/base/tile/MenuBlockBE.java @@ -2,13 +2,12 @@ import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -16,9 +15,8 @@ import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.menu.BlockEntityMenu; -import org.moddingx.libx.menu.BlockMenu; +import org.moddingx.libx.menu.type.AdvancedMenuType; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.RegistrationContext; @@ -38,13 +36,13 @@ */ public class MenuBlockBE> extends BlockBE { - public final MenuType menu; + public final AdvancedMenuType menu; - public MenuBlockBE(ModX mod, Class beClass, MenuType menu, BlockBehaviour.Properties properties) { + public MenuBlockBE(ModX mod, Class beClass, AdvancedMenuType menu, BlockBehaviour.Properties properties) { this(mod, beClass, menu, properties, new Item.Properties()); } - public MenuBlockBE(ModX mod, Class beClass, MenuType menu, BlockBehaviour.Properties properties, @Nullable Item.Properties itemProperties) { + public MenuBlockBE(ModX mod, Class beClass, AdvancedMenuType menu, BlockBehaviour.Properties properties, @Nullable Item.Properties itemProperties) { super(mod, beClass, properties, itemProperties); this.menu = menu; } @@ -56,20 +54,13 @@ public void registerAdditional(RegistrationContext ctx, Registerable.EntryCollec builder.register(Registries.MENU, this.menu); } - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { - super.initTracking(ctx, builder); - builder.track(ForgeRegistries.MENU_TYPES, MenuBlockBE.class.getDeclaredField("menu")); - } - @Nonnull @Override - @SuppressWarnings("deprecation") - public InteractionResult use(@Nonnull BlockState state, @Nonnull Level level, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult hit) { - if (!level.isClientSide && player instanceof ServerPlayer sp) { - BlockMenu.openMenu(sp, this.menu, Component.translatable("screen." + MenuBlockBE.this.mod.modid + "." + Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(MenuBlockBE.this)).getPath()), pos); + public InteractionResult useWithoutItem(@Nonnull BlockState state, @Nonnull Level level, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull BlockHitResult hit) { + if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) { + Component title = Component.translatable("screen." + this.mod.modid + "." + Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(this)).getPath()); + this.menu.open(serverPlayer, title, pos); } - return InteractionResult.sidedSuccess(level.isClientSide); + return InteractionResult.SUCCESS; } } diff --git a/src/main/java/org/moddingx/libx/capability/ItemCapabilities.java b/src/main/java/org/moddingx/libx/capability/ItemCapabilities.java deleted file mode 100644 index 3c5fcc3d..00000000 --- a/src/main/java/org/moddingx/libx/capability/ItemCapabilities.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.moddingx.libx.capability; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandlerModifiable; -import org.moddingx.libx.inventory.IAdvancedItemHandlerModifiable; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.function.BiPredicate; -import java.util.function.Predicate; -import java.util.function.Supplier; - -public class ItemCapabilities { - - /** - * Creates a new {@link LazyOptional} for an {@link IItemHandlerModifiable}. - */ - public static LazyOptional create(IItemHandlerModifiable handler) { - return create(() -> handler); - } - - /** - * Creates a new {@link LazyOptional} for an {@link IItemHandlerModifiable}. - * - * @param extract A predicate on whether an item can be extracted through this {@link LazyOptional}. This gets passed the slot to extract from. - * @param insert A predicate on whether an item can be inserted through this {@link LazyOptional}. This gets passed the slot to insert to and the stack that should be inserted.. - */ - public static LazyOptional create(IItemHandlerModifiable handler, @Nullable Predicate extract, @Nullable BiPredicate insert) { - return create(() -> handler, extract, insert); - } - - /** - * Creates a new {@link LazyOptional} for an {@link IItemHandlerModifiable}. - */ - public static LazyOptional create(Supplier handler) { - return LazyOptional.of(() -> IAdvancedItemHandlerModifiable.wrap(handler.get())); - } - - /** - * Creates a new {@link LazyOptional} for an {@link IItemHandlerModifiable}. - * - * @param extract A predicate on whether an item can be extracted through this {@link LazyOptional}. This gets passed the slot to extract from. - * @param insert A predicate on whether an item can be inserted through this {@link LazyOptional}. This gets passed the slot to insert to and the stack that should be inserted.. - */ - public static LazyOptional create(Supplier handler, @Nullable Predicate extract, @Nullable BiPredicate insert) { - return LazyOptional.of(() -> new WrappedHandler(handler.get(), extract == null ? slot -> true : extract, insert == null ? (slot, stack) -> true : insert)); - } - - private static class WrappedHandler implements IAdvancedItemHandlerModifiable { - - private final IItemHandlerModifiable handler; - private final Predicate extract; - private final BiPredicate insert; - - public WrappedHandler(IItemHandlerModifiable handler, Predicate extract, BiPredicate insert) { - this.handler = handler; - this.extract = extract; - this.insert = insert; - } - - @Override - public void setStackInSlot(int slot, @Nonnull ItemStack stack) { - this.handler.setStackInSlot(slot, stack); - } - - @Override - public int getSlots() { - return this.handler.getSlots(); - } - - @Nonnull - @Override - public ItemStack getStackInSlot(int slot) { - return this.handler.getStackInSlot(slot); - } - - @Nonnull - @Override - public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { - return this.insert.test(slot, stack) ? this.handler.insertItem(slot, stack, simulate) : stack; - } - - @Nonnull - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - return this.extract.test(slot) ? this.handler.extractItem(slot, amount, simulate) : ItemStack.EMPTY; - } - - @Override - public int getSlotLimit(int slot) { - return this.handler.getSlotLimit(slot); - } - - @Override - public boolean isItemValid(int slot, @Nonnull ItemStack stack) { - return this.insert.test(slot, stack) && this.handler.isItemValid(slot, stack); - } - } -} diff --git a/src/main/java/org/moddingx/libx/capability/SimpleProvider.java b/src/main/java/org/moddingx/libx/capability/SimpleProvider.java deleted file mode 100644 index a948de5c..00000000 --- a/src/main/java/org/moddingx/libx/capability/SimpleProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.moddingx.libx.capability; - -import net.minecraft.core.Direction; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.LazyOptional; -import org.moddingx.libx.util.lazy.LazyValue; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; -import java.util.function.Supplier; - -/** - * A simple {@link ICapabilityProvider capability provider} for a single capability that is - * lazily initialised. For all other capabilities, a parent provider will be queried. - */ -public class SimpleProvider implements ICapabilityProvider { - - @Nullable - private final ICapabilityProvider parent; - private final Capability capability; - private final LazyValue value; - - /** - * Creates a new {@link SimpleProvider} that provides the value from the given supplier for - * the given capability. The supplier will only be invoked once. - */ - public SimpleProvider(Capability capability, Supplier value) { - this(null, capability, value); - } - - /** - * Creates a new {@link SimpleProvider} that provides the given value for the given capability. - */ - public SimpleProvider(Capability capability, LazyValue value) { - this(null, capability, value); - } - - /** - * Creates a new {@link SimpleProvider} that provides the value from the given supplier for - * the given capability. The supplier will only be invoked once. - * - * @param parent The parent provider used for other capabilities. - */ - public SimpleProvider(@Nullable ICapabilityProvider parent, Capability capability, Supplier value) { - this(parent, capability, new LazyValue<>(value)); - } - - /** - * Creates a new {@link SimpleProvider} that provides the given value for the given capability. - * - * @param parent The parent provider used for other capabilities. - */ - public SimpleProvider(@Nullable ICapabilityProvider parent, Capability capability, LazyValue value) { - this.parent = parent; - this.capability = capability; - this.value = value; - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (this.capability == cap) { - return LazyOptional.of(() -> Objects.requireNonNull(this.value.get())).cast(); - } else { - return this.parent != null ? this.parent.getCapability(cap, side) : LazyOptional.empty(); - } - } -} diff --git a/src/main/java/org/moddingx/libx/codec/CodecHelper.java b/src/main/java/org/moddingx/libx/codec/CodecHelper.java index 9254bd37..63af5ac0 100644 --- a/src/main/java/org/moddingx/libx/codec/CodecHelper.java +++ b/src/main/java/org/moddingx/libx/codec/CodecHelper.java @@ -1,11 +1,7 @@ package org.moddingx.libx.codec; -import com.google.gson.JsonElement; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; -import com.mojang.serialization.JsonOps; -import net.minecraft.nbt.NbtOps; -import net.minecraft.nbt.Tag; import javax.annotation.Nullable; import java.util.concurrent.Callable; @@ -16,16 +12,6 @@ */ public class CodecHelper { - /** - * {@link CodecOps} for {@link JsonOps json}. - */ - public static final CodecOps JSON = new CodecOps<>(JsonElement.class, JsonOps.INSTANCE); - - /** - * {@link CodecOps} for {@link NbtOps nbt}. - */ - public static final CodecOps NBT = new CodecOps<>(Tag.class, NbtOps.INSTANCE); - /** * Wraps a value into a {@link DataResult}. If the value is non-{@code null}, the result will be * successful and contain the value. If the value is {@code null}, the result will be a failure diff --git a/src/main/java/org/moddingx/libx/codec/CodecOps.java b/src/main/java/org/moddingx/libx/codec/CodecOps.java deleted file mode 100644 index 0bc10dbd..00000000 --- a/src/main/java/org/moddingx/libx/codec/CodecOps.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.moddingx.libx.codec; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.JsonOps; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.RegistryAccess; -import net.minecraft.nbt.NbtOps; -import net.minecraft.resources.RegistryOps; - -/** - * Provides some utility methods to encode and decode thing using a codec for a - * specific {@link DynamicOps}. - * - * {@link CodecOps} for {@link JsonOps json} and {@link NbtOps nbt} can be found in {@link CodecHelper}. - */ -public class CodecOps { - - private final Class baseClass; - private final DynamicOps ops; - - /** - * Creates new {@link CodecOps}. - * - * @param baseClass The base value class of the {@link DynamicOps} to use. - * @param ops The base {@link DynamicOps} to use. - */ - public CodecOps(Class baseClass, DynamicOps ops) { - this.baseClass = baseClass; - this.ops = ops; - } - - /** - * Writes an element using a code. - */ - public E write(Codec codec, T value) { - return this.write(codec, value, this.baseClass); - } - - /** - * Writes an element using a code. - * - * @param registries The {@link RegistryAccess} to provide for registry - * aware codecs. - */ - public E write(Codec codec, T value, HolderLookup.Provider registries) { - return this.write(codec, value, this.baseClass, registries); - } - - /** - * Writes an element using a code. - * - * @param resultType The class that the result is expected to have. It is ensured, - * that the result is of this class. If the codec produces data - * of another class, an exception will be thrown. - */ - public R write(Codec codec, T value, Class resultType) { - return encodeWith(codec, value, this.ops, this.baseClass, resultType); - } - - /** - * Writes an element using a code. - * - * @param resultType The class that the result is expected to have. It is ensured, - * that the result is of this class. If the codec produces data - * of another class, an exception will be thrown. - * @param registries The {@link RegistryAccess} to provide for registry - * aware codecs. - */ - public R write(Codec codec, T value, Class resultType, HolderLookup.Provider registries) { - return encodeWith(codec, value, RegistryOps.create(this.ops, registries), this.baseClass, resultType); - } - - /** - * Reads a value using a codec. - */ - public T read(Codec codec, E value) { - return decodeWith(codec, value, this.ops); - } - - /** - * Reads a value using a codec. - * - * @param registries The {@link RegistryAccess} to provide for registry aware codecs. - */ - public T read(Codec codec, E value, HolderLookup.Provider registries) { - return decodeWith(codec, value, RegistryOps.create(this.ops, registries)); - } - - private static R encodeWith(Codec codec, T value, DynamicOps ops, Class baseClass, Class resultType) { - return codec.encodeStart(ops, value).flatMap(result -> { - if (resultType == baseClass || resultType.isAssignableFrom(result.getClass())) { - //noinspection unchecked - return DataResult.success((R) result); - } else { - return DataResult.error(() -> "Invalid type while encoding with value " + value + " with " + codec + ": Expected " + resultType + ", got " + result.getClass()); - } - }).getOrThrow(false, msg -> {}); - } - - private static T decodeWith(Codec codec, E value, DynamicOps ops) { - return codec.decode(ops, value).map(Pair::getFirst).getOrThrow(false, msg -> {}); - } -} diff --git a/src/main/java/org/moddingx/libx/codec/MoreCodecs.java b/src/main/java/org/moddingx/libx/codec/MoreCodecs.java index 7add09bd..e347419f 100644 --- a/src/main/java/org/moddingx/libx/codec/MoreCodecs.java +++ b/src/main/java/org/moddingx/libx/codec/MoreCodecs.java @@ -1,16 +1,9 @@ package org.moddingx.libx.codec; -import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.*; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.nbt.TagParser; import net.minecraft.util.Unit; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.crafting.CraftingHelper; -import org.moddingx.libx.crafting.RecipeHelper; import org.moddingx.libx.impl.codec.*; import java.util.ArrayList; @@ -27,7 +20,7 @@ public class MoreCodecs { /** - * A codec for the {@link Unit} constant that encodes to nothing. + * A streamCodec for the {@link Unit} constant that encodes to nothing. */ public static final Codec UNIT = new Codec<>() { @@ -43,42 +36,28 @@ public DataResult> decode(DynamicOps ops, T input) { }; /** - * A {@link Codec} for {@link ItemStack item stacks} that will encode the stack as NBT when using - * NBT dynamic ops, as recipe JSON when using JSON dynamic ops and as a string containing the NBT tag - * if using some other dynamic ops. - */ - public static final Codec SAFE_ITEM_STACK = typeMapped( - Codec.STRING.flatXmap( - str -> CodecHelper.doesNotThrow(() -> ItemStack.of(TagParser.parseTag(str))), - stack -> CodecHelper.doesNotThrow(() -> stack.save(new CompoundTag()).toString()) - ), - TypedEncoder.of(Tag.class, stack -> stack.save(new CompoundTag()), tag -> ItemStack.of((CompoundTag) tag)), - TypedEncoder.of(JsonElement.class, stack -> RecipeHelper.serializeItemStack(stack, true), json -> CraftingHelper.getItemStack(json.getAsJsonObject(), true)) - ); - - /** - * Gets a codec that always errors with the given message. + * Gets a streamCodec that always errors with the given message. */ public static Codec error(String msg) { return error(msg, msg); } /** - * Gets a codec that always errors with the given messages. + * Gets a streamCodec that always errors with the given messages. */ public static Codec error(String encodeMsg, String decodeMsg) { return new ErrorCodec<>(encodeMsg, decodeMsg); } /** - * Gets a codec that encodes an {@link Optional} with a given child codec. + * Gets a streamCodec that encodes an {@link Optional} with a given child streamCodec. */ public static Codec> option(Codec codec) { return new OptionCodec<>(codec); } /** - * Creates a fixed codec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. + * Creates a fixed streamCodec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. * Decoding fille succeed if the serialized value equals the given value, otherwise it fails. Fixed codecs are * useful in {@link Codec#either(Codec, Codec) either}-codecs. */ @@ -87,7 +66,7 @@ public static Codec fixed(Number value) { } /** - * Creates a fixed codec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. + * Creates a fixed streamCodec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. * Decoding fille succeed if the serialized value equals the given value, otherwise it fails. Fixed codecs are * useful in {@link Codec#either(Codec, Codec) either}-codecs. */ @@ -96,8 +75,8 @@ public static Codec fixed(String value) { } /** - * Creates a fixed codec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. - * Decoding fille succeed if the serialized value equals the given value, otherwise it fails. Fixed codecs are + * Creates a fixed streamCodec that always encodes the {@link Unit#INSTANCE unit value} to the given serialized value. + * Decoding will succeed if the serialized value equals the given value, otherwise it fails. Fixed codecs are * useful in {@link Codec#either(Codec, Codec) either}-codecs. */ public static Codec fixed(Dynamic value) { @@ -105,7 +84,7 @@ public static Codec fixed(Dynamic value) { } /** - * Gets a codec that encodes an {@link Enum enum} as a string. + * Gets a streamCodec that encodes an {@link Enum enum} as a string. */ public static > Codec enumCodec(Class clazz) { return EnumCodec.get(clazz); @@ -113,7 +92,7 @@ public static > Codec enumCodec(Class clazz) { /** * Extends the give {@link Codec} with some new fields defined by the given {@link MapCodec}. The given - * codec must encode to a {@link MapLike}. + * streamCodec must encode to a {@link MapLike}. */ public static Codec> extend(Codec codec, MapCodec extension) { return extend(codec, extension, Function.identity(), Pair::of); @@ -121,20 +100,20 @@ public static Codec> extend(Codec codec, MapCodec extens /** * Extends the give {@link Codec} with some new fields defined by the given {@link MapCodec}. The given - * codec must encode to a {@link MapLike}. + * streamCodec must encode to a {@link MapLike}. */ public static Codec extend(Codec codec, MapCodec extension, Function> decompose, BiFunction construct) { return mapDispatch(extension, key -> DataResult.success(codec), decompose.andThen(Pair::swap), (e, m) -> DataResult.success(construct.apply(m, e))); } /** - * Creates a map dispatched codec. When encoding an element, it ist first decomposed into key and value. - * The key is used to obtain a codec to encode the value using the passed {@code valueCodecs} function. + * Creates a map dispatched streamCodec. When encoding an element, it ist first decomposed into key and value. + * The key is used to obtain a streamCodec to encode the value using the passed {@code valueCodecs} function. * The {@link Codec} returned from that function must encode to a {@link MapLike}. - * After that, the key is encoded and merged into the {@link MapLike} from the value codec. + * After that, the key is encoded and merged into the {@link MapLike} from the value streamCodec. * * Decoding works the other way round in that the key is read first. Then the {@code valueCodecs} function - * is used to obtain a {@link Codec} to decode the value. In the end, the codec uses both key and value to + * is used to obtain a {@link Codec} to decode the value. In the end, the streamCodec uses both key and value to * construct the resulting element. Both the {@link MapCodec} and the codecs returned from {@code valueCodecs} * must be able to work with additional values, they don't know about. */ @@ -171,21 +150,21 @@ public static MapCodec optionalFieldOf(Codec codec, String name, T def } /** - * Gets a type mapped codec that will try to encode and decode values with the first + * Gets a type mapped streamCodec that will try to encode and decode values with the first * matching {@link TypedEncoder}. * If no {@link TypedEncoder} matches, an error will be returned. */ @SafeVarargs @SuppressWarnings({"ManualArrayToCollectionCopy", "UseBulkOperation"}) public static Codec typeMapped(TypedEncoder... encoders) { - if (encoders.length == 0) return error("Empty type mapped codec"); + if (encoders.length == 0) return error("Empty type mapped streamCodec"); List> list = new ArrayList<>(); for (TypedEncoder encoder : encoders) list.add(encoder); return new TypeMappedCodec<>(list, null); } /** - * Gets a type mapped codec that will try to encode and decode values with the first + * Gets a type mapped streamCodec that will try to encode and decode values with the first * matching {@link TypedEncoder}. * If no {@link TypedEncoder} matches, the fallback is used. */ diff --git a/src/main/java/org/moddingx/libx/codec/MoreStreamCodecs.java b/src/main/java/org/moddingx/libx/codec/MoreStreamCodecs.java new file mode 100644 index 00000000..14c82662 --- /dev/null +++ b/src/main/java/org/moddingx/libx/codec/MoreStreamCodecs.java @@ -0,0 +1,121 @@ +package org.moddingx.libx.codec; + +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.EndTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.VarInt; +import net.minecraft.network.codec.StreamCodec; + +import javax.annotation.Nonnull; +import java.util.*; +import java.util.function.Supplier; + +/** + * Provides additional {@link StreamCodec stream codecs}. + */ +public class MoreStreamCodecs { + + /** + * A {@link StreamCodec stream streamCodec} for NBT tags. + */ + public static final StreamCodec TAG = StreamCodec.of( + FriendlyByteBuf::writeNbt, + buf -> Objects.requireNonNullElse(FriendlyByteBuf.readNbt(buf, NbtAccounter.create(2097152L)), EndTag.INSTANCE) + ); + + /** + * A {@link StreamCodec stream streamCodec} for NBT compound tags. + */ + public static final StreamCodec COMPOUND_TAG = StreamCodec.of( + FriendlyByteBuf::writeNbt, + buf -> Objects.requireNonNull(FriendlyByteBuf.readNbt(buf), "Not a compound tag.") + ); + + /** + * Creates a unit {@link StreamCodec}. The returned codec will never write any bytes and always use the + * provided {@link Supplier} to produce a result value. It ignores its input while encoding. + */ + public static StreamCodec unit(Supplier value) { + return new StreamCodec<>() { + + @Override + public void encode(@Nonnull B buffer, @Nonnull T value) {} + + @Nonnull + @Override + public T decode(@Nonnull B buffer) { + return value.get(); + } + }; + } + + public static StreamCodec> maybe(StreamCodec elementCodec) { + return new StreamCodec<>() { + + @Override + public void encode(@Nonnull B buffer, @Nonnull Optional value) { + buffer.writeBoolean(value.isPresent()); + value.ifPresent(element -> elementCodec.encode(buffer, element)); + } + + @Nonnull + @Override + public Optional decode(@Nonnull B buffer) { + boolean present = buffer.readBoolean(); + return present ? Optional.of(elementCodec.decode(buffer)) : Optional.empty(); + } + }; + } + + public static StreamCodec> listOf(StreamCodec elementCodec) { + return new StreamCodec<>() { + + @Override + public void encode(@Nonnull B buffer, @Nonnull List value) { + VarInt.write(buffer, value.size()); + for (T element : value) elementCodec.encode(buffer, element); + } + + @Nonnull + @Override + public List decode(@Nonnull B buffer) { + int size = VarInt.read(buffer); + ArrayList list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(elementCodec.decode(buffer)); + } + return Collections.unmodifiableList(list); + } + }; + } + + public static StreamCodec> mapOf(StreamCodec keyCodec, StreamCodec valueCodec) { + return new StreamCodec<>() { + + @Override + public void encode(@Nonnull B buffer, @Nonnull Map value) { + VarInt.write(buffer, value.size()); + for (Map.Entry entry : value.entrySet()) { + keyCodec.encode(buffer, entry.getKey()); + valueCodec.encode(buffer, entry.getValue()); + } + } + + @Nonnull + @Override + public Map decode(@Nonnull B buffer) { + int size = VarInt.read(buffer); + HashMap map = new HashMap<>(size); + for (int i = 0; i < size; i++) { + K key = keyCodec.decode(buffer); + V value = valueCodec.decode(buffer); + map.put(key, value); + } + return Collections.unmodifiableMap(map); + } + }; + } +} diff --git a/src/main/java/org/moddingx/libx/command/EnumArgument2.java b/src/main/java/org/moddingx/libx/command/EnumArgumentIgnoreCase.java similarity index 83% rename from src/main/java/org/moddingx/libx/command/EnumArgument2.java rename to src/main/java/org/moddingx/libx/command/EnumArgumentIgnoreCase.java index 0decdbe3..35510d81 100644 --- a/src/main/java/org/moddingx/libx/command/EnumArgument2.java +++ b/src/main/java/org/moddingx/libx/command/EnumArgumentIgnoreCase.java @@ -14,7 +14,7 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.util.Unit; -import net.minecraftforge.server.command.EnumArgument; +import net.neoforged.neoforge.server.command.EnumArgument; import org.moddingx.libx.LibX; import javax.annotation.Nonnull; @@ -25,23 +25,21 @@ import java.util.stream.Stream; /** - * As the {@link EnumArgument} is sometimes a bit buggy because when the entered value is - * lowercase but the actual enum value is uppercase and it also does not sync properly, here's - * a variant that solves these issues. + * A case insensitive version of {@link EnumArgument}. */ -public class EnumArgument2> implements ArgumentType { +public class EnumArgumentIgnoreCase> implements ArgumentType { /** * Creates a new enum argument for the given enum class. */ - public static > EnumArgument2 enumArgument(Class enumClass) { - return new EnumArgument2<>(enumClass); + public static > EnumArgumentIgnoreCase enumArgument(Class enumClass) { + return new EnumArgumentIgnoreCase<>(enumClass); } private final Class enumClass; private final DynamicCommandExceptionType invalidValue; - private EnumArgument2(final Class enumClass) { + private EnumArgumentIgnoreCase(final Class enumClass) { if (!enumClass.isEnum()) { throw new IllegalArgumentException("Can't create enum argument for non-enum class."); } @@ -71,7 +69,7 @@ public Collection getExamples() { } @SuppressWarnings({"rawtypes", "unchecked"}) - public static class Info implements ArgumentTypeInfo, Info.Template> { + public static class Info implements ArgumentTypeInfo, Info.Template> { public static final Info INSTANCE = new Info(); @@ -109,11 +107,11 @@ public void serializeToJson(@Nonnull Template template, @Nonnull JsonObject json @Nonnull @Override - public Template unpack(@Nonnull EnumArgument2 arg) { + public Template unpack(@Nonnull EnumArgumentIgnoreCase arg) { return new Template(arg.enumClass); } - public class Template implements ArgumentTypeInfo.Template> { + public class Template implements ArgumentTypeInfo.Template> { final Class> enumClass; @@ -124,13 +122,13 @@ private Template(Class> enumClass) { @Nonnull @Override @SuppressWarnings({"unchecked", "rawtypes"}) - public EnumArgument2 instantiate(@Nonnull CommandBuildContext ctx) { - return new EnumArgument2<>((Class) this.enumClass); + public EnumArgumentIgnoreCase instantiate(@Nonnull CommandBuildContext ctx) { + return new EnumArgumentIgnoreCase<>((Class) this.enumClass); } @Nonnull @Override - public ArgumentTypeInfo, ?> type() { + public ArgumentTypeInfo, ?> type() { return Info.this; } } diff --git a/src/main/java/org/moddingx/libx/config/ConfigManager.java b/src/main/java/org/moddingx/libx/config/ConfigManager.java index 2e221f73..e3d5d265 100644 --- a/src/main/java/org/moddingx/libx/config/ConfigManager.java +++ b/src/main/java/org/moddingx/libx/config/ConfigManager.java @@ -6,14 +6,14 @@ import com.google.gson.JsonParseException; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.loading.FMLEnvironment; -import net.minecraftforge.fml.loading.FMLPaths; -import net.minecraftforge.network.PacketDistributor; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.network.PacketDistributor; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.moddingx.libx.LibX; @@ -22,12 +22,11 @@ import org.moddingx.libx.config.mapper.ValueMapper; import org.moddingx.libx.config.validate.DoubleRange; import org.moddingx.libx.config.validator.ConfigValidator; -import org.moddingx.libx.crafting.IngredientStack; import org.moddingx.libx.event.ConfigLoadedEvent; import org.moddingx.libx.impl.config.ConfigImpl; import org.moddingx.libx.impl.config.ConfigState; import org.moddingx.libx.impl.config.ModMappers; -import org.moddingx.libx.impl.network.ConfigShadowMessage; +import org.moddingx.libx.impl.network.ConfigShadowHandler; import org.moddingx.libx.impl.network.NetworkImpl; import org.moddingx.libx.util.data.ResourceList; @@ -38,11 +37,10 @@ /** * Provides a config system for configuration files that is meant to be more easy and powerful than - * the system by forge based on {@link com.electronwill.nightconfig NightConfig}. This system creates - * json files with comments based on a class. That class may contain fields with {@link Config @Config} - * annotations. Each field with a config annotation will get one value in the config file. To create sub - * groups, you can create static nested classes inside the base class. Suppose you have the following - * class structure: + * the system by neoforge based on NightConfig. This system creates json files with comments based on a + * class. That class may contain fields with {@link Config @Config} annotations. Each field with a config + * annotation will get one value in the config file. To create sub groups, you can create static nested + * classes inside the base class. Suppose you have the following class structure: * *
  * 
@@ -118,8 +116,6 @@
  *     
  • {@link Set Set<?>}
  • *
  • {@link Map Map<String, ?>}
  • *
  • {@link ResourceLocation}
  • - *
  • {@link Ingredient}
  • - *
  • {@link IngredientStack}
  • *
  • {@link Component}
  • *
  • {@link ResourceList}
  • *
  • {@link UUID UUID}
  • @@ -198,7 +194,7 @@ public static void registerConfigValidator(String modid, ConfigValidator v * @param clientConfig Whether this is a client config. */ public static void registerConfig(String modid, Class configClass, boolean clientConfig) { - registerConfig(new ResourceLocation(modid, "config"), configClass, clientConfig); + registerConfig(ResourceLocation.fromNamespaceAndPath(modid, "config"), configClass, clientConfig); } /** @@ -224,7 +220,7 @@ public static void registerConfig(ResourceLocation location, Class configClas } /** - * Forces reload of all common configs. This will not sync the config though. Use {@link #forceResync(ServerPlayer)} for this. + * Forces reload of all common configs. This will not sync the config though. Use {@link #synchronize(ServerPlayer)} for this. */ public static void reloadCommon() { for (Class configClass : configs.keySet()) { @@ -236,7 +232,7 @@ public static void reloadCommon() { * Forces reload of all client configs. */ public static void reloadClient() { - if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) return; + if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) return; for (Class configClass : configs.keySet()) { reloadConfig(configClass, false, true); } @@ -248,13 +244,13 @@ private static void firstLoadConfig(Class configClass) { } try { ConfigImpl config = ConfigImpl.getConfig(configIds.inverse().get(configClass)); - if (!config.clientConfig || FMLEnvironment.dist == Dist.CLIENT) { + if (!config.clientConfig || FMLLoader.getDist() == Dist.CLIENT) { ConfigState defaultState = config.stateFromValues(); config.setDefaultState(defaultState); ConfigState state = config.readFromFileOrCreateBy(defaultState); config.saveState(state); state.apply(); - MinecraftForge.EVENT_BUS.post(new ConfigLoadedEvent(config.id, config.baseClass, ConfigLoadedEvent.LoadReason.INITIAL, config.clientConfig, config.path, config.path)); + NeoForge.EVENT_BUS.post(new ConfigLoadedEvent(config.id, config.baseClass, ConfigLoadedEvent.LoadReason.INITIAL, config.clientConfig, config.path, config.path)); } } catch (IOException | IllegalStateException | JsonParseException e) { LibX.logger.error("Failed to load config '" + configIds.inverse().get(configClass) + "' (class: " + configClass + ")", e); @@ -262,7 +258,7 @@ private static void firstLoadConfig(Class configClass) { } /** - * Forces reload of one config. This will not sync the config though. Use {@link #forceResync(ServerPlayer, Class)} for this. + * Forces reload of one config. This will not sync the config though. Use {@link #synchronize(ServerPlayer, Class)} for this. */ public static void reloadConfig(Class configClass) { reloadConfig(configClass, true, true); @@ -276,14 +272,14 @@ private static void reloadConfig(Class configClass, boolean allowCommon, bool try { ConfigImpl config = ConfigImpl.getConfig(configIds.inverse().get(configClass)); if (config.clientConfig ? allowClient : allowCommon) { - if (!config.clientConfig || FMLEnvironment.dist == Dist.CLIENT) { + if (!config.clientConfig || FMLLoader.getDist() == Dist.CLIENT) { ConfigState state = config.readFromFileOrCreateByDefault(); config.saveState(state); if (!config.isShadowed()) { state.apply(); } config.reloadClientWorldState(); - MinecraftForge.EVENT_BUS.post(new ConfigLoadedEvent(config.id, config.baseClass, ConfigLoadedEvent.LoadReason.RELOAD, config.clientConfig, config.path, config.path)); + NeoForge.EVENT_BUS.post(new ConfigLoadedEvent(config.id, config.baseClass, ConfigLoadedEvent.LoadReason.RELOAD, config.clientConfig, config.path, config.path)); } } } catch (IOException | IllegalStateException | JsonParseException e) { @@ -292,38 +288,75 @@ private static void reloadConfig(Class configClass, boolean allowCommon, bool } /** - * Forces a resync of one config to one player. + * Forces synchronisation of one config to all players. */ - public static void forceResync(@Nullable ServerPlayer player, Class configClass) { - if (!configIds.containsValue(configClass)) { - throw new IllegalArgumentException("Class " + configClass + " is not registered as a config."); - } - if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) { - ResourceLocation id = configIds.inverse().get(configClass); - ConfigImpl config = ConfigImpl.getConfig(id); - if (!config.clientConfig && NetworkImpl.getImpl().canSend()) { - PacketDistributor.PacketTarget target = player == null ? PacketDistributor.ALL.noArg() : PacketDistributor.PLAYER.with(() -> player); - NetworkImpl.getImpl().channel.send(target, new ConfigShadowMessage(config, config.cachedOrCurrent())); - } - } else { - LibX.logger.error("ConfigManager.forceResync was called on a physical client. Ignoring."); - } + public static void synchronize(MinecraftServer server, Class configClass) { + synchronize(server, null, List.of(configClass)); } /** - * Forces a resync of all configs to one player. + * Forces synchronisation of all configs to all players. */ - public static void forceResync(@Nullable ServerPlayer player) { - if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) { - for (ResourceLocation id : ConfigManager.configs()) { - ConfigImpl config = ConfigImpl.getConfig(id); - if (!config.clientConfig && NetworkImpl.getImpl().canSend()) { - PacketDistributor.PacketTarget target = player == null ? PacketDistributor.ALL.noArg() : PacketDistributor.PLAYER.with(() -> player); - NetworkImpl.getImpl().channel.send(target, new ConfigShadowMessage(config, config.cachedOrCurrent())); + public static void synchronize(MinecraftServer server) { + synchronize(server, null, null); + } + + /** + * Forces synchronisation of one config to one player. + */ + public static void synchronize(ServerPlayer player, Class configClass) { + synchronize(player.server, player, List.of(configClass)); + } + + /** + * Forces synchronisation of all configs to one player. + */ + public static void synchronize(ServerPlayer player) { + synchronize(player.server, player, null); + } + + private static void synchronize(MinecraftServer server, @Nullable ServerPlayer receiver, @Nullable List> configClasses) { + List configs = new ArrayList<>(configClasses == null ? configs().size() : configClasses.size()); + + if (configClasses != null) { + for (Class configClass : configClasses) { + if (!configIds.containsValue(configClass)) { + throw new IllegalArgumentException("Class " + configClass + " is not registered as a config."); } + ResourceLocation id = configIds.inverse().get(configClass); + ConfigImpl config = ConfigImpl.getConfig(id); + if (!config.clientConfig) configs.add(config); + } + } else { + for (ResourceLocation id : configs()) { + ConfigImpl config = ConfigImpl.getConfig(id); + if (!config.clientConfig) configs.add(config); + } + } + + if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) { + sendConfigState(server, receiver, configs); + } else { + LibX.logger.error("ConfigManager.synchronize was called on a physical client. Ignoring."); + } + } + + private static void sendConfigState(MinecraftServer server, @Nullable ServerPlayer receiver, List configs) { + if (configs.isEmpty()) return; + List messages = configs.stream().map(config -> new ConfigShadowHandler.Message(config, config.cachedOrCurrent())).toList(); + ConfigShadowHandler.Message firstMessage = messages.getFirst(); + ConfigShadowHandler.Message[] otherMessages = messages.stream().skip(1).toArray(ConfigShadowHandler.Message[]::new); + + if (receiver != null) { + if (NetworkImpl.getImpl().canSend(receiver, ConfigShadowHandler.TYPE)) { + PacketDistributor.sendToPlayer(receiver, firstMessage, otherMessages); } } else { - LibX.logger.error("ConfigManager.forceResync was called on a physical client. Ignoring."); + for (ServerPlayer player : server.getPlayerList().getPlayers()) { + if (NetworkImpl.getImpl().canSend(player, ConfigShadowHandler.TYPE)) { + PacketDistributor.sendToPlayer(player, firstMessage, otherMessages); + } + } } } diff --git a/src/main/java/org/moddingx/libx/config/gui/EditorOps.java b/src/main/java/org/moddingx/libx/config/gui/EditorOps.java index 034c011d..77e98588 100644 --- a/src/main/java/org/moddingx/libx/config/gui/EditorOps.java +++ b/src/main/java/org/moddingx/libx/config/gui/EditorOps.java @@ -24,25 +24,22 @@ default void enabled(boolean enabled) { * Wraps a {@link GuiEventListener} into matching editor ops. */ static EditorOps wrap(GuiEventListener widget) { - if (widget instanceof EditorOps ops) { - return ops; - } else if (widget instanceof EditBox base) { - return new EditorOps() { + return switch (widget) { + case EditorOps ops -> ops; + case EditBox base -> new EditorOps() { @Override public void enabled(boolean enabled) { base.setEditable(enabled); base.active = enabled; } }; - } else if (widget instanceof AbstractWidget base) { - return new EditorOps() { + case AbstractWidget base -> new EditorOps() { @Override public void enabled(boolean enabled) { base.active = enabled; } }; - } else { - return new EditorOps() {}; - } + case null, default -> new EditorOps() {}; + }; } } diff --git a/src/main/java/org/moddingx/libx/config/mapper/GenericValueMapper.java b/src/main/java/org/moddingx/libx/config/mapper/GenericValueMapper.java index 55602f0e..8dd9d646 100644 --- a/src/main/java/org/moddingx/libx/config/mapper/GenericValueMapper.java +++ b/src/main/java/org/moddingx/libx/config/mapper/GenericValueMapper.java @@ -2,8 +2,9 @@ import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.Config; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; @@ -61,17 +62,13 @@ public interface GenericValueMapper { E toJson(T value, ValueMapper mapper); /** - * @see ValueMapper#fromNetwork(FriendlyByteBuf) + * @see ValueMapper#streamCodec() */ - default T fromNetwork(FriendlyByteBuf buffer, ValueMapper mapper) { - return this.fromJson(ConfigImpl.INTERNAL.fromJson(buffer.readUtf(0x40000), this.element()), mapper); - } - - /** - * @see ValueMapper#toNetwork(Object, FriendlyByteBuf) - */ - default void toNetwork(T value, FriendlyByteBuf buffer, ValueMapper mapper) { - buffer.writeUtf(ConfigImpl.INTERNAL.toJson(this.toJson(value, mapper)), 0x40000); + default StreamCodec streamCodec(ValueMapper mapper) { + return StreamCodec.of( + (buf, value) -> buf.writeUtf(ConfigImpl.INTERNAL.toJson(this.toJson(value, mapper)), 0x40000), + buf -> this.fromJson(ConfigImpl.INTERNAL.fromJson(buf.readUtf(0x40000), this.element()), mapper) + ); } /** diff --git a/src/main/java/org/moddingx/libx/config/mapper/ValueMapper.java b/src/main/java/org/moddingx/libx/config/mapper/ValueMapper.java index 58dc6b31..f347b86e 100644 --- a/src/main/java/org/moddingx/libx/config/mapper/ValueMapper.java +++ b/src/main/java/org/moddingx/libx/config/mapper/ValueMapper.java @@ -3,8 +3,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.Config; import org.moddingx.libx.config.ConfigManager; import org.moddingx.libx.config.correct.ConfigCorrection; @@ -54,19 +55,13 @@ public interface ValueMapper { E toJson(T value); /** - * Reads a value from a {@link FriendlyByteBuf}. The default implementation expects a - * JSON string and gives this string to {@link #fromJson(JsonElement) fromJSON}. + * Gets a {@link StreamCodec} that describes, how to serialise values of this type over the network. */ - default T fromNetwork(FriendlyByteBuf buffer) { - return this.fromJson(ConfigImpl.INTERNAL.fromJson(buffer.readUtf(0x40000), this.element())); - } - - /** - * Writes a value to a {@link FriendlyByteBuf}. The default implementation calls - * {@link #toJson(Object) toJSON} and writes the resulting JSON as a string. - */ - default void toNetwork(T value, FriendlyByteBuf buffer) { - buffer.writeUtf(ConfigImpl.INTERNAL.toJson(this.toJson(value)), 0x40000); + default StreamCodec streamCodec() { + return StreamCodec.of( + (buf, value) -> buf.writeUtf(ConfigImpl.INTERNAL.toJson(this.toJson(value)), 0x40000), + buf -> this.fromJson(ConfigImpl.INTERNAL.fromJson(buf.readUtf(0x40000), this.element())) + ); } /** diff --git a/src/main/java/org/moddingx/libx/crafting/IngredientStack.java b/src/main/java/org/moddingx/libx/crafting/IngredientStack.java index 70c1ebfb..133e91da 100644 --- a/src/main/java/org/moddingx/libx/crafting/IngredientStack.java +++ b/src/main/java/org/moddingx/libx/crafting/IngredientStack.java @@ -1,7 +1,10 @@ package org.moddingx.libx.crafting; -import com.google.gson.JsonObject; -import net.minecraft.network.FriendlyByteBuf; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; @@ -13,6 +16,18 @@ public record IngredientStack(Ingredient ingredient, int count) implements Predicate { public static final IngredientStack EMPTY = new IngredientStack(Ingredient.EMPTY, 0); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Ingredient.CODEC.fieldOf("ingredient").forGetter(IngredientStack::ingredient), + Codec.INT.fieldOf("count").forGetter(IngredientStack::count) + ).apply(instance, IngredientStack::new) + ); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + Ingredient.CONTENTS_STREAM_CODEC, IngredientStack::ingredient, + ByteBufCodecs.VAR_INT, IngredientStack::count, + IngredientStack::new + ); public IngredientStack(Ingredient ingredient, int count) { if (count <= 0 || ingredient.isEmpty()) { @@ -39,41 +54,4 @@ public boolean test(ItemStack stack) { public boolean isEmpty() { return this.count == 0 || this.ingredient.isEmpty(); } - - /** - * Serialises the IngredientStack to json. - */ - public JsonObject toJson() { - JsonObject json = new JsonObject(); - json.add("Ingredient", this.ingredient.toJson()); - json.addProperty("Count", this.count); - return json; - } - - /** - * Writes this IngredientStack to a {@link FriendlyByteBuf}. - */ - public void toNetwork(FriendlyByteBuf buffer) { - buffer.writeVarInt(this.count); - this.ingredient.toNetwork(buffer); - } - - /** - * Deserializes and IngredientStack from json. - */ - public static IngredientStack fromJson(JsonObject json) { - Ingredient ingredient = json.has("Ingredient") ? Ingredient.fromJson(json.get("Ingredient")) : Ingredient.EMPTY; - int count = json.has("Count") && json.get("Count").isJsonPrimitive() ? json.get("Count").getAsInt() : 1; - - return new IngredientStack(ingredient, count); - } - - /** - * Reads an IngredientStack from a {@link FriendlyByteBuf}. - */ - public static IngredientStack fromNetwork(FriendlyByteBuf buffer) { - int count = buffer.readVarInt(); - Ingredient ingredient = Ingredient.fromNetwork(buffer); - return new IngredientStack(ingredient, count); - } } diff --git a/src/main/java/org/moddingx/libx/crafting/RecipeHelper.java b/src/main/java/org/moddingx/libx/crafting/RecipeHelper.java index 085f7b3b..69a729f4 100644 --- a/src/main/java/org/moddingx/libx/crafting/RecipeHelper.java +++ b/src/main/java/org/moddingx/libx/crafting/RecipeHelper.java @@ -1,19 +1,12 @@ package org.moddingx.libx.crafting; -import com.google.gson.JsonObject; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeManager; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.world.item.crafting.*; -import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; public class RecipeHelper { @@ -22,11 +15,10 @@ public class RecipeHelper { * * @param rm The recipe manager to use. You can get one from a world. */ - public static boolean isItemValidInput(RecipeManager rm, RecipeType recipeType, ItemStack stack) { - //noinspection unchecked - Collection> recipes = rm.byType((RecipeType>) recipeType).values(); - for (Recipe recipe : recipes) { - for (Ingredient ingredient : recipe.getIngredients()) { + public static > boolean isItemValidInput(RecipeManager rm, RecipeType recipeType, ItemStack stack) { + Collection> recipes = rm.getAllRecipesFor(recipeType); + for (RecipeHolder recipe : recipes) { + for (Ingredient ingredient : recipe.value().getIngredients()) { if (ingredient.test(stack)) { return true; } @@ -73,7 +65,7 @@ public static List stackUp(List stacks) { if (!stack.isEmpty()) { int itemsLeft = stack.getCount(); for (ItemStack used : stacked) { - if (ItemStack.isSameItemSameTags(stack, used)) { + if (ItemStack.isSameItemSameComponents(stack, used)) { int stackTransfer = Math.min(itemsLeft, used.getMaxStackSize() - used.getCount()); if (stackTransfer < 0) { stackTransfer = 0; @@ -91,34 +83,4 @@ public static List stackUp(List stacks) { } return Collections.unmodifiableList(stacked); } - - /** - * Serialises the given {@link ItemStack} to json, so it can be read back by {@link CraftingHelper#getItemStack(JsonObject, boolean)}. - */ - public static JsonObject serializeItemStack(ItemStack stack, boolean writeNBT) { - JsonObject json = new JsonObject(); - json.addProperty("item", Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(stack.getItem()), "Can't serialize ItemStack: Item has no registry name: " + stack.getItem()).toString()); - json.addProperty("count", stack.getCount()); - if (writeNBT) { - CompoundTag stackTag = stack.hasTag() ? stack.getTag() : null; - Tag capsTag = forgeCaps(stack); - if (stackTag != null || capsTag != null) { - // Need to make a copy, so the stack is not modified. - CompoundTag resultTag = stackTag == null ? new CompoundTag() : stackTag.copy(); - if (capsTag != null) resultTag.put("ForgeCaps", capsTag); - json.addProperty("nbt", resultTag.toString()); - } - } - return json; - } - - @Nullable - private static Tag forgeCaps(ItemStack stack) { - CompoundTag nbt = stack.serializeNBT(); - if (nbt.contains("ForgeCaps") && (!(nbt.get("ForgeCaps") instanceof CompoundTag cmp) || !cmp.isEmpty())) { - return nbt.get("ForgeCaps"); - } else { - return null; - } - } } diff --git a/src/main/java/org/moddingx/libx/crafting/ingredient/EffectIngredient.java b/src/main/java/org/moddingx/libx/crafting/ingredient/EffectIngredient.java index f4ec8d94..e57f4dee 100644 --- a/src/main/java/org/moddingx/libx/crafting/ingredient/EffectIngredient.java +++ b/src/main/java/org/moddingx/libx/crafting/ingredient/EffectIngredient.java @@ -1,32 +1,30 @@ package org.moddingx.libx.crafting.ingredient; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.effect.MobEffect; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.player.StackedContents; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.alchemy.Potion; -import net.minecraft.world.item.alchemy.PotionUtils; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.IIngredientSerializer; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.world.item.alchemy.PotionContents; +import net.neoforged.neoforge.common.crafting.ICustomIngredient; +import net.neoforged.neoforge.common.crafting.IngredientType; +import org.apache.commons.lang3.stream.Streams; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Stream; /** @@ -35,7 +33,27 @@ * tag will also be detected. And you can match a for example a potion of the turtle master and a potion of * slowness as both have the slowness effect. */ -public class EffectIngredient extends Ingredient { +public class EffectIngredient implements ICustomIngredient { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(ei -> Objects.requireNonNullElse(ei.potionItem, Items.AIR)), + MobEffectInstance.CODEC.listOf().fieldOf("effects").forGetter(ei -> ei.effects), + Codec.BOOL.fieldOf("allows_extra_effects").orElse(false).forGetter(ei -> ei.extraEffects), + Codec.BOOL.fieldOf("allows_higher_amplifier").orElse(true).forGetter(ei -> ei.higherAmplifier), + Codec.BOOL.fieldOf("allows_higher_duration").orElse(true).forGetter(ei -> ei.higherDuration) + ).apply(instance, EffectIngredient::new) + ); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.registry(Registries.ITEM), ei -> ei.potionItem, + ByteBufCodecs.list().apply(MobEffectInstance.STREAM_CODEC), ei -> ei.effects, + ByteBufCodecs.BOOL, ei -> ei.extraEffects, + ByteBufCodecs.BOOL, ei -> ei.higherAmplifier, + ByteBufCodecs.BOOL, ei -> ei.higherDuration, + EffectIngredient::new + ); + + public static final IngredientType TYPE = new IngredientType<>(CODEC, STREAM_CODEC); /** * The item required for the potion. Can be null t match any item. @@ -64,11 +82,11 @@ public class EffectIngredient extends Ingredient { public final boolean higherDuration; public EffectIngredient(ItemStack potionStack) { - this(potionStack.getItem(), PotionUtils.getMobEffects(potionStack), false, true, true); + this(potionStack.getItem(), getEffects(potionStack), false, true, true); } public EffectIngredient(ItemStack potionStack, boolean extraEffects, boolean higherAmplifier, boolean higherDuration) { - this(potionStack.getItem(), PotionUtils.getMobEffects(potionStack), extraEffects, higherAmplifier, higherDuration); + this(potionStack.getItem(), getEffects(potionStack), extraEffects, higherAmplifier, higherDuration); } public EffectIngredient(@Nullable Item potionItem, List effects) { @@ -76,9 +94,12 @@ public EffectIngredient(@Nullable Item potionItem, List effec } public EffectIngredient(@Nullable Item potionItem, List effects, boolean extraEffects, boolean higherAmplifier, boolean higherDuration) { - super(Stream.empty()); + this(potionItem, effects.stream(), extraEffects, higherAmplifier, higherDuration); + } + + private EffectIngredient(@Nullable Item potionItem, Stream effects, boolean extraEffects, boolean higherAmplifier, boolean higherDuration) { this.potionItem = potionItem; - this.effects = List.copyOf(effects); + this.effects = effects.map(MobEffectInstance::new).toList(); this.extraEffects = extraEffects; this.higherAmplifier = higherAmplifier; this.higherDuration = higherDuration; @@ -86,20 +107,27 @@ public EffectIngredient(@Nullable Item potionItem, List effec @Nonnull @Override - public ItemStack[] getItems() { + public IngredientType getType() { + return TYPE; + } + + @Nonnull + @Override + public Stream getItems() { ItemStack potion = new ItemStack(this.potionItem == null ? Items.POTION : this.potionItem); - PotionUtils.setCustomEffects(potion, this.effects); - return new ItemStack[]{potion}; + PotionContents potionContents = new PotionContents(Optional.empty(), Optional.empty(), this.effects.stream().map(MobEffectInstance::new).toList()); + potion.set(DataComponents.POTION_CONTENTS, potionContents); + return Stream.of(potion); } @Override public boolean test(@Nullable ItemStack stack) { if (stack != null && !stack.isEmpty() && (this.potionItem == null || stack.getItem() == this.potionItem)) { - List effectsLeft = new ArrayList<>(PotionUtils.getMobEffects(stack)); + List effectsLeft = new ArrayList<>(getEffects(stack).toList()); for (MobEffectInstance effect : this.effects) { if (!effectsLeft.removeIf(left -> (left.getEffect() == effect.getEffect()) && (left.getAmplifier() == effect.getAmplifier() || (this.higherAmplifier && left.getAmplifier() > effect.getAmplifier())) - && (left.getEffect().isInstantenous() || left.getDuration() == effect.getDuration() || (this.higherDuration && left.getDuration() > effect.getDuration())))) { + && (left.getEffect().value().isInstantenous() || left.getDuration() == effect.getDuration() || (this.higherDuration && left.getDuration() > effect.getDuration())))) { return false; } } @@ -108,155 +136,15 @@ public boolean test(@Nullable ItemStack stack) { return false; } } - - @Nonnull - @Override - public IntList getStackingIds() { - ItemStack[] stacks = this.getItems(); - IntArrayList ial = new IntArrayList(stacks.length); - for (ItemStack stack : stacks) - ial.add(StackedContents.getStackingIndex(stack)); - return ial; + + private static Stream getEffects(ItemStack stack) { + PotionContents potionContents = stack.get(DataComponents.POTION_CONTENTS); + if (potionContents == null) return Stream.of(); + return Streams.of(potionContents.getAllEffects()); } @Override public boolean isSimple() { return false; } - - @Nonnull - @Override - public IIngredientSerializer getSerializer() { - return Serializer.INSTANCE; - } - - @Override - public boolean isEmpty() { - return this.potionItem == Items.AIR || this.potionItem == null && this.effects.isEmpty(); - } - - @Nonnull - @Override - @SuppressWarnings("ConstantConditions") - public JsonElement toJson() { - JsonObject json = new JsonObject(); - json.addProperty("type", CraftingHelper.getID(Serializer.INSTANCE).toString()); - if (this.potionItem == null) { - json.add("item", JsonNull.INSTANCE); - } else { - json.addProperty("item", Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(this.potionItem)).toString()); - } - JsonArray jsonEffects = new JsonArray(); - for (MobEffectInstance effect : this.effects) { - JsonObject effectJson = new JsonObject(); - effectJson.addProperty("potion", Objects.requireNonNull(ForgeRegistries.MOB_EFFECTS.getKey(effect.getEffect())).toString()); - effectJson.addProperty("amplifier", effect.getAmplifier()); - effectJson.addProperty("duration", effect.getDuration()); - jsonEffects.add(effectJson); - } - json.add("effects", jsonEffects); - json.addProperty("extraEffects", this.extraEffects); - json.addProperty("higherAmplifier", this.higherAmplifier); - json.addProperty("higherDuration", this.higherDuration); - return json; - } - - public static class Serializer implements IIngredientSerializer { - - public static final Serializer INSTANCE = new Serializer(); - - private Serializer() { - - } - - @Nonnull - @Override - public EffectIngredient parse(@Nonnull FriendlyByteBuf buffer) { - Item potionItem; - if (buffer.readBoolean()) { - potionItem = ForgeRegistries.ITEMS.getValue(buffer.readResourceLocation()); - if (potionItem == null) { - potionItem = Items.AIR; - } - } else { - potionItem = null; - } - - List effects = new ArrayList<>(); - int effectsSize = buffer.readInt(); - for (int i = 0; i < effectsSize; i++) { - MobEffect potion = ForgeRegistries.MOB_EFFECTS.getValue(buffer.readResourceLocation()); - if (potion == null) { - potion = MobEffects.MOVEMENT_SPEED; - } - int amplifier = buffer.readInt(); - int duration = buffer.readInt(); - effects.add(new MobEffectInstance(potion, duration, amplifier)); - } - - boolean extraEffects = buffer.readBoolean(); - boolean higherAmplifier = buffer.readBoolean(); - boolean higherDuration = buffer.readBoolean(); - - return new EffectIngredient(potionItem, effects, extraEffects, higherAmplifier, higherDuration); - } - - @Nonnull - @Override - public EffectIngredient parse(JsonObject json) { - JsonElement itemJson = json.get("item"); - Item potionItem; - if (itemJson.isJsonNull()) { - potionItem = null; - } else { - ResourceLocation potionRl = ResourceLocation.tryParse(itemJson.getAsString()); - potionItem = potionRl == null ? null : ForgeRegistries.ITEMS.getValue(potionRl); - if (potionItem == null) potionItem = Items.AIR; - } - - List effects = new ArrayList<>(); - for (JsonElement effectJson : json.get("effects").getAsJsonArray()) { - JsonObject effect = effectJson.getAsJsonObject(); - MobEffect potion = ForgeRegistries.MOB_EFFECTS.getValue(new ResourceLocation(effect.get("potion").getAsString())); - if (potion == null) { - potion = MobEffects.MOVEMENT_SPEED; - } - int amplifier = effect.get("amplifier").getAsInt(); - int duration = effect.get("duration").getAsInt(); - effects.add(new MobEffectInstance(potion, duration, amplifier)); - } - - boolean extraEffects = false; - if (json.has("extraEffects")) { - extraEffects = json.get("extraEffects").getAsBoolean(); - } - - boolean higherAmplifier = true; - if (json.has("higherAmplifier")) { - higherAmplifier = json.get("higherAmplifier").getAsBoolean(); - } - - boolean higherDuration = true; - if (json.has("higherDuration")) { - higherDuration = json.get("higherDuration").getAsBoolean(); - } - - return new EffectIngredient(potionItem, effects, extraEffects, higherAmplifier, higherDuration); - } - - @Override - public void write(@Nonnull FriendlyByteBuf buffer, @Nonnull EffectIngredient ingredient) { - buffer.writeBoolean(ingredient.potionItem != null); - if (ingredient.potionItem != null) buffer.writeResourceLocation(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(ingredient.potionItem))); - buffer.writeInt(ingredient.effects.size()); - for (MobEffectInstance effect : ingredient.effects) { - buffer.writeResourceLocation(Objects.requireNonNull(ForgeRegistries.MOB_EFFECTS.getKey(effect.getEffect()))); - buffer.writeInt(effect.getAmplifier()); - buffer.writeInt(effect.getDuration()); - } - buffer.writeBoolean(ingredient.extraEffects); - buffer.writeBoolean(ingredient.higherAmplifier); - buffer.writeBoolean(ingredient.higherDuration); - } - } } diff --git a/src/main/java/org/moddingx/libx/creativetab/CreativeTabX.java b/src/main/java/org/moddingx/libx/creativetab/CreativeTabX.java index 4372af79..3b4933bc 100644 --- a/src/main/java/org/moddingx/libx/creativetab/CreativeTabX.java +++ b/src/main/java/org/moddingx/libx/creativetab/CreativeTabX.java @@ -1,13 +1,16 @@ package org.moddingx.libx.creativetab; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.flag.FeatureFlagSet; -import net.minecraft.world.item.*; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.ForgeRegistry; -import net.minecraftforge.registries.RegisterEvent; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.GameMasterBlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.registries.RegisterEvent; import org.moddingx.libx.impl.ModInternal; import org.moddingx.libx.mod.ModX; @@ -24,8 +27,15 @@ public abstract class CreativeTabX { // Use numeric ids for ordering as they should represent the order in which items were registered. - @SuppressWarnings("UnstableApiUsage") - private static final Comparator REGISTRY_ORDER = Comparator.comparing(item -> ForgeRegistries.ITEMS instanceof ForgeRegistry reg ? reg.getID(item) : Integer.MAX_VALUE - 1); + private static final Comparator REGISTRY_ORDER = Comparator.comparing(item -> { + if (BuiltInRegistries.ITEM instanceof MappedRegistry) { + //noinspection unchecked + MappedRegistry mapped = (MappedRegistry) BuiltInRegistries.ITEM; + return mapped.getId(item); + } else { + return Integer.MAX_VALUE - 1; + } + }); protected final ModX mod; protected final ResourceLocation id; @@ -107,7 +117,7 @@ protected void addModItemStacks(TabContext ctx, Function * adds the stacks to the tab using a custom order. */ protected void addModItemStacks(TabContext ctx, Comparator order, Function> stacks) { - ForgeRegistries.ITEMS.getEntries().stream() + BuiltInRegistries.ITEM.entrySet().stream() .filter(entry -> this.mod.modid.equals(entry.getKey().location().getNamespace())) .map(Map.Entry::getValue) .filter(item -> item.isEnabled(ctx.features())) diff --git a/src/main/java/org/moddingx/libx/datagen/DatagenContext.java b/src/main/java/org/moddingx/libx/datagen/DatagenContext.java index 9297319a..61096a08 100644 --- a/src/main/java/org/moddingx/libx/datagen/DatagenContext.java +++ b/src/main/java/org/moddingx/libx/datagen/DatagenContext.java @@ -2,7 +2,7 @@ import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.moddingx.libx.mod.ModX; import java.util.function.Function; diff --git a/src/main/java/org/moddingx/libx/datagen/DatagenSystem.java b/src/main/java/org/moddingx/libx/datagen/DatagenSystem.java index 7533fffa..1734ae9a 100644 --- a/src/main/java/org/moddingx/libx/datagen/DatagenSystem.java +++ b/src/main/java/org/moddingx/libx/datagen/DatagenSystem.java @@ -1,17 +1,20 @@ package org.moddingx.libx.datagen; +import com.mojang.serialization.Codec; import net.minecraft.core.Registry; import net.minecraft.data.DataGenerator; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; +import net.minecraft.resources.RegistryDataLoader; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.RegistryLayer; import net.minecraft.server.packs.PackType; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.loading.FMLPaths; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.data.event.GatherDataEvent; import org.moddingx.libx.LibX; import org.moddingx.libx.impl.ModInternal; import org.moddingx.libx.impl.datagen.InternalDataProvider; @@ -26,10 +29,12 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Stream; public class DatagenSystem { private static final Set>> EXTENSION_REGISTRIES = new HashSet<>(); + private static final Map>, Codec> EXTRA_REGISTRIES = new HashMap<>(); /** * Marks a registry as an extension registry. An extension registry is a registry, where the id of the elements @@ -38,17 +43,39 @@ public class DatagenSystem { * Extension registries are frozen later during datagen to allow them access to frozen non-extension registries * while being populated. * + * This method sets acts globally for all mods, therefore a mod should only use it their own registries. + * * @see DatagenStage */ - public static void registerExtensionRegistry(ResourceKey> registryKey) { + public static synchronized void registerExtensionRegistry(ResourceKey> registryKey) { String activeMod = ModLoadingContext.get().getActiveNamespace(); if (!Objects.equals(LibX.getInstance().modid, activeMod) && !Objects.equals(registryKey.location().getNamespace(), activeMod)) { - // LibX is the exception: It has to make vanilla and forge registries extension registries + // LibX is the exception: It has to make vanilla and neoforge registries extension registries LibX.logger.warn("Registry " + registryKey.location() + " marked as extension registry by foreign mod: " + activeMod); } EXTENSION_REGISTRIES.add(registryKey); } + /** + * Defines a registry for datagen. This adds a registry with the given key and codec to the root {@link RegistrySet} + * from where it is inherited into all other {@link RegistrySet registry sets}. This is useful when there is no such + * registry at runtime and the registry is only required during datagen. + * + * This method sets acts globally for all mods, therefore a mod should only use it their own registries. + */ + public static synchronized void defineDatagenRegistry(ResourceKey> registryKey, Codec codec) { + String activeMod = ModLoadingContext.get().getActiveNamespace(); + if (!Objects.equals(LibX.getInstance().modid, activeMod) && !Objects.equals(registryKey.location().getNamespace(), activeMod)) { + // LibX is the exception: It has to make vanilla and neoforge registries extension registries + LibX.logger.warn("Registry " + registryKey.location() + " defined for datagen by foreign mod: " + activeMod); + } + if (EXTRA_REGISTRIES.containsKey(registryKey)) { + LibX.logger.error("Registry " + registryKey.location() + " defined for datagen twice."); + throw new IllegalStateException("Registry " + registryKey.location() + " defined for datagen twice."); + } + EXTRA_REGISTRIES.put(registryKey, codec); + } + /** * Gets a set of all extension.registries. * @@ -91,7 +118,26 @@ private DatagenSystem(ModX mod, GatherDataEvent event) { this.mod = mod; this.generator = event.getGenerator(); this.fileHelper = event.getExistingFileHelper(); - this.rootRegistries = new DatagenRegistrySet(DatagenRegistryLoader.loadRegistries(this.fileHelper)); + DatagenRegistryLoader.RegistrySelector selector = (layer, registries) -> { + if (layer != RegistryLayer.WORLDGEN) return registries; + List> extraRegistries = new ArrayList<>(); + for (Map.Entry>, Codec> extraEntry : EXTRA_REGISTRIES.entrySet()) { + if (registries.stream().anyMatch(registryData -> Objects.equals(extraEntry.getKey(), registryData.key()))) { + throw new IllegalStateException("Registry " + extraEntry.getKey() + " is a regular registry and was defined as datagen-only registry."); + } + //noinspection unchecked + extraRegistries.add(new RegistryDataLoader.RegistryData<>( + (ResourceKey>) extraEntry.getKey(), + (Codec) extraEntry.getValue(), + false + )); + } + return Stream.concat(registries.stream(), extraRegistries.stream()).toList(); + }; + this.rootRegistries = new DatagenRegistrySet( + DatagenRegistryLoader.loadRegistries(this.fileHelper, selector), + new DatagenRegistrySet.KnownRegistries(DatagenRegistryLoader.getDataPackRegistries(null, selector)) + ); this.mainTarget = new PackTarget("main", this, new DatagenRegistrySet(List.of(this.rootRegistries)), Map.of( PackType.CLIENT_RESOURCES, this.generator.getPackOutput().getOutputFolder(PackOutput.Target.RESOURCE_PACK), PackType.SERVER_DATA, this.generator.getPackOutput().getOutputFolder(PackOutput.Target.DATA_PACK) diff --git a/src/main/java/org/moddingx/libx/datagen/RegistryProvider.java b/src/main/java/org/moddingx/libx/datagen/RegistryProvider.java index 48eeb078..dc9d30b5 100644 --- a/src/main/java/org/moddingx/libx/datagen/RegistryProvider.java +++ b/src/main/java/org/moddingx/libx/datagen/RegistryProvider.java @@ -1,7 +1,21 @@ package org.moddingx.libx.datagen; +import net.minecraft.data.DataProvider; + +/** + * A registry provider is the analogue of a {@link DataProvider} for the {@link DatagenStage#REGISTRY_SETUP registry setup} + * and {@link DatagenStage#EXTENSION_SETUP extension setup} stages. It can register elements to the relevant registries + * which will be written to the datagen output once the datagen finishes. + */ public interface RegistryProvider { + /** + * Gets the name of the provider. + */ String getName(); + + /** + * Runs the provider. + */ void run(); } diff --git a/src/main/java/org/moddingx/libx/datagen/RegistrySet.java b/src/main/java/org/moddingx/libx/datagen/RegistrySet.java index eda35018..b072bc2e 100644 --- a/src/main/java/org/moddingx/libx/datagen/RegistrySet.java +++ b/src/main/java/org/moddingx/libx/datagen/RegistrySet.java @@ -17,7 +17,7 @@ public interface RegistrySet { * Gets a registry from the registry set. */ Registry registry(ResourceKey> registryKey); - + /** * Gets a writable registry from the registry set. This only succeeds, if the registry is a datapack registry * and this method is called in the correct {@link DatagenStage stage}. diff --git a/src/main/java/org/moddingx/libx/datagen/loot/LootBuilders.java b/src/main/java/org/moddingx/libx/datagen/loot/LootBuilders.java index 020579d2..143df7eb 100644 --- a/src/main/java/org/moddingx/libx/datagen/loot/LootBuilders.java +++ b/src/main/java/org/moddingx/libx/datagen/loot/LootBuilders.java @@ -67,7 +67,7 @@ public AllLootBuilder add(LootPoolEntryContainer.Builder entry) { @Nonnull @Override public LootPoolEntryContainer build() { - return new AllLootEntry(this.lootEntries.toArray(new LootPoolEntryContainer[0]), this.getConditions()); + return new AllLootEntry(List.copyOf(this.lootEntries), this.getConditions()); } } @@ -95,7 +95,7 @@ public GroupLootBuilder add(LootPoolEntryContainer.Builder entry) { @Nonnull @Override public LootPoolEntryContainer build() { - return new EntryGroup(this.lootEntries.toArray(new LootPoolEntryContainer[0]), this.getConditions()); + return new EntryGroup(List.copyOf(this.lootEntries), this.getConditions()); } } @@ -123,7 +123,7 @@ public SequenceLootBuilder add(LootPoolEntryContainer.Builder entry) { @Nonnull @Override public LootPoolEntryContainer build() { - return new SequentialEntry(this.lootEntries.toArray(new LootPoolEntryContainer[0]), this.getConditions()); + return new SequentialEntry(List.copyOf(this.lootEntries), this.getConditions()); } } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/AdvancementProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/AdvancementProviderBase.java index 9e647101..315d5607 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/AdvancementProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/AdvancementProviderBase.java @@ -1,10 +1,16 @@ package org.moddingx.libx.datagen.provider; +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; import net.minecraft.advancements.*; import net.minecraft.advancements.critereon.*; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.network.chat.Component; +import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; @@ -12,22 +18,25 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemEntityPropertyCondition; +import net.neoforged.neoforge.common.conditions.ICondition; +import net.neoforged.neoforge.common.conditions.WithConditions; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.PackTarget; +import org.moddingx.libx.datagen.RegistrySet; +import org.moddingx.libx.datapack.DatapackHelper; import org.moddingx.libx.mod.ModX; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; -import java.util.stream.Collectors; /** * Base provider for custom {@link Advancement advancements}. If you want to have multiple advancement @@ -39,17 +48,26 @@ public abstract class AdvancementProviderBase implements DataProvider { protected final ModX mod; protected final PackTarget packTarget; - private final Map> advancements = new HashMap<>(); + private final RegistrySet registries; + private final Map> advancements = new HashMap<>(); private String rootId = null; - private Supplier rootSupplier = null; + private Supplier rootSupplier = null; public AdvancementProviderBase(DatagenContext ctx) { this.mod = ctx.mod(); this.packTarget = ctx.target(); + this.registries = ctx.registries(); } public abstract void setup(); + /** + * Gets a list of conditions for all advancements added by this provider. + */ + protected List conditions() { + return List.of(); + } + @Nonnull @Override public String getName() { @@ -60,11 +78,16 @@ public String getName() { @Override public CompletableFuture run(@Nonnull CachedOutput cache) { this.setup(); - return CompletableFuture.allOf(this.advancements.values().stream().map(supplier -> { - Advancement advancement = supplier.get(); - Path path = this.packTarget.path(PackType.SERVER_DATA) - .resolve(advancement.getId().getNamespace() + "/advancements/" + advancement.getId().getPath() + ".json"); - return DataProvider.saveStable(cache, advancement.deconstruct().serializeToJson(), path); + RegistryOps ops = RegistryOps.create(JsonOps.INSTANCE, this.registries.registryAccess()); + return CompletableFuture.allOf(this.advancements.entrySet().stream().map(entry -> { + ResourceLocation id = entry.getKey(); + ResourceKey key = ResourceKey.create(Registries.ADVANCEMENT, id); + AdvancementInfo advancementInfo = entry.getValue().get(); + if (advancementInfo.advancement() == null) return CompletableFuture.completedFuture(null); + WithConditions conditionalAdvancement = new WithConditions<>(this.conditions(), advancementInfo.advancement()); + JsonElement json = Advancement.CONDITIONAL_CODEC.encodeStart(ops, Optional.of(conditionalAdvancement)).getOrThrow(RuntimeException::new); + Path path = this.packTarget.path(PackType.SERVER_DATA).resolve(DatapackHelper.registryPath(key)); + return DataProvider.saveStable(cache, json, path); }).toArray(CompletableFuture[]::new)); } @@ -119,9 +142,9 @@ public AdvancementFactory root(String namespace, String id) { /** * Adds a built {@link Advancement advancement} to the provider. */ - public void advancement(Advancement advancement) { - if (this.advancements.put(advancement.getId(), () -> advancement) != null) { - throw new IllegalStateException("Duplicate advancement: " + advancement.getId()); + public void advancement(ResourceLocation id, Advancement advancement) { + if (this.advancements.put(id, () -> new AdvancementInfo(id, advancement)) != null) { + throw new IllegalStateException("Duplicate advancement: " + id); } } @@ -146,24 +169,6 @@ public AdvancementFactory advancement(String id) { return this.advancement(this.idFor(id)); } - /** - * Creates a dummy {@link Advancement advancement} with a given id to be used as a parent if your - * advancement should have another advancement from another mod as parent. - */ - public Advancement dummy(ResourceLocation id) { - return this.dummy(id, false); - } - - /** - * Creates a dummy {@link Advancement advancement} with a given id to be used as a parent if your - * advancement should have another advancement from another mod as parent. - * - * @param hidden Whether the advancement is hidden. - */ - public Advancement dummy(ResourceLocation id, boolean hidden) { - return new Advancement(id, null, new DisplayInfo(new ItemStack(Items.BARRIER), Component.empty(), Component.empty(), null, FrameType.TASK, true, true, hidden), AdvancementRewards.EMPTY, new HashMap<>(), new String[][]{}, false); - } - private ResourceLocation idFor(String id) { if (this.rootId == null) { throw new IllegalStateException("On advancement providers without a root advancement only fully qualified resource locations are allowed, no plain ids."); @@ -172,27 +177,27 @@ private ResourceLocation idFor(String id) { } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires all of the given items to be in + * Gets a {@link Criterion criterion} that requires all of the given items to be in * the inventory at the same time. */ - public CriterionTriggerInstance items(ItemLike... items) { + public Criterion items(ItemLike... items) { return this.items(Arrays.stream(items).map(item -> ItemPredicate.Builder.item().of(item).build()).toArray(ItemPredicate[]::new)); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires all of the given items to be in + * Gets a {@link Criterion criterion} that requires all of the given items to be in * the inventory at the same time. */ @SafeVarargs - public final CriterionTriggerInstance items(TagKey... items) { + public final Criterion items(TagKey... items) { return this.items(Arrays.stream(items).map(item -> ItemPredicate.Builder.item().of(item).build()).toArray(ItemPredicate[]::new)); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires all of the given items to be in + * Gets a {@link Criterion criterion} that requires all of the given items to be in * the inventory at the same time. */ - public CriterionTriggerInstance items(ItemPredicate... items) { + public Criterion items(ItemPredicate... items) { return InventoryChangeTrigger.TriggerInstance.hasItems(items); } @@ -215,49 +220,56 @@ public final TaskFactory itemTasks(TagKey... items) { * Gets a {@link TaskFactory} that adds a task for every item given to this method. */ public TaskFactory itemTasks(ItemPredicate... items) { - return () -> Arrays.stream(items).map(item -> new CriterionTriggerInstance[]{this.items(item) }).toArray(CriterionTriggerInstance[][]::new); + return () -> Arrays.stream(items).map(item -> List.>of(this.items(item))).toList(); + } + + /** + * Gets a {@link Criterion criterion} that requires a player to consume (eat/drink) any item. + */ + public Criterion eat() { + return ConsumeItemTrigger.TriggerInstance.usedItem(); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to consume (eat/drink) an item. + * Gets a {@link Criterion criterion} that requires a player to consume (eat/drink) an item. */ - public CriterionTriggerInstance eat(ItemLike food) { - return this.eat(ItemPredicate.Builder.item().of(food).build()); + public Criterion eat(ItemLike food) { + return this.eat(ItemPredicate.Builder.item().of(food)); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to consume (eat/drink) an item. + * Gets a {@link Criterion criterion} that requires a player to consume (eat/drink) an item. */ - public CriterionTriggerInstance eat(TagKey food) { - return this.eat(ItemPredicate.Builder.item().of(food).build()); + public Criterion eat(TagKey food) { + return this.eat(ItemPredicate.Builder.item().of(food)); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to consume (eat/drink) an item. + * Gets a {@link Criterion criterion} that requires a player to consume (eat/drink) an item. */ - public CriterionTriggerInstance eat(ItemPredicate food) { - return new ConsumeItemTrigger.TriggerInstance(ContextAwarePredicate.ANY, food); + public Criterion eat(ItemPredicate.Builder food) { + return ConsumeItemTrigger.TriggerInstance.usedItem(food); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to leave a dimension. + * Gets a {@link Criterion criterion} that requires a player to leave a dimension. */ - public CriterionTriggerInstance leave(ResourceKey dimension) { - return new ChangeDimensionTrigger.TriggerInstance(ContextAwarePredicate.ANY, dimension, null); + public Criterion leave(ResourceKey dimension) { + return ChangeDimensionTrigger.TriggerInstance.changedDimensionFrom(dimension); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to enter a dimension. + * Gets a {@link Criterion criterion} that requires a player to enter a dimension. */ - public CriterionTriggerInstance enter(ResourceKey dimension) { + public Criterion enter(ResourceKey dimension) { return ChangeDimensionTrigger.TriggerInstance.changedDimensionTo(dimension); } /** - * Gets a {@link CriterionTriggerInstance criterion} that requires a player to perform a specific dimension change. + * Gets a {@link Criterion criterion} that requires a player to perform a specific dimension change. */ - public CriterionTriggerInstance changeDim(ResourceKey from, ResourceKey to) { - return new ChangeDimensionTrigger.TriggerInstance(ContextAwarePredicate.ANY, from, to); + public Criterion changeDim(ResourceKey from, ResourceKey to) { + return ChangeDimensionTrigger.TriggerInstance.changedDimension(from, to); } /** @@ -277,44 +289,49 @@ public ContextAwarePredicate entity(EntityType type) { /** * Gets an {@link ItemPredicate} for an item and optionally some enchantments. */ - public ItemPredicate stack(ItemLike item, Enchantment... enchs) { + @SafeVarargs + public final ItemPredicate.Builder stack(ItemLike item, ResourceKey... enchs) { ItemPredicate.Builder builder = ItemPredicate.Builder.item().of(item); - for (Enchantment ench : enchs) { - builder.hasEnchantment(new EnchantmentPredicate(ench, MinMaxBounds.Ints.atLeast(1))); - } - return builder.build(); + return this.applyEnchantments(builder, enchs); } /** * Gets an {@link ItemPredicate} for an item and optionally some enchantments. */ - public ItemPredicate stack(TagKey item, Enchantment... enchs) { + @SafeVarargs + public final ItemPredicate.Builder stack(TagKey item, ResourceKey... enchs) { ItemPredicate.Builder builder = ItemPredicate.Builder.item().of(item); - for (Enchantment ench : enchs) { - builder.hasEnchantment(new EnchantmentPredicate(ench, MinMaxBounds.Ints.atLeast(1))); - } - return builder.build(); + return this.applyEnchantments(builder, enchs); } /** * Gets an {@link ItemPredicate} for some enchantments. */ - public ItemPredicate stack(Enchantment... enchs) { + @SafeVarargs + public final ItemPredicate.Builder stack(ResourceKey... enchs) { if (enchs.length == 0) { - throw new IllegalStateException("Don't use stack() for an any predicate. Use ItemPredicate.ANY instead."); + throw new IllegalStateException("stack() can't be used to obtain an allways matching predicate."); } ItemPredicate.Builder builder = ItemPredicate.Builder.item(); - for (Enchantment ench : enchs) { - builder.hasEnchantment(new EnchantmentPredicate(ench, MinMaxBounds.Ints.atLeast(1))); - } - return builder.build(); + return this.applyEnchantments(builder, enchs); } /** * Gets an {@link ItemPredicate} for an enchantment with a minimum level. */ - public ItemPredicate stack(Enchantment ench, int min) { - return ItemPredicate.Builder.item().hasEnchantment(new EnchantmentPredicate(ench, MinMaxBounds.Ints.atLeast(min))).build(); + public ItemPredicate.Builder stack(ResourceKey ench, int min) { + Registry registry = this.registries.registry(Registries.ENCHANTMENT); + EnchantmentPredicate enchantmentPredicate = new EnchantmentPredicate(registry.getHolderOrThrow(ench), MinMaxBounds.Ints.atLeast(min)); + return ItemPredicate.Builder.item().withSubPredicate(ItemSubPredicates.ENCHANTMENTS, ItemEnchantmentsPredicate.enchantments(List.of(enchantmentPredicate))); + } + + private ItemPredicate.Builder applyEnchantments(ItemPredicate.Builder builder, ResourceKey[] enchantments) { + if (enchantments.length == 0) return builder; + Registry registry = this.registries.registry(Registries.ENCHANTMENT); + List enchantmentPredicates = Arrays.stream(enchantments) + .map(key -> new EnchantmentPredicate(registry.getHolderOrThrow(key), MinMaxBounds.Ints.ANY)) + .toList(); + return builder.withSubPredicate(ItemSubPredicates.ENCHANTMENTS, ItemEnchantmentsPredicate.enchantments(enchantmentPredicates)); } /** @@ -327,15 +344,15 @@ public class AdvancementFactory { private final ResourceLocation id; private final boolean root; - private Supplier parent; - private DisplayInfo display; - private ResourceLocation background; - private final List> criteria = new ArrayList<>(); + private Supplier parent; + @Nullable private DisplayInfo display; + @Nullable private ResourceLocation background; + private final List>> criteria = new ArrayList<>(); private AdvancementRewards reward = AdvancementRewards.EMPTY; private boolean telmetryEvent; private AdvancementFactory(String namespace, String rootId) { - this.id = new ResourceLocation(namespace, rootId + "/root"); + this.id = ResourceLocation.fromNamespaceAndPath(namespace, rootId + "/root"); this.root = true; this.parent = () -> null; this.telmetryEvent = false; @@ -347,15 +364,6 @@ private AdvancementFactory(ResourceLocation id) { this.parent = () -> null; } - /** - * Sets the parent of this advancement. - */ - public AdvancementFactory parent(Advancement parent) { - if (this.root) throw new IllegalStateException("Can't set parent for root advancement."); - this.parent = () -> parent; - return this; - } - /** * Sets the parent of this advancement. The advancement must be found in this provider. */ @@ -378,6 +386,16 @@ public AdvancementFactory parent(String id) { return this.parent(AdvancementProviderBase.this.idFor(id)); } + /** + * Sets the parent of this advancement. This method should not be used with advancements from this provider + * and is only meant to set foreign advancements as parent. + */ + public AdvancementFactory foreignParent(ResourceLocation id) { + if (this.root) throw new IllegalStateException("Can't set parent for root advancement."); + this.parent = () -> new AdvancementInfo(id, null); + return this; + } + /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. @@ -390,16 +408,16 @@ public AdvancementFactory display(ItemLike icon) { * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemLike icon, FrameType frame) { - return this.display(new ItemStack(icon), frame); + public AdvancementFactory display(ItemLike icon, AdvancementType type) { + return this.display(new ItemStack(icon), type); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemLike icon, FrameType frame, boolean toast, boolean chat, boolean hidden) { - return this.display(new ItemStack(icon), frame, toast, chat, hidden); + public AdvancementFactory display(ItemLike icon, AdvancementType type, boolean toast, boolean chat, boolean hidden) { + return this.display(new ItemStack(icon), type, toast, chat, hidden); } /** @@ -407,26 +425,26 @@ public AdvancementFactory display(ItemLike icon, FrameType frame, boolean toast, * advancement won't be visible. */ public AdvancementFactory display(ItemStack icon) { - return this.display(icon, FrameType.TASK); + return this.display(icon, AdvancementType.TASK); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemStack icon, FrameType frame) { - return this.display(icon, frame, !this.root, !this.root, false); + public AdvancementFactory display(ItemStack icon, AdvancementType type) { + return this.display(icon, type, !this.root, !this.root, false); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemStack icon, FrameType frame, boolean toast, boolean chat, boolean hidden) { + public AdvancementFactory display(ItemStack icon, AdvancementType type, boolean toast, boolean chat, boolean hidden) { return this.display(icon, Component.translatable("advancements." + this.id.getNamespace() + "." + this.id.getPath().replace('/', '.') + ".title"), Component.translatable("advancements." + this.id.getNamespace() + "." + this.id.getPath().replace('/', '.') + ".description"), - frame, toast, chat, hidden + type, toast, chat, hidden ); } @@ -442,16 +460,16 @@ public AdvancementFactory display(ItemLike icon, Component title, Component desc * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemLike icon, Component title, Component description, FrameType frame) { - return this.display(new ItemStack(icon), title, description, frame); + public AdvancementFactory display(ItemLike icon, Component title, Component description, AdvancementType type) { + return this.display(new ItemStack(icon), title, description, type); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemLike icon, Component title, Component description, FrameType frame, boolean toast, boolean chat, boolean hidden) { - return this.display(new ItemStack(icon), title, description, frame, toast, chat, hidden); + public AdvancementFactory display(ItemLike icon, Component title, Component description, AdvancementType type, boolean toast, boolean chat, boolean hidden) { + return this.display(new ItemStack(icon), title, description, type, toast, chat, hidden); } /** @@ -459,23 +477,23 @@ public AdvancementFactory display(ItemLike icon, Component title, Component desc * advancement won't be visible. */ public AdvancementFactory display(ItemStack icon, Component title, Component description) { - return this.display(icon, title, description, FrameType.TASK); + return this.display(icon, title, description, AdvancementType.TASK); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemStack icon, Component title, Component description, FrameType frame) { - return this.display(icon, title, description, frame, !this.root, !this.root, false); + public AdvancementFactory display(ItemStack icon, Component title, Component description, AdvancementType type) { + return this.display(icon, title, description, type, !this.root, !this.root, false); } /** * Sets the display info for this advancement. If {@code display} is not called, the * advancement won't be visible. */ - public AdvancementFactory display(ItemStack icon, Component title, Component description, FrameType frame, boolean toast, boolean chat, boolean hidden) { - this.display = new DisplayInfo(icon, title, description, null, frame, toast, chat, hidden); + public AdvancementFactory display(ItemStack icon, Component title, Component description, AdvancementType type, boolean toast, boolean chat, boolean hidden) { + this.display = new DisplayInfo(icon, title, description, Optional.empty(), type, toast, chat, hidden); return this; } @@ -494,11 +512,11 @@ public AdvancementFactory background(ResourceLocation background) { * Adds a task to the advancement. A task can consist of multiple criteria. In this case * one of the criteria must be completed to complete the whole task. */ - public AdvancementFactory task(CriterionTriggerInstance... criteria) { + public AdvancementFactory task(Criterion... criteria) { if (criteria.length == 0) { throw new IllegalStateException("Can not add empty task to advancement."); } - this.criteria.add(Arrays.stream(criteria).map(Criterion::new).collect(Collectors.toList())); + this.criteria.add(List.of(criteria)); return this; } @@ -506,14 +524,13 @@ public AdvancementFactory task(CriterionTriggerInstance... criteria) { * Adds multiple tasks to the advancement. Here all criteria must be completed to * complete the advancement. */ - public AdvancementFactory tasks(CriterionTriggerInstance... criteria) { + public AdvancementFactory tasks(Criterion... criteria) { if (criteria.length == 0) { throw new IllegalStateException("Can not add empty task to advancement."); } - for (CriterionTriggerInstance instance : criteria) { - this.criteria.add(List.of(new Criterion(instance))); + for (Criterion criterion : criteria) { + this.criteria.add(List.of(criterion)); } - this.criteria.add(Arrays.stream(criteria).map(Criterion::new).collect(Collectors.toList())); return this; } @@ -521,8 +538,8 @@ public AdvancementFactory tasks(CriterionTriggerInstance... criteria) { * Adds multiple tasks to this advancement defined by the given {@link TaskFactory}. */ public AdvancementFactory tasks(TaskFactory factory) { - for (CriterionTriggerInstance[] task : factory.apply()) { - this.task(task); + for (List> task : factory.apply()) { + this.task(task.toArray(Criterion[]::new)); } return this; } @@ -539,36 +556,42 @@ public AdvancementFactory sendsTelmetryEvent() { this.telmetryEvent = true; return this; } - - private Advancement build() { + + private AdvancementInfo build() { if (this.criteria.isEmpty()) { throw new IllegalStateException("Can not add advancement without tasks."); } Set idsTaken = new HashSet<>(); - String[][] criteriaIds = new String[this.criteria.size()][]; - Map criteriaMap = new HashMap<>(); - for (int i = 0; i < this.criteria.size(); i++) { - String[] criterionGroup = new String[this.criteria.get(i).size()]; - for (int j = 0; j < this.criteria.get(i).size(); j++) { - String baseName = Objects.requireNonNull(this.criteria.get(i).get(j).getTrigger(), "Can't build advancement: Empty criterion").getCriterion().getPath(); - baseName = baseName.replace('.', '_').replace('/', '_'); + List> criteriaIds = new ArrayList<>(); + Map> criteriaMap = new HashMap<>(); + for (List> criterionGroup : this.criteria) { + List criterionGroupIds = new ArrayList<>(); + for (Criterion criterion : criterionGroup) { + CriterionTrigger trigger = Objects.requireNonNull(criterion.trigger(), "Can't build advancement: Empty criterion"); + ResourceLocation triggerId = Objects.requireNonNull(BuiltInRegistries.TRIGGER_TYPES.getKey(trigger), "Unregistered criterion trigger"); + String baseName = "minecraft".equals(triggerId.getNamespace()) ? triggerId.getPath() : triggerId.toString(); + baseName = baseName.replace(':', '_').replace('.', '_').replace('/', '_'); String nextId = baseName; int num = 2; while ((idsTaken.contains(nextId))) { nextId = baseName + (num++); } idsTaken.add(nextId); - criterionGroup[j] = nextId; - criteriaMap.put(nextId, this.criteria.get(i).get(j)); + criterionGroupIds.add(nextId); + criteriaMap.put(nextId, criterion); } - criteriaIds[i] = criterionGroup; + criteriaIds.add(List.copyOf(criterionGroupIds)); } - Advancement parentAdv = this.parent.get(); - if (this.root && parentAdv != null) { + AdvancementInfo parent = this.parent.get(); + ResourceLocation parentId = parent == null ? null : parent.id(); + Advancement parentAdv = parentId == null ? null : parent.advancement(); + if (this.root && parentId != null) { throw new IllegalStateException("Root advancement can not have a parent."); - } else if (!this.root && parentAdv == null) { + } else if (!this.root && parentId == null) { if (AdvancementProviderBase.this.rootSupplier != null) { - parentAdv = AdvancementProviderBase.this.rootSupplier.get(); + parent = AdvancementProviderBase.this.rootSupplier.get(); + parentId = parent == null ? null : parent.id(); + parentAdv = parentId == null ? null : parent.advancement(); if (parentAdv == null) { throw new IllegalStateException("Root advancement configured wrongly. This is an error in LibX."); } @@ -583,15 +606,16 @@ private Advancement build() { } else if (this.background == null) { throw new IllegalStateException("Can't build root advancement without background."); } - displayInfo = new DisplayInfo(this.display.getIcon(), this.display.getTitle(), this.display.getDescription(), this.background, this.display.getFrame(), this.display.shouldShowToast(), this.display.shouldAnnounceChat(), this.display.isHidden()); + displayInfo = new DisplayInfo(this.display.getIcon(), this.display.getTitle(), this.display.getDescription(), Optional.ofNullable(this.background), this.display.getType(), this.display.shouldShowToast(), this.display.shouldAnnounceChat(), this.display.isHidden()); } - if (parentAdv != null && parentAdv.getDisplay() == null && displayInfo != null) { + if (parentAdv != null && parentAdv.display().isEmpty() && displayInfo != null) { throw new IllegalStateException("Can't build advancement with display and display-less parent."); } - if (parentAdv != null && parentAdv.getDisplay() != null && displayInfo != null && parentAdv.getDisplay().isHidden() && !displayInfo.isHidden()) { + if (parentAdv != null && parentAdv.display().isPresent() && displayInfo != null && parentAdv.display().get().isHidden() && !displayInfo.isHidden()) { throw new IllegalStateException("Can't build visible advancement with hidden parent."); } - return new Advancement(this.id, parentAdv, displayInfo, this.reward, criteriaMap, criteriaIds, this.telmetryEvent); + Advancement advancement = new Advancement(Optional.ofNullable(parentId), Optional.ofNullable(displayInfo), this.reward, criteriaMap, new AdvancementRequirements(List.copyOf(criteriaIds)), this.telmetryEvent); + return new AdvancementInfo(this.id, advancement); } } @@ -600,6 +624,9 @@ private Advancement build() { */ public interface TaskFactory { - CriterionTriggerInstance[][] apply(); + List>> apply(); } + + // null advancement means unknown + private record AdvancementInfo(ResourceLocation id, @Nullable Advancement advancement) {} } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/DamageTypeProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/DamageTypeProviderBase.java index 0a8f7e1c..68f3ce92 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/DamageTypeProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/DamageTypeProviderBase.java @@ -40,7 +40,7 @@ public class DamageTypeBuilder { private DamageEffects effects = DamageEffects.HURT; private DeathMessageType deathMessageType = DeathMessageType.DEFAULT; - public DamageTypeBuilder(String msgId, float exhaustion) { + private DamageTypeBuilder(String msgId, float exhaustion) { this.msgId = msgId; this.exhaustion = exhaustion; } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/EnchantmentProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/EnchantmentProviderBase.java new file mode 100644 index 00000000..b3081f86 --- /dev/null +++ b/src/main/java/org/moddingx/libx/datagen/provider/EnchantmentProviderBase.java @@ -0,0 +1,410 @@ +package org.moddingx.libx.datagen.provider; + +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.tags.TagKey; +import net.minecraft.util.valueproviders.ConstantInt; +import net.minecraft.util.valueproviders.IntProvider; +import net.minecraft.util.valueproviders.UniformInt; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.enchantment.ConditionalEffect; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.LevelBasedValue; +import net.minecraft.world.item.enchantment.effects.*; +import net.minecraft.world.item.enchantment.providers.EnchantmentProvider; +import net.minecraft.world.item.enchantment.providers.EnchantmentsByCost; +import net.minecraft.world.item.enchantment.providers.EnchantmentsByCostWithDifficulty; +import net.minecraft.world.item.enchantment.providers.SingleEnchantment; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import org.moddingx.libx.datagen.DatagenContext; +import org.moddingx.libx.datagen.DatagenStage; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; + +/** + * Registry provider for {@link Enchantment enchantments} and {@link EnchantmentProvider enchantment providers}. + *

    + * This provider must run in the {@link DatagenStage#REGISTRY_SETUP registry setup} stage. + */ +public abstract class EnchantmentProviderBase extends RegistryProviderBase { + + public EnchantmentProviderBase(DatagenContext ctx) { + super(ctx, DatagenStage.REGISTRY_SETUP); + } + + @Nonnull + @Override + public String getName() { + return this.mod.modid + " enchantments"; + } + + public EnchantmentBuilder enchantment(Component name) { + return new EnchantmentBuilder(name); + } + + public SingleEnchantmentProviderBuilder provider(Holder enchantment) { + return new SingleEnchantmentProviderBuilder(enchantment); + } + + public MultiEnchantmentProviderBuilder provider(TagKey enchantments) { + return new MultiEnchantmentProviderBuilder(this.set(enchantments)); + } + + public MultiEnchantmentProviderBuilder provider(HolderSet enchantments) { + return new MultiEnchantmentProviderBuilder(enchantments); + } + + public class EnchantmentBuilder { + + private final Component name; + @Nullable private HolderSet supportedItems; + @Nullable private HolderSet primaryItems; + private int weight; + private int maxLevel; + @Nullable private Enchantment.Cost minCost; + @Nullable private Enchantment.Cost maxCost; + private int anvilCost; + private final Set slots; + private HolderSet exclusiveSet; + private final DataComponentMap.Builder effects; + private final Map>, List> effectLists; + + private EnchantmentBuilder(Component name) { + this.name = name; + this.supportedItems = null; + this.primaryItems = null; + this.weight = 1; + this.maxLevel = 1; + this.minCost = null; + this.maxCost = null; + this.anvilCost = 1; + this.slots = new HashSet<>(); + this.exclusiveSet = HolderSet.direct(); + this.effects = DataComponentMap.builder(); + this.effectLists = new HashMap<>(); + } + + public EnchantmentBuilder supportedItems(ItemLike... items) { + List> holderList = Arrays.stream(items).map(item -> EnchantmentProviderBase.this.holder(Registries.ITEM, item.asItem())).toList(); + return this.supportedItems(HolderSet.direct(holderList)); + } + + public EnchantmentBuilder supportedItems(TagKey items) { + return this.supportedItems(EnchantmentProviderBase.this.set(items)); + } + + public EnchantmentBuilder supportedItems(HolderSet items) { + this.supportedItems = items; + return this; + } + + public EnchantmentBuilder primaryItems(ItemLike... items) { + List> holderList = Arrays.stream(items).map(item -> EnchantmentProviderBase.this.holder(Registries.ITEM, item.asItem())).toList(); + return this.primaryItems(HolderSet.direct(holderList)); + } + + public EnchantmentBuilder primaryItems(TagKey items) { + return this.primaryItems(EnchantmentProviderBase.this.set(items)); + } + + public EnchantmentBuilder primaryItems(HolderSet items) { + this.primaryItems = items; + return this; + } + + public EnchantmentBuilder weight(int weight) { + this.weight = weight; + return this; + } + + public EnchantmentBuilder maxLevel(int maxLevel) { + this.maxLevel = maxLevel; + return this; + } + + public EnchantmentBuilder minCost(int base, int extraPerAdditionalLevel) { + this.minCost = new Enchantment.Cost(base, extraPerAdditionalLevel); + return this; + } + + public EnchantmentBuilder maxCost(int base, int extraPerAdditionalLevel) { + this.maxCost = new Enchantment.Cost(base, extraPerAdditionalLevel); + return this; + } + + public EnchantmentBuilder cost(int base, int extraPerAdditionalLevel) { + this.minCost = new Enchantment.Cost(base, extraPerAdditionalLevel); + this.maxCost = new Enchantment.Cost(base, extraPerAdditionalLevel); + return this; + } + + public EnchantmentBuilder anvilCost(int anvilCost) { + this.anvilCost = anvilCost; + return this; + } + + public EnchantmentBuilder slot(EquipmentSlotGroup slot) { + this.slots.add(slot); + return this; + } + + @SafeVarargs + public final EnchantmentBuilder exclusiveSet(Holder... exclusiveSet) { + return this.exclusiveSet(EnchantmentProviderBase.this.set(exclusiveSet)); + } + + public EnchantmentBuilder exclusiveSet(TagKey exclusiveSet) { + return this.exclusiveSet(EnchantmentProviderBase.this.set(exclusiveSet)); + } + + public EnchantmentBuilder exclusiveSet(HolderSet exclusiveSet) { + this.exclusiveSet = exclusiveSet; + return this; + } + + public EnchantmentBuilder onlyEffect(DataComponentType type, T value) { + this.effects.set(type, value); + return this; + } + + public EnchantmentBuilder effect(DataComponentType> type, T value) { + //noinspection unchecked + List effectList = ((List) this.effectLists.computeIfAbsent((DataComponentType>) (DataComponentType) type, k -> new ArrayList<>())); + effectList.add(value); + return this; + } + + public EnchantmentBuilder conditionalEffect(DataComponentType>> type, T value) { + return this.conditionalEffect(type, value, null); + } + + public EnchantmentBuilder conditionalEffect(DataComponentType>> type, T value, @Nullable LootItemCondition condition) { + //noinspection unchecked + List> effectList = ((List>) this.effectLists.computeIfAbsent((DataComponentType>) (DataComponentType) type, k -> new ArrayList<>())); + effectList.add(new ConditionalEffect<>(value, Optional.ofNullable(condition))); + return this; + } + + public EnchantmentBuilder addValue(DataComponentType>> type, float value) { + return this.addValue(type, value, null); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, float value) { + return this.multiplyValue(type, value, null); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, float value) { + return this.replaceValue(type, value, null); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, float value) { + return this.removeBinomialValueValue(type, value, null); + } + + public EnchantmentBuilder addValue(DataComponentType>> type, float value, @Nullable LootItemCondition condition) { + return this.addValue(type, new LevelBasedValue.Constant(value), condition); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, float value, @Nullable LootItemCondition condition) { + return this.multiplyValue(type, new LevelBasedValue.Constant(value), condition); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, float value, @Nullable LootItemCondition condition) { + return this.replaceValue(type, new LevelBasedValue.Constant(value), condition); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, float value, @Nullable LootItemCondition condition) { + return this.removeBinomialValueValue(type, new LevelBasedValue.Constant(value), condition); + } + + public EnchantmentBuilder addValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst) { + return this.addValue(type, base, extraPerLevelAboveFirst, null); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst) { + return this.multiplyValue(type, base, extraPerLevelAboveFirst, null); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst) { + return this.replaceValue(type, base, extraPerLevelAboveFirst, null); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst) { + return this.removeBinomialValueValue(type, base, extraPerLevelAboveFirst, null); + } + + public EnchantmentBuilder addValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst, @Nullable LootItemCondition condition) { + return this.addValue(type, new LevelBasedValue.Linear(base, extraPerLevelAboveFirst), condition); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst, @Nullable LootItemCondition condition) { + return this.multiplyValue(type, new LevelBasedValue.Linear(base, extraPerLevelAboveFirst), condition); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst, @Nullable LootItemCondition condition) { + return this.replaceValue(type, new LevelBasedValue.Linear(base, extraPerLevelAboveFirst), condition); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, float base, float extraPerLevelAboveFirst, @Nullable LootItemCondition condition) { + return this.removeBinomialValueValue(type, new LevelBasedValue.Linear(base, extraPerLevelAboveFirst), condition); + } + + public EnchantmentBuilder addValue(DataComponentType>> type, LevelBasedValue value) { + return this.addValue(type, value, null); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, LevelBasedValue value) { + return this.multiplyValue(type, value, null); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, LevelBasedValue value) { + return this.replaceValue(type, value, null); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, LevelBasedValue value) { + return this.removeBinomialValueValue(type, value, null); + } + + public EnchantmentBuilder addValue(DataComponentType>> type, LevelBasedValue value, @Nullable LootItemCondition condition) { + return this.conditionalEffect(type, new AddValue(value), condition); + } + + public EnchantmentBuilder multiplyValue(DataComponentType>> type, LevelBasedValue value, @Nullable LootItemCondition condition) { + return this.conditionalEffect(type, new MultiplyValue(value), condition); + } + + public EnchantmentBuilder replaceValue(DataComponentType>> type, LevelBasedValue value, @Nullable LootItemCondition condition) { + return this.conditionalEffect(type, new SetValue(value), condition); + } + + public EnchantmentBuilder removeBinomialValueValue(DataComponentType>> type, LevelBasedValue value, @Nullable LootItemCondition condition) { + return this.conditionalEffect(type, new RemoveBinomial(value), condition); + } + + /** + * Builds the {@link Enchantment}. + *

    + * This method returns an {@link Holder.Reference.Type#INTRUSIVE intrusive holder} that must be properly + * added the registry. {@link RegistryProviderBase} does this automatically if the result is stored in a + * {@code public}, non-{@code static} field inside the provider. + */ + public Holder build() { + if (this.supportedItems == null) throw new IllegalStateException("No supported items set for enchantment."); + if (this.minCost == null) throw new IllegalStateException("No minimum cost set for enchantment."); + if (this.maxCost == null) throw new IllegalStateException("No maximum cost set for enchantment."); + if (this.slots.contains(EquipmentSlotGroup.HAND)) { + this.slots.remove(EquipmentSlotGroup.MAINHAND); + this.slots.remove(EquipmentSlotGroup.OFFHAND); + } + if (this.slots.contains(EquipmentSlotGroup.ARMOR)) { + this.slots.remove(EquipmentSlotGroup.HEAD); + this.slots.remove(EquipmentSlotGroup.CHEST); + this.slots.remove(EquipmentSlotGroup.LEGS); + this.slots.remove(EquipmentSlotGroup.FEET); + } + + DataComponentMap.Builder finalEffects = DataComponentMap.builder(); + for (Map.Entry>, List> entry : this.effectLists.entrySet()) { + finalEffects.set(entry.getKey(), List.copyOf(entry.getValue())); + } + finalEffects.addAll(this.effects.build()); + List slotList = this.slots.isEmpty() || this.slots.contains(EquipmentSlotGroup.ANY) ? List.of(EquipmentSlotGroup.ANY) : this.slots.stream().sorted().toList(); + Enchantment.EnchantmentDefinition definition = new Enchantment.EnchantmentDefinition(this.supportedItems, Optional.ofNullable(this.primaryItems), this.weight, this.maxLevel, this.minCost, this.maxCost, this.anvilCost, slotList); + Enchantment enchantment = new Enchantment(this.name, definition, this.exclusiveSet, finalEffects.build()); + return EnchantmentProviderBase.this.registries.writableRegistry(Registries.ENCHANTMENT).createIntrusiveHolder(enchantment); + } + } + + public class SingleEnchantmentProviderBuilder { + + private final Holder enchantment; + private IntProvider level; + + private SingleEnchantmentProviderBuilder(Holder enchantment) { + this.enchantment = enchantment; + this.level = ConstantInt.of(1); + } + + public SingleEnchantmentProviderBuilder level(int level) { + return this.level(ConstantInt.of(level)); + } + + public SingleEnchantmentProviderBuilder level(int minLevel, int maxLevel) { + return this.level(UniformInt.of(minLevel, maxLevel)); + } + + public SingleEnchantmentProviderBuilder level(IntProvider level) { + this.level = level; + return this; + } + + /** + * Builds the {@link EnchantmentProvider}. + *

    + * This method returns an {@link Holder.Reference.Type#INTRUSIVE intrusive holder} that must be properly + * added the registry. {@link RegistryProviderBase} does this automatically if the result is stored in a + * {@code public}, non-{@code static} field inside the provider. + */ + public Holder build() { + EnchantmentProvider provider = new SingleEnchantment(this.enchantment, this.level); + return EnchantmentProviderBase.this.registries.writableRegistry(Registries.ENCHANTMENT_PROVIDER).createIntrusiveHolder(provider); + } + } + + public class MultiEnchantmentProviderBuilder { + + private final HolderSet enchantments; + private Cost cost; + + private MultiEnchantmentProviderBuilder(HolderSet enchantments) { + this.enchantments = enchantments; + this.cost = new Cost.Single(ConstantInt.of(1)); + } + + public MultiEnchantmentProviderBuilder cost(int cost) { + return this.cost(ConstantInt.of(cost)); + } + + public MultiEnchantmentProviderBuilder cost(int minCost, int maxCost) { + return this.cost(UniformInt.of(minCost, maxCost)); + } + + public MultiEnchantmentProviderBuilder cost(IntProvider cost) { + this.cost = new Cost.Single(cost); + return this; + } + + public MultiEnchantmentProviderBuilder difficultyBasedCost(int minCost, int maxCostSpan) { + this.cost = new Cost.DifficultyBased(minCost, maxCostSpan); + return this; + } + + /** + * Builds the {@link EnchantmentProvider}. + *

    + * This method returns an {@link Holder.Reference.Type#INTRUSIVE intrusive holder} that must be properly + * added the registry. {@link RegistryProviderBase} does this automatically if the result is stored in a + * {@code public}, non-{@code static} field inside the provider. + */ + public Holder build() { + EnchantmentProvider provider = switch (this.cost) { + case Cost.Single single -> new EnchantmentsByCost(this.enchantments, single.value()); + case Cost.DifficultyBased difficultyBased -> new EnchantmentsByCostWithDifficulty(this.enchantments, difficultyBased.minCost(), difficultyBased.maxCostSpan()); + }; + return EnchantmentProviderBase.this.registries.writableRegistry(Registries.ENCHANTMENT_PROVIDER).createIntrusiveHolder(provider); + } + + private sealed interface Cost { + record Single(IntProvider value) implements Cost {} + record DifficultyBased(int minCost, int maxCostSpan) implements Cost {} + } + } +} diff --git a/src/main/java/org/moddingx/libx/datagen/provider/RegistryProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/RegistryProviderBase.java index 94dc3fa6..d98c986f 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/RegistryProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/RegistryProviderBase.java @@ -1,16 +1,16 @@ package org.moddingx.libx.datagen.provider; -import com.mojang.serialization.Lifecycle; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistrationInfo; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; -import net.minecraftforge.registries.holdersets.AndHolderSet; -import net.minecraftforge.registries.holdersets.AnyHolderSet; -import net.minecraftforge.registries.holdersets.NotHolderSet; -import net.minecraftforge.registries.holdersets.OrHolderSet; +import net.neoforged.neoforge.registries.holdersets.AndHolderSet; +import net.neoforged.neoforge.registries.holdersets.AnyHolderSet; +import net.neoforged.neoforge.registries.holdersets.NotHolderSet; +import net.neoforged.neoforge.registries.holdersets.OrHolderSet; import org.moddingx.libx.LibX; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.DatagenStage; @@ -152,9 +152,20 @@ public final HolderSet or(HolderSet a, TagKey b) { public final HolderSet or(HolderSet... sets) { return new OrHolderSet<>(List.of(sets)); } - + + /** + * Runs the provider. The default implementation just invokes {@link #registerFields()}. + */ @Override public void run() { + this.registerFields(); + } + + /** + * Registers all unbound intrusive holders stored in public {@link Holder} fields in this class to their respective + * registries. + */ + protected final void registerFields() { try { for (Field field : this.getClass().getFields()) { if (field.getDeclaringClass() != this.getClass()) continue; // Skip fields from superclasses @@ -163,13 +174,13 @@ public void run() { if (!Holder.class.isAssignableFrom(field.getType())) continue; Holder value = (Holder) field.get(this); if (value instanceof Holder.Reference ref) { - if (ref.getType() == Holder.Reference.Type.INTRUSIVE && !ref.isBound()) { + if (ref.type == Holder.Reference.Type.INTRUSIVE && !ref.isBound()) { ResourceKey> registryKey = this.registries.findRegistryFor(ref); if (registryKey == null) throw new IllegalStateException("Can't infer target registry for " + field.getName() + " in '" + this.getName() + "'. Was the holder created properly?"); ResourceLocation id; Id idObj = field.getAnnotation(Id.class); if (idObj != null) { - id = new ResourceLocation(idObj.namespace().isEmpty() ? this.mod.modid : idObj.namespace(), idObj.value()); + id = ResourceLocation.fromNamespaceAndPath(idObj.namespace().isEmpty() ? this.mod.modid : idObj.namespace(), idObj.value()); } else { StringBuilder sb = new StringBuilder(); for (char chr : field.getName().toCharArray()) { @@ -178,10 +189,10 @@ public void run() { } sb.append(Character.toLowerCase(chr)); } - id = new ResourceLocation(this.mod.modid, sb.toString()); + id = ResourceLocation.fromNamespaceAndPath(this.mod.modid, sb.toString()); } //noinspection unchecked - this.registries.writableRegistry((ResourceKey>) registryKey).register(ResourceKey.create((ResourceKey>) registryKey, id), ref.value(), Lifecycle.stable()); + this.registries.writableRegistry((ResourceKey>) registryKey).register(ResourceKey.create((ResourceKey>) registryKey, id), ref.value(), RegistrationInfo.BUILT_IN); } else if (field.getAnnotation(Id.class) != null) { Id idObj = field.getAnnotation(Id.class); String id = (idObj.namespace().isEmpty() ? this.mod.modid : idObj.namespace()) + ":" + idObj.value(); diff --git a/src/main/java/org/moddingx/libx/datagen/provider/SoundDefinitionProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/SoundDefinitionProviderBase.java index a769b3bc..6e630f60 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/SoundDefinitionProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/SoundDefinitionProviderBase.java @@ -1,14 +1,14 @@ package org.moddingx.libx.datagen.provider; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.common.data.SoundDefinition; -import net.minecraftforge.common.data.SoundDefinitionsProvider; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.SoundDefinition; +import net.neoforged.neoforge.common.data.SoundDefinitionsProvider; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.mod.ModX; @@ -53,7 +53,7 @@ public String getName() { * This sound will not be processed by the default generator */ protected void ignore(SoundEvent sound) { - this.ignore(Objects.requireNonNull(ForgeRegistries.SOUND_EVENTS.getKey(sound))); + this.ignore(Objects.requireNonNull(BuiltInRegistries.SOUND_EVENT.getKey(sound))); } /** @@ -85,7 +85,7 @@ protected SoundSettingsBuilder settings() { * Creates a new sound definition for the given sound event. */ protected SoundDefinitionBuilder sound(SoundEvent sound) { - return this.sound(Objects.requireNonNull(ForgeRegistries.SOUND_EVENTS.getKey(sound)), this.settings()); + return this.sound(Objects.requireNonNull(BuiltInRegistries.SOUND_EVENT.getKey(sound)), this.settings()); } /** @@ -99,7 +99,7 @@ protected SoundDefinitionBuilder sound(ResourceLocation sound) { * Creates a new sound definition for the given sound event and default sound settings. */ protected SoundDefinitionBuilder sound(SoundEvent sound, SoundSettingsBuilder settings) { - return this.sound(Objects.requireNonNull(ForgeRegistries.SOUND_EVENTS.getKey(sound)), settings); + return this.sound(Objects.requireNonNull(BuiltInRegistries.SOUND_EVENT.getKey(sound)), settings); } /** @@ -116,9 +116,9 @@ protected SoundDefinitionBuilder sound(ResourceLocation sound, SoundSettingsBuil private void registerSounds() { this.setup(); - for (ResourceLocation id : ForgeRegistries.SOUND_EVENTS.getKeys().stream().sorted().toList()) { + for (ResourceLocation id : BuiltInRegistries.SOUND_EVENT.keySet().stream().sorted().toList()) { if (this.mod.modid.equals(id.getNamespace()) && !this.ignored.contains(id)) { - SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(id); + SoundEvent sound = BuiltInRegistries.SOUND_EVENT.get(id); if (sound != null) { this.defaultSound(id, sound); } @@ -342,7 +342,7 @@ public SoundDefinitionBuilder withRange(String path, int amount, Consumer configure) { for (int i = 0; i < amount; i++) { - this.with(new ResourceLocation(soundId.getNamespace(), soundId.getPath() + i), configure); + this.with(ResourceLocation.fromNamespaceAndPath(soundId.getNamespace(), soundId.getPath() + i), configure); } return this; } @@ -358,7 +358,7 @@ public SoundDefinitionBuilder event(SoundEvent event) { * Adds another sound event as a sound for this definition. Also allows to then further customise the sound. */ public SoundDefinitionBuilder event(SoundEvent event, Consumer configure) { - SoundDefinition.Sound sound = SoundDefinition.Sound.sound(Objects.requireNonNull(ForgeRegistries.SOUND_EVENTS.getKey(event)), SoundDefinition.SoundType.EVENT); + SoundDefinition.Sound sound = SoundDefinition.Sound.sound(Objects.requireNonNull(BuiltInRegistries.SOUND_EVENT.getKey(event)), SoundDefinition.SoundType.EVENT); this.settings.applyTo(sound); configure.accept(sound); this.definition.with(sound); diff --git a/src/main/java/org/moddingx/libx/datagen/provider/loot/BlockLootProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/loot/BlockLootProviderBase.java index 67ae24e4..e7968af7 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/loot/BlockLootProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/loot/BlockLootProviderBase.java @@ -1,11 +1,8 @@ package org.moddingx.libx.datagen.provider.loot; -import net.minecraft.advancements.critereon.EnchantmentPredicate; -import net.minecraft.advancements.critereon.ItemPredicate; -import net.minecraft.advancements.critereon.MinMaxBounds; -import net.minecraft.advancements.critereon.StatePropertiesPredicate; +import net.minecraft.advancements.critereon.*; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import net.minecraft.util.StringRepresentable; import net.minecraft.world.item.Item; @@ -27,10 +24,8 @@ import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer; import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount; import net.minecraft.world.level.storage.loot.functions.CopyBlockState; -import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.predicates.*; -import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.loot.LootBuilders; @@ -38,11 +33,14 @@ import org.moddingx.libx.datagen.provider.loot.entry.LootFactory; import org.moddingx.libx.datagen.provider.loot.entry.LootModifier; import org.moddingx.libx.datagen.provider.loot.entry.SimpleLootFactory; +import org.moddingx.libx.impl.loot.CopyBlockEntityDataFunction; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; public abstract class BlockLootProviderBase extends LootProviderBase { @@ -156,7 +154,7 @@ public SilkModifier noSilk() { * A loot modifier to apply fortune based on the formula used for ores. */ public LootModifier fortuneOres() { - return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE))); + return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addOreBonusCount(this.holder(Enchantments.FORTUNE)))); } /** @@ -170,7 +168,7 @@ public LootModifier fortuneUniform() { * A loot modifier to apply fortune based on a uniform formula. */ public LootModifier fortuneUniform(int multiplier) { - return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addUniformBonusCount(Enchantments.BLOCK_FORTUNE, multiplier))); + return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addUniformBonusCount(this.holder(Enchantments.FORTUNE), multiplier))); } /** @@ -184,7 +182,7 @@ public LootModifier fortuneBinomial(float probability) { * A loot modifier to apply fortune based on a binomial formula. */ public LootModifier fortuneBinomial(float probability, int bonus) { - return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addBonusBinomialDistributionCount(Enchantments.BLOCK_FORTUNE, probability, bonus))); + return this.modifier((block, entry) -> entry.apply(ApplyBonusCount.addBonusBinomialDistributionCount(this.holder(Enchantments.FORTUNE), probability, bonus))); } @@ -207,7 +205,7 @@ public LootItemCondition.Builder randomFortune(float baseChance, float... levelC float[] chances = new float[levelChances.length + 1]; chances[0] = baseChance; System.arraycopy(levelChances, 0, chances, 1, levelChances.length); - return BonusLevelTableCondition.bonusLevelFlatChance(Enchantments.BLOCK_FORTUNE, chances); + return BonusLevelTableCondition.bonusLevelFlatChance(this.holder(Enchantments.FORTUNE), chances); } /** @@ -236,7 +234,9 @@ public MatchStateBuilder matchState() { */ public LootItemCondition.Builder silkCondition() { ItemPredicate.Builder predicate = ItemPredicate.Builder.item() - .hasEnchantment(new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.atLeast(1))); + .withSubPredicate(ItemSubPredicates.ENCHANTMENTS, ItemEnchantmentsPredicate.enchantments(List.of( + new EnchantmentPredicate(this.holder(Enchantments.SILK_TOUCH), MinMaxBounds.Ints.ANY) + ))); return MatchTool.toolMatches(predicate); } @@ -247,10 +247,7 @@ public LootItemCondition.Builder silkCondition() { */ public LootModifier copyNBT(String... tags) { return this.modifier((block, entry) -> { - CopyNbtFunction.Builder func = CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY); - for (String tag : tags) { - func = func.copy(tag, "BlockEntityTag." + tag); - } + CopyBlockEntityDataFunction.Builder func = CopyBlockEntityDataFunction.copyBlockEntityData(block, Set.of(tags)); return entry.apply(func); }); } @@ -289,25 +286,31 @@ private SilkModifier(@Nullable GenericLootModifier modifier) { * This serves as a builder for a loot condition and a builder for a match tool predicate * in one. */ - public static class MatchToolBuilder implements LootItemCondition.Builder { + public class MatchToolBuilder implements LootItemCondition.Builder { private final ItemPredicate.Builder builder; + private final List enchantments; private MatchToolBuilder(ItemPredicate.Builder builder) { this.builder = builder; + this.enchantments = new ArrayList<>(); } @Nonnull @Override public LootItemCondition build() { + if (!this.enchantments.isEmpty()) { + this.builder.withSubPredicate(ItemSubPredicates.ENCHANTMENTS, ItemEnchantmentsPredicate.enchantments(List.copyOf(this.enchantments))); + this.enchantments.clear(); + } return MatchTool.toolMatches(this.builder).build(); } /** * Adds a required enchantment to this builder. */ - public MatchToolBuilder enchantment(Enchantment enchantment) { - return this.enchantment(enchantment, MinMaxBounds.Ints.atLeast(1)); + public MatchToolBuilder enchantment(ResourceKey enchantment) { + return this.enchantment(enchantment, MinMaxBounds.Ints.ANY); } /** @@ -315,7 +318,7 @@ public MatchToolBuilder enchantment(Enchantment enchantment) { * * @param minLevel The minimum level of the enchantment that must be present. */ - public MatchToolBuilder enchantment(Enchantment enchantment, int minLevel) { + public MatchToolBuilder enchantment(ResourceKey enchantment, int minLevel) { return this.enchantment(enchantment, MinMaxBounds.Ints.atLeast(minLevel)); } @@ -324,20 +327,23 @@ public MatchToolBuilder enchantment(Enchantment enchantment, int minLevel) { * * @param level The exact level of the enchantment that must be present. */ - public MatchToolBuilder enchantmentExact(Enchantment enchantment, int level) { + public MatchToolBuilder enchantmentExact(ResourceKey enchantment, int level) { return this.enchantment(enchantment, MinMaxBounds.Ints.exactly(level)); } - private MatchToolBuilder enchantment(Enchantment enchantment, MinMaxBounds.Ints bounds) { - this.builder.hasEnchantment(new EnchantmentPredicate(enchantment, bounds)); + private MatchToolBuilder enchantment(ResourceKey enchantment, MinMaxBounds.Ints bounds) { + this.enchantments.add(new EnchantmentPredicate(BlockLootProviderBase.this.holder(enchantment), bounds)); return this; } /** - * Adds required NBT data to this builder. + * Sets an {@link ItemSubPredicate} for this builder. This replaces any previously set values for the given + * {@link ItemSubPredicate.Type type}. {@link ItemSubPredicates#ENCHANTMENTS Enchantments} can't be set this + * way, use the {@link #enchantment(ResourceKey) enchantments} methods instead. */ - public MatchToolBuilder nbt(CompoundTag nbt) { - this.builder.hasNbt(nbt); + public MatchToolBuilder setSubPredicate(ItemSubPredicate.Type type, T predicate) { + if (type == ItemSubPredicates.ENCHANTMENTS) throw new IllegalArgumentException("Use MatchToolBuilder#enchantment"); + this.builder.withSubPredicate(type, predicate); return this; } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/loot/EntityLootProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/loot/EntityLootProviderBase.java index 4c33cb1d..09bc024d 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/loot/EntityLootProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/loot/EntityLootProviderBase.java @@ -2,11 +2,14 @@ import net.minecraft.advancements.critereon.EntityFlagsPredicate; import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.Registries; +import net.minecraft.data.loot.EntityLootSubProvider; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootTable; -import net.minecraft.world.level.storage.loot.functions.LootingEnchantFunction; +import net.minecraft.world.level.storage.loot.functions.EnchantedCountIncreaseFunction; import net.minecraft.world.level.storage.loot.functions.SmeltItemFunction; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; @@ -16,6 +19,7 @@ import org.moddingx.libx.datagen.provider.loot.entry.LootModifier; import javax.annotation.Nullable; +import java.util.stream.Stream; public abstract class EntityLootProviderBase extends LootProviderBase> { @@ -45,20 +49,37 @@ public LootModifier> looting(int max) { * @param max The maximum amount of additional drops. */ public LootModifier> looting(int min, int max) { - return this.modifier((entity, entry) -> entry.apply(LootingEnchantFunction.lootingMultiplier(UniformGenerator.between(min, max)))); + HolderLookup.Provider enchantmentHolderProvider = HolderLookup.Provider.create(Stream.of(this.registries.registry(Registries.ENCHANTMENT).asLookup())); + return this.modifier((entity, entry) -> entry.apply(EnchantedCountIncreaseFunction.lootingMultiplier(enchantmentHolderProvider, UniformGenerator.between(min, max)))); } /** * Gets a loot condition that checks, whether the killed entity was on fire. */ public LootItemCondition.Builder fire() { - return LootItemEntityPropertyCondition.hasProperties(LootContext.EntityTarget.THIS, EntityPredicate.Builder.entity().flags(EntityFlagsPredicate.Builder.flags().setOnFire(true).build())); + return LootItemEntityPropertyCondition.hasProperties(LootContext.EntityTarget.THIS, EntityPredicate.Builder.entity().flags(EntityFlagsPredicate.Builder.flags().setOnFire(true))); } /** * Gets a loot modifier that smelts the item, if the killed entity was on fire. */ public LootModifier> smeltOnFire() { - return this.modifier((entity, entry) -> entry.apply(SmeltItemFunction.smelted().when(this.fire()))); + return this.modifier((entity, entry) -> entry.apply(SmeltItemFunction.smelted().when(new GiveMeAccessToShouldSmeltLoot().accessibleShouldSmeltLoot()))); + } + + private static class GiveMeAccessToShouldSmeltLoot extends EntityLootSubProvider { + + protected GiveMeAccessToShouldSmeltLoot() { + super(FeatureFlagSet.of(), HolderLookup.Provider.create(Stream.of())); + } + + @Override + public void generate() { + // + } + + public LootItemCondition.Builder accessibleShouldSmeltLoot() { + return this.shouldSmeltLoot(); + } } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/loot/GlobalLootProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/loot/GlobalLootProviderBase.java index 2fad4c09..f477bb88 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/loot/GlobalLootProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/loot/GlobalLootProviderBase.java @@ -5,9 +5,9 @@ import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition; import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.data.GlobalLootModifierProvider; -import net.minecraftforge.common.loot.LootModifier; -import net.minecraftforge.common.loot.LootTableIdCondition; +import net.neoforged.neoforge.common.data.GlobalLootModifierProvider; +import net.neoforged.neoforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.LootTableIdCondition; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.impl.loot.modifier.AdditionLootModifier; import org.moddingx.libx.impl.loot.modifier.RemovalLootModifier; @@ -16,6 +16,7 @@ import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.function.Function; /** @@ -26,7 +27,7 @@ public abstract class GlobalLootProviderBase extends GlobalLootModifierProvider protected final ModX mod; public GlobalLootProviderBase(DatagenContext ctx) { - super(ctx.output(), ctx.mod().modid); + super(ctx.output(), CompletableFuture.completedFuture(ctx.registries().registryAccess()), ctx.mod().modid); this.mod = ctx.mod(); } @@ -133,7 +134,7 @@ public T or(LootConditionsBuilder conditions) { * Adds a condition for the queried loot table. */ public T forLootTable(String lootTableNamespace, String lootTablePath) { - return this.forLootTable(new ResourceLocation(lootTableNamespace, lootTablePath)); + return this.forLootTable(ResourceLocation.fromNamespaceAndPath(lootTableNamespace, lootTablePath)); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/loot/LootProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/loot/LootProviderBase.java index 9c223b16..6299f035 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/loot/LootProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/loot/LootProviderBase.java @@ -1,29 +1,34 @@ package org.moddingx.libx.datagen.provider.loot; import com.google.common.collect.Multimap; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.RegistrationInfo; import net.minecraft.core.Registry; -import net.minecraft.data.CachedOutput; -import net.minecraft.data.DataProvider; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.PackType; +import net.minecraft.util.ProblemReporter; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; -import net.minecraft.world.level.storage.loot.*; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.ValidationContext; import net.minecraft.world.level.storage.loot.entries.*; import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction; import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet; -import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.predicates.*; import net.minecraft.world.level.storage.loot.providers.number.BinomialDistributionGenerator; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; -import net.minecraftforge.common.data.ExistingFileHelper; import org.moddingx.libx.LibX; import org.moddingx.libx.datagen.DatagenContext; +import org.moddingx.libx.datagen.DatagenStage; import org.moddingx.libx.datagen.PackTarget; +import org.moddingx.libx.datagen.RegistrySet; import org.moddingx.libx.datagen.loot.LootBuilders; +import org.moddingx.libx.datagen.provider.RegistryProviderBase; import org.moddingx.libx.datagen.provider.loot.entry.GenericLootModifier; import org.moddingx.libx.datagen.provider.loot.entry.LootFactory; import org.moddingx.libx.datagen.provider.loot.entry.LootModifier; @@ -33,22 +38,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.nio.file.Path; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public abstract class LootProviderBase implements DataProvider { - - private static final ExistingFileHelper.IResourceType LOOT_TYPE = new ExistingFileHelper.ResourceType(PackType.SERVER_DATA, ".json", "loot_tables"); +public abstract class LootProviderBase extends RegistryProviderBase { protected final ModX mod; protected final PackTarget packTarget; - protected final ExistingFileHelper fileHelper; + protected final RegistrySet registries; protected final String folder; protected final LootContextParamSet params; protected final Supplier>> modElements; @@ -66,10 +67,11 @@ protected LootProviderBase(DatagenContext ctx, String folder, LootContextParamSe ); } - protected LootProviderBase(DatagenContext ctx, String folder, LootContextParamSet params, Supplier>> modElements, Function allElementIds) { + private LootProviderBase(DatagenContext ctx, String folder, LootContextParamSet params, Supplier>> modElements, Function allElementIds) { + super(ctx, DatagenStage.REGISTRY_SETUP); this.mod = ctx.mod(); this.packTarget = ctx.target(); - this.fileHelper = ctx.fileHelper(); + this.registries = ctx.registries(); this.folder = folder; this.params = params; this.modElements = modElements; @@ -81,9 +83,10 @@ protected LootProviderBase(DatagenContext ctx, String folder, LootContextParamSe } protected LootProviderBase(DatagenContext ctx, String folder, LootContextParamSet params, Function elementIds) { + super(ctx, DatagenStage.REGISTRY_SETUP); this.mod = ctx.mod(); this.packTarget = ctx.target(); - this.fileHelper = ctx.fileHelper(); + this.registries = ctx.registries(); this.folder = folder; this.params = params; this.modElements = () -> this.functionMap.keySet().stream().map(element -> Map.entry(elementIds.apply(element), element)); @@ -135,56 +138,42 @@ protected SimpleLootFactory element() { @Nonnull @Override public String getName() { - ResourceLocation key = LootContextParamSets.getKey(this.params); - String name = key == null ? "generic" : ("minecraft".equals(key.getNamespace()) ? key.getPath() : key.toString()); - return this.mod.modid + " " + name + " loot tables"; + return this.mod.modid + " " + this.folder + " loot tables"; } - @Nonnull @Override - public CompletableFuture run(@Nonnull CachedOutput cache) { + public void run() { + // We do not invoke super.run() + // Because of the validation needed for loot tables, we don't support registering from fields. this.setup(); Map tables = this.modElements.get() .filter(entry -> this.mod.modid.equals(entry.getKey().getNamespace())) .filter(entry -> !this.ignored.contains(entry.getValue())) .flatMap(this::resolve) - .map(entry -> Map.entry(new ResourceLocation(entry.getKey().getNamespace(), this.folder + "/" + entry.getKey().getPath()), entry.getValue())) + .map(entry -> Map.entry(ResourceLocation.fromNamespaceAndPath(entry.getKey().getNamespace(), this.folder + "/" + entry.getKey().getPath()), entry.getValue())) .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); - ValidationContext validationContext = new ValidationContext(this.params, new LootDataResolver() { - - @Nullable - @Override - @SuppressWarnings("unchecked") - public A getElement(@Nonnull LootDataId id) { - if (id.type() != LootDataType.TABLE) return null; - if (tables.containsKey(id.location())) return (A) tables.get(id.location()); - if (LootProviderBase.this.fileHelper.exists(id.location(), LOOT_TYPE)) return (A) LootTable.lootTable().build(); - return null; - } - }); - + WritableRegistry registry = this.registries.writableRegistry(Registries.LOOT_TABLE); for (Map.Entry entry : tables.entrySet()) { - entry.getValue().validate(validationContext.enterElement("{" + entry.getKey() + "}", new LootDataId<>(LootDataType.TABLE, entry.getKey()))); + registry.register(ResourceKey.create(Registries.LOOT_TABLE, entry.getKey()), entry.getValue(), RegistrationInfo.BUILT_IN); } - + + ProblemReporter.Collector problems = new ProblemReporter.Collector(); + HolderLookup.Provider lootTableHolderProvider = HolderLookup.Provider.create(Stream.of(this.registries.registry(Registries.LOOT_TABLE).asLookup())); + ValidationContext validationContext = new ValidationContext(problems, this.params, lootTableHolderProvider.asGetterLookup()); + for (Map.Entry entry : tables.entrySet()) { - this.fileHelper.trackGenerated(entry.getKey(), LOOT_TYPE); + entry.getValue().validate(validationContext.setParams(this.params).enterElement("{" + entry.getKey() + "}", ResourceKey.create(Registries.LOOT_TABLE, entry.getKey()))); } - - Multimap multimap = validationContext.getProblems(); + + Multimap multimap = problems.get(); if (!multimap.isEmpty()) { - multimap.forEach((where, what) -> LibX.logger.warn("LootTable validation problem in " + where + ": " + what)); + multimap.forEach((where, what) -> LibX.logger.warn("LootTable validation problem in " + where + ": " + what)); throw new IllegalStateException("There were problems validating the loot tables."); } - - return CompletableFuture.allOf(tables.entrySet().stream().map(entry -> { - Path path = this.packTarget.path(PackType.SERVER_DATA).resolve(entry.getKey().getNamespace()).resolve("loot_tables").resolve(entry.getKey().getPath() + ".json"); - return DataProvider.saveStable(cache, LootDataType.TABLE.parser().toJsonTree(entry.getValue()), path); - }).toArray(CompletableFuture[]::new)); } - + private Stream> resolve(Map.Entry entry) { Function loot; if (this.functionMap.containsKey(entry.getValue())) { @@ -193,7 +182,10 @@ private Stream> resolve(Map.Entry builder; } - return loot == null ? Stream.empty() : Stream.of(Map.entry(entry.getKey(), loot.apply(entry.getValue()).setParamSet(this.params).build())); + if (loot == null) return Stream.empty(); + LootTable.Builder builder = loot.apply(entry.getValue()); + if (builder.randomSequence.isEmpty()) builder.setRandomSequence(entry.getKey()); + return Stream.of(Map.entry(entry.getKey(), loot.apply(entry.getValue()).setParamSet(this.params).build())); } protected final LootModifier modifier(BiFunction, LootPoolSingletonContainer.Builder> function) { @@ -265,14 +257,14 @@ public LootModifier from(LootItemConditionalFunction.Builder function) { */ public SimpleLootFactory reference(T value) { ResourceLocation elementId = this.idResolver.apply(value); - return this.reference(new ResourceLocation(elementId.getNamespace(), this.folder + "/" + elementId.getPath())); + return this.reference(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.fromNamespaceAndPath(elementId.getNamespace(), this.folder + "/" + elementId.getPath()))); } /** * Makes a reference to another loot table. */ - public SimpleLootFactory reference(ResourceLocation lootTable) { - return SimpleLootFactory.from(LootTableReference.lootTableReference(lootTable)); + public SimpleLootFactory reference(ResourceKey lootTable) { + return SimpleLootFactory.from(NestedLootTable.lootTableReference(lootTable)); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/model/BlockStateProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/model/BlockStateProviderBase.java index 4741b6bf..4e53d51c 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/model/BlockStateProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/model/BlockStateProviderBase.java @@ -1,6 +1,7 @@ package org.moddingx.libx.datagen.provider.model; import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.CachedOutput; import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; @@ -10,13 +11,11 @@ import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.client.RenderTypeGroup; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.client.model.generators.*; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.registries.ForgeRegistries; -import org.moddingx.libx.LibX; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.generators.*; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.registries.NeoForgeRegistries; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.impl.base.decoration.blocks.*; import org.moddingx.libx.impl.datagen.model.TypedBlockModelProvider; @@ -27,7 +26,6 @@ import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.stream.Stream; @@ -41,11 +39,11 @@ */ public abstract class BlockStateProviderBase extends BlockStateProvider { - public static final ResourceLocation LEAVES_PARENT = new ResourceLocation("minecraft", "block/leaves"); - public static final ResourceLocation BUTTON_PARENT = new ResourceLocation("minecraft", "block/button"); - public static final ResourceLocation PRESSED_BUTTON_PARENT = new ResourceLocation("minecraft", "block/button_pressed"); - public static final ResourceLocation PRESSURE_PLATE_PARENT = new ResourceLocation("minecraft", "block/pressure_plate_up"); - public static final ResourceLocation PRESSED_PRESSURE_PLATE_PARENT = new ResourceLocation("minecraft", "block/pressure_plate_down"); + public static final ResourceLocation LEAVES_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/leaves"); + public static final ResourceLocation BUTTON_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/button"); + public static final ResourceLocation PRESSED_BUTTON_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/button_pressed"); + public static final ResourceLocation PRESSURE_PLATE_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/pressure_plate_up"); + public static final ResourceLocation PRESSED_PRESSURE_PLATE_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/pressure_plate_down"); protected final ModX mod; protected final PackOutput packOutput; @@ -93,6 +91,7 @@ protected void manualModel(Block b, ModelFile model) { this.customModel.put(b, model); } + @Nonnull @Override public BlockModelProvider models() { return this.models(this.currentRenderTypes); @@ -122,11 +121,11 @@ protected void setRenderType(@Nullable ResourceLocation renderTypes) { protected final void registerStatesAndModels() { this.setup(); - for (ResourceLocation id : ForgeRegistries.BLOCKS.getKeys().stream().sorted().toList()) { - Block block = ForgeRegistries.BLOCKS.getValue(id); - if (block != null && this.mod.modid.equals(id.getNamespace()) && !this.manualState.contains(block)) { + for (ResourceLocation id : BuiltInRegistries.BLOCK.keySet().stream().sorted().toList()) { + Block block = BuiltInRegistries.BLOCK.get(id); + if (this.mod.modid.equals(id.getNamespace()) && !this.manualState.contains(block)) { if (this.existingModel.contains(block)) { - this.defaultState(id, block, () -> this.models().getExistingFile(new ResourceLocation(id.getNamespace(), "block/" + id.getPath()))); + this.defaultState(id, block, () -> this.models().getExistingFile(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath()))); } else if (this.customModel.containsKey(block)) { this.defaultState(id, block, () -> this.customModel.get(block)); } else { @@ -137,8 +136,9 @@ protected final void registerStatesAndModels() { } } + @Nonnull @Override - public CompletableFuture run(CachedOutput cache) { + public CompletableFuture run(@Nonnull CachedOutput cache) { CompletableFuture mainFuture = super.run(cache); return CompletableFuture.allOf(Stream.concat(Stream.of(mainFuture), this.typedModelProviders.values().stream() .map(provider -> provider.generateAll(cache)) @@ -161,7 +161,7 @@ protected void defaultState(ResourceLocation id, Block block, Supplier state.getRenderShape() != RenderShape.MODEL)) { if (block instanceof LiquidBlock liquidBlock) { - Optional tex = fluidTextureId(liquidBlock.getFluid()); - if (tex.isPresent()) { - return this.models().getBuilder(id.getPath()).texture("particle", tex.get()); - } else { - return this.models().getBuilder(id.getPath()); - } + Optional tex = Optional.ofNullable(this.fluidTextureId(liquidBlock.fluid.getSource().getFluidType())); + return tex.map(resourceLocation -> this.models().getBuilder(id.getPath()).texture("particle", resourceLocation)) + .orElseGet(() -> this.models().getBuilder(id.getPath())); } else { return this.models().getBuilder(id.getPath()); // We don't need a model for that block. } } else if (block instanceof LeavesBlock) { - return this.models().withExistingParent(Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block)).getPath(), LEAVES_PARENT) + return this.models().withExistingParent(Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block)).getPath(), LEAVES_PARENT) .texture("all", this.blockTexture(block)) .renderType(RenderTypes.CUTOUT_MIPPED); } else { @@ -241,7 +238,7 @@ protected ModelFile defaultModel(ResourceLocation id, Block block) { * Creates a block state and models for a button. */ public void buttonBlock(Block block, ResourceLocation texture) { - ResourceLocation blockId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block)); + ResourceLocation blockId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block)); ModelFile model = this.models().withExistingParent(blockId.getPath(), BUTTON_PARENT) .texture("texture", texture); @@ -276,7 +273,7 @@ public void buttonBlock(Block block, ResourceLocation texture) { * Creates a block state and models for a pressure plate. */ public void pressurePlateBlock(Block block, ResourceLocation texture) { - ResourceLocation blockId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(block)); + ResourceLocation blockId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block)); ModelFile model = this.models().withExistingParent(blockId.getPath(), PRESSURE_PLATE_PARENT) .texture("texture", texture); @@ -291,36 +288,28 @@ public void pressurePlateBlock(Block block, ResourceLocation texture) { private static ResourceLocation textureId(ResourceLocation blockId) { Objects.requireNonNull(blockId); - return new ResourceLocation(blockId.getNamespace(), "block/" + blockId.getPath()); + return ResourceLocation.fromNamespaceAndPath(blockId.getNamespace(), "block/" + blockId.getPath()); } private static ResourceLocation textureId(ResourceLocation blockId, String suffix) { Objects.requireNonNull(blockId); - return new ResourceLocation(blockId.getNamespace(), "block/" + blockId.getPath() + "_" + suffix); + return ResourceLocation.fromNamespaceAndPath(blockId.getNamespace(), "block/" + blockId.getPath() + "_" + suffix); } - private static Optional fluidTextureId(Fluid fluid) { - try { - - IClientFluidTypeExtensions ext = IClientFluidTypeExtensions.of(fluid); - if (ext != IClientFluidTypeExtensions.DEFAULT) { - return Optional.ofNullable(ext.getStillTexture()); - } else { - // Forge no longer calls this during datagen - // so we need to do it manually - AtomicReference ref = new AtomicReference<>(null); - fluid.getFluidType().initializeClient(ref::set); - ext = ref.get(); - if (ext != null) { - return Optional.ofNullable(ext.getStillTexture()); - } else { - return Optional.empty(); - } - } - } catch (Exception | NoClassDefFoundError e) { - LibX.logger.warn("Failed to load fluid render properties", e); - return Optional.empty(); + /** + * Retrieves the texture for a given {@link FluidType}. This is used as particle texture in the default model. + * The default implementation returns {@code namespace:block/path} if it exists, otherwise throws an exception. + * Returning {@code null} causes no particle texure to be set. + */ + @Nullable + protected ResourceLocation fluidTextureId(FluidType fluidType) { + ResourceLocation id = NeoForgeRegistries.FLUID_TYPES.getKey(fluidType); + if (id == null) throw new IllegalStateException("fluid type not registered: " + fluidType); + ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath()); + if (!this.fileHelper.exists(texture, ModelProvider.TEXTURE)) { + throw new IllegalStateException("Could not find a texture for fluid " + id + ". You can provide one at " + texture + " or override fluidTextureId to use a different texture location."); } + return texture; } /** @@ -332,11 +321,11 @@ private RenderTypes() { } - public static final ResourceLocation SOLID = new ResourceLocation("minecraft", "solid"); - public static final ResourceLocation CUTOUT = new ResourceLocation("minecraft", "cutout"); - public static final ResourceLocation CUTOUT_MIPPED = new ResourceLocation("minecraft", "cutout_mipped"); - public static final ResourceLocation CUTOUT_MIPPED_ALL = new ResourceLocation("minecraft", "cutout_mipped_all"); - public static final ResourceLocation TRANSLUCENT = new ResourceLocation("minecraft", "translucent"); - public static final ResourceLocation TRIPWIRE = new ResourceLocation("minecraft", "tripwire"); + public static final ResourceLocation SOLID = ResourceLocation.fromNamespaceAndPath("minecraft", "solid"); + public static final ResourceLocation CUTOUT = ResourceLocation.fromNamespaceAndPath("minecraft", "cutout"); + public static final ResourceLocation CUTOUT_MIPPED = ResourceLocation.fromNamespaceAndPath("minecraft", "cutout_mipped"); + public static final ResourceLocation CUTOUT_MIPPED_ALL = ResourceLocation.fromNamespaceAndPath("minecraft", "cutout_mipped_all"); + public static final ResourceLocation TRANSLUCENT = ResourceLocation.fromNamespaceAndPath("minecraft", "translucent"); + public static final ResourceLocation TRIPWIRE = ResourceLocation.fromNamespaceAndPath("minecraft", "tripwire"); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/model/ItemModelProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/model/ItemModelProviderBase.java index 90fa9b3d..03a53cc7 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/model/ItemModelProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/model/ItemModelProviderBase.java @@ -1,26 +1,26 @@ package org.moddingx.libx.datagen.provider.model; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.SpawnEggItem; -import net.minecraftforge.client.extensions.common.IClientItemExtensions; -import net.minecraftforge.client.model.generators.ItemModelProvider; -import net.minecraftforge.client.model.generators.ModelFile; -import net.minecraftforge.client.model.generators.loaders.DynamicFluidContainerModelBuilder; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.world.level.block.Block; +import net.neoforged.neoforge.client.model.generators.ItemModelProvider; +import net.neoforged.neoforge.client.model.generators.ModelFile; +import net.neoforged.neoforge.client.model.generators.loaders.DynamicFluidContainerModelBuilder; import org.moddingx.libx.LibX; import org.moddingx.libx.datagen.DatagenContext; -import org.moddingx.libx.impl.RendererOnDataGenException; import org.moddingx.libx.impl.base.decoration.blocks.*; import org.moddingx.libx.mod.ModX; +import org.moddingx.libx.render.ItemStackRenderer; import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; /** * A base class for item model provider. An extending class should call the @@ -29,19 +29,20 @@ */ public abstract class ItemModelProviderBase extends ItemModelProvider { - public static final ResourceLocation GENERATED = new ResourceLocation("item/generated"); - public static final ResourceLocation HANDHELD = new ResourceLocation("item/handheld"); - public static final ResourceLocation DRIPPING_BUCKET = new ResourceLocation("forge", "bucket_drip"); + public static final ResourceLocation GENERATED = ResourceLocation.fromNamespaceAndPath("minecraft", "item/generated"); + public static final ResourceLocation HANDHELD = ResourceLocation.fromNamespaceAndPath("minecraft", "item/handheld"); + public static final ResourceLocation DRIPPING_BUCKET = ResourceLocation.fromNamespaceAndPath("neoforge", "bucket_drip"); public static final ResourceLocation SPECIAL_BLOCK_PARENT = LibX.getInstance().resource("item/base/special_block"); - public static final ResourceLocation SPAWN_EGG_PARENT = new ResourceLocation("minecraft", "item/template_spawn_egg"); - public static final ResourceLocation FENCE_PARENT = new ResourceLocation("minecraft", "block/fence_inventory"); - public static final ResourceLocation BUTTON_PARENT = new ResourceLocation("minecraft", "block/button_inventory"); - public static final ResourceLocation WALL_PARENT = new ResourceLocation("minecraft", "block/wall_inventory"); + public static final ResourceLocation SPAWN_EGG_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "item/template_spawn_egg"); + public static final ResourceLocation FENCE_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/fence_inventory"); + public static final ResourceLocation BUTTON_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/button_inventory"); + public static final ResourceLocation WALL_PARENT = ResourceLocation.fromNamespaceAndPath("minecraft", "block/wall_inventory"); protected final ModX mod; private final Set handheld = new HashSet<>(); private final Set ignored = new HashSet<>(); + private final Set specialBlocks = new HashSet<>(); public ItemModelProviderBase(DatagenContext ctx) { super(ctx.output(), ctx.mod().modid, ctx.fileHelper()); @@ -68,17 +69,24 @@ protected void manualModel(Item item) { this.ignored.add(item); } + /** + * The {@link BlockItem} of the provided {@link Block} uses a custom {@link BlockEntityWithoutLevelRenderer} such as {@link ItemStackRenderer}. + */ + protected void specialBlock(Block block) { + this.specialBlocks.add(block); + } + @Override protected void registerModels() { this.setup(); - for (ResourceLocation id : ForgeRegistries.ITEMS.getKeys().stream().sorted().toList()) { - Item item = ForgeRegistries.ITEMS.getValue(id); - if (item != null && this.mod.modid.equals(id.getNamespace()) && !this.ignored.contains(item)) { + for (ResourceLocation id : BuiltInRegistries.ITEM.keySet().stream().sorted().toList()) { + Item item = BuiltInRegistries.ITEM.get(id); + if (this.mod.modid.equals(id.getNamespace()) && !this.ignored.contains(item)) { if (item instanceof BlockItem blockItem) { this.defaultBlock(id, blockItem); } else if (this.handheld.contains(item)) { - this.withExistingParent(id.getPath(), HANDHELD).texture("layer0", new ResourceLocation(id.getNamespace(), "item/" + id.getPath())); + this.withExistingParent(id.getPath(), HANDHELD).texture("layer0", ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "item/" + id.getPath())); } else { this.defaultItem(id, item); } @@ -95,54 +103,33 @@ protected void defaultItem(ResourceLocation id, Item item) { this.withExistingParent(id.getPath(), DRIPPING_BUCKET) .texture("base", this.modLoc("item/" + id.getPath())) .customLoader(DynamicFluidContainerModelBuilder::begin) - .fluid(bucketItem.getFluid()); + .fluid(bucketItem.content); } else { - this.withExistingParent(id.getPath(), GENERATED).texture("layer0", new ResourceLocation(id.getNamespace(), "item/" + id.getPath())); + this.withExistingParent(id.getPath(), GENERATED).texture("layer0", ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "item/" + id.getPath())); } } protected void defaultBlock(ResourceLocation id, BlockItem item) { - if (isItemStackRenderer(item)) { + if (this.specialBlocks.contains(item.getBlock())) { this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(SPECIAL_BLOCK_PARENT)); } else if (item.getBlock() instanceof DecoratedFenceBlock decorated) { - ResourceLocation parentId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(decorated.parent)); - ResourceLocation texture = new ResourceLocation(parentId.getNamespace(), "block/" + parentId.getPath()); + ResourceLocation parentId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(decorated.parent)); + ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(parentId.getNamespace(), "block/" + parentId.getPath()); this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(FENCE_PARENT)).texture("texture", texture); } else if (item.getBlock() instanceof DecoratedButton decorated) { - ResourceLocation parentId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(decorated.parent)); - ResourceLocation texture = new ResourceLocation(parentId.getNamespace(), "block/" + parentId.getPath()); + ResourceLocation parentId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(decorated.parent)); + ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(parentId.getNamespace(), "block/" + parentId.getPath()); this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(BUTTON_PARENT)).texture("texture", texture); } else if (item.getBlock() instanceof DecoratedWallBlock decorated) { - ResourceLocation parentId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(decorated.parent)); - ResourceLocation texture = new ResourceLocation(parentId.getNamespace(), "block/" + parentId.getPath()); + ResourceLocation parentId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(decorated.parent)); + ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(parentId.getNamespace(), "block/" + parentId.getPath()); this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(WALL_PARENT)).texture("wall", texture); } else if (item.getBlock() instanceof DecoratedTrapdoorBlock) { - this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(new ResourceLocation(id.getNamespace(), "block/" + id.getPath() + "_bottom"))); + this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath() + "_bottom"))); } else if (item.getBlock() instanceof DecoratedDoorBlock || item.getBlock() instanceof DecoratedSign.Standing || item.getBlock() instanceof DecoratedSign.Wall || item.getBlock() instanceof DecoratedHangingSign.Ceiling || item.getBlock() instanceof DecoratedHangingSign.Wall) { - this.withExistingParent(id.getPath(), GENERATED).texture("layer0", new ResourceLocation(id.getNamespace(), "item/" + id.getPath())); + this.withExistingParent(id.getPath(), GENERATED).texture("layer0", ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "item/" + id.getPath())); } else { - this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(new ResourceLocation(id.getNamespace(), "block/" + id.getPath()))); - } - } - - private static boolean isItemStackRenderer(Item item) { - try { - IClientItemExtensions ext = IClientItemExtensions.of(item); - if (ext != IClientItemExtensions.DEFAULT) { - ext.getCustomRenderer(); - } else { - // Forge no longer calls this during datagen, - // so we need to do it manually - AtomicReference ref = new AtomicReference<>(null); - item.initializeClient(ref::set); - ext = ref.get(); - if (ext != null) ext.getCustomRenderer(); - } - } catch (RendererOnDataGenException e) { - return true; - } catch (Exception | NoClassDefFoundError e) { - return false; + this.getBuilder(id.getPath()).parent(new ModelFile.UncheckedModelFile(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "block/" + id.getPath()))); } - return false; } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/EntryBuilder.java b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/EntryBuilder.java index c45450cf..6d199cc2 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/EntryBuilder.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/EntryBuilder.java @@ -7,7 +7,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.moddingx.libx.datagen.provider.patchouli.content.CaptionContent; import org.moddingx.libx.datagen.provider.patchouli.content.TextContent; import org.moddingx.libx.datagen.provider.patchouli.page.Content; @@ -82,7 +82,7 @@ public EntryBuilder advancement(String path) { * Sets an advancement needed to unlock the entry. */ public EntryBuilder advancement(String namespace, String path) { - return this.advancement(new ResourceLocation(namespace, path)); + return this.advancement(ResourceLocation.fromNamespaceAndPath(namespace, path)); } /** @@ -127,7 +127,7 @@ public EntryBuilder flip(String anchor) { * Adds some images to the entry. The image namespaces are set to the namespace of the category, this entry belongs to. */ public EntryBuilder image(String title, String... images) { - return this.image(title, Arrays.stream(images).map(s -> new ResourceLocation(this.mod.modid, s)).toArray(ResourceLocation[]::new)); + return this.image(title, Arrays.stream(images).map(s -> ResourceLocation.fromNamespaceAndPath(this.mod.modid, s)).toArray(ResourceLocation[]::new)); } /** @@ -150,7 +150,7 @@ public EntryBuilder crafting(String path) { * and form a double recipe page. */ public EntryBuilder crafting(String namespace, String path) { - return this.crafting(new ResourceLocation(namespace, path)); + return this.crafting(ResourceLocation.fromNamespaceAndPath(namespace, path)); } /** @@ -174,7 +174,7 @@ public EntryBuilder smelting(String path) { * and form a double recipe page. */ public EntryBuilder smelting(String namespace, String path) { - return this.smelting(new ResourceLocation(namespace, path)); + return this.smelting(ResourceLocation.fromNamespaceAndPath(namespace, path)); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/PatchouliProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/PatchouliProviderBase.java index b3c6ad90..d233a709 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/PatchouliProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/PatchouliProviderBase.java @@ -5,7 +5,7 @@ import net.minecraft.data.DataProvider; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.PackTarget; import org.moddingx.libx.impl.datagen.load.DatagenFontLoader; @@ -64,7 +64,7 @@ public PatchouliProviderBase(DatagenContext ctx, BookProperties properties) { * @see CategoryBuilder */ public CategoryBuilder category(String id) { - CategoryBuilder builder = new CategoryBuilder(this.mod, new ResourceLocation(this.bookNamespace, id)); + CategoryBuilder builder = new CategoryBuilder(this.mod, ResourceLocation.fromNamespaceAndPath(this.bookNamespace, id)); this.categories.add(builder); this.categoryIds.add(id); return builder; @@ -105,7 +105,7 @@ private EntryBuilder entry(String id, String category, boolean foreignEntry) { } else { if (!this.categoryIds.contains(category)) throw new IllegalArgumentException("Unknown category: " + category); } - EntryBuilder builder = new EntryBuilder(this.mod, id, new ResourceLocation(this.bookNamespace, category)); + EntryBuilder builder = new EntryBuilder(this.mod, id, ResourceLocation.fromNamespaceAndPath(this.bookNamespace, category)); this.entries.add(builder); return builder; } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/page/PageJson.java b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/page/PageJson.java index 61167ae6..0d3f5180 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/patchouli/page/PageJson.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/patchouli/page/PageJson.java @@ -2,18 +2,22 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; +import com.mojang.serialization.Codec; import net.minecraft.client.StringSplitter; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.impl.datagen.load.DatagenFontLoader; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -26,20 +30,41 @@ public class PageJson { */ public static JsonElement stack(ItemStack stack) { StringBuilder sb = new StringBuilder(); - ResourceLocation id = ForgeRegistries.ITEMS.getKey(stack.getItem()); - if (id == null) throw new IllegalStateException("Item not registered: " + stack); + ResourceLocation id = BuiltInRegistries.ITEM.getKey(stack.getItem()); sb.append(id.getNamespace()); sb.append(":"); sb.append(id.getPath()); + sb.append(componentPatch(stack.getComponentsPatch())); if (stack.getCount() != 1) { sb.append("#"); sb.append(stack.getCount()); } - if (stack.hasTag() && !stack.getOrCreateTag().isEmpty()) { - sb.append(stack.getOrCreateTag()); - } return new JsonPrimitive(sb.toString()); } + + private static String componentPatch(DataComponentPatch patch) { + boolean empty = true; + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (Map.Entry, Optional> entry : patch.entrySet()) { + Codec codec = entry.getKey().codec(); + if (codec != null) { + if (empty) { + empty = false; + sb.append(","); + } + if (entry.getValue().isPresent()) { + @SuppressWarnings("unchecked") + Tag tag = ((Codec) codec).encodeStart(NbtOps.INSTANCE, entry.getValue().get()).getOrThrow(); + sb.append(Objects.requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(entry.getKey()))).append("=").append(tag); + } else { + sb.append("!").append(Objects.requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(entry.getKey()))); + } + } + } + sb.append("]"); + return empty ? "" : sb.toString(); + } /** * Splits the given text onto multiple full text pages. diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/DefaultExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/DefaultExtension.java index a543ace9..d1eb9fd1 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/DefaultExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/DefaultExtension.java @@ -1,7 +1,7 @@ package org.moddingx.libx.datagen.provider.recipe; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.BlockItem; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.base.decoration.DecorationType; import org.moddingx.libx.impl.datagen.recipe.DecorationRecipes; import org.moddingx.libx.mod.ModX; @@ -15,7 +15,7 @@ public interface DefaultExtension extends RecipeExtension { static void setup(ModX mod, DefaultExtension ext) { - ForgeRegistries.ITEMS.getEntries().stream() + BuiltInRegistries.ITEM.entrySet().stream() .filter(e -> mod.modid.equals(e.getKey().location().getNamespace())) .map(Map.Entry::getValue) .filter(item -> item instanceof BlockItem) diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeExtension.java index 2001a8b7..44dd3cb3 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeExtension.java @@ -1,19 +1,18 @@ package org.moddingx.libx.datagen.provider.recipe; -import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.Criterion; import net.minecraft.advancements.critereon.ItemPredicate; -import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.data.recipes.RecipeOutput; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.crafting.CompoundIngredient; +import net.neoforged.neoforge.common.crafting.CompoundIngredient; import org.moddingx.libx.mod.ModX; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; /** * A recipe extension is an interface that provides logic for a {@link RecipeProviderBase}. Custom recipe @@ -30,44 +29,44 @@ public interface RecipeExtension { * Gets the {@link RecipeProviderBase} for this extension. */ RecipeProviderBase provider(); - + /** - * Gets the {@link Consumer} for {@link FinishedRecipe finished recipes} to add recipes to. + * Gets the {@link RecipeOutput} to add recipes to. */ - Consumer consumer(); + RecipeOutput output(); /** - * Builds an {@link CriterionTriggerInstance advancement criterion} for the given {@link ItemLike item}. + * Builds an {@link Criterion advancement criterion} for the given {@link ItemLike item}. */ - CriterionTriggerInstance criterion(ItemLike item); + Criterion criterion(ItemLike item); /** - * Builds an {@link CriterionTriggerInstance advancement criterion} for the given {@link TagKey tag}. + * Builds an {@link Criterion advancement criterion} for the given {@link TagKey tag}. */ - CriterionTriggerInstance criterion(TagKey item); + Criterion criterion(TagKey item); /** - * Builds an {@link CriterionTriggerInstance advancement criterion} that requires all of the given + * Builds an {@link Criterion advancement criterion} that requires all of the given * {@link ItemPredicate items}. */ - CriterionTriggerInstance criterion(ItemPredicate... items); + Criterion criterion(ItemPredicate... items); /** * Gets a list of criteria that should be ORed, meaning that the recipe should unlock when one of * them is completed instead of all of them. */ - default List criteria(Ingredient item) { - List instances = new ArrayList<>(); - if (item.isVanilla()) { - for (Ingredient.Value entry : item.values) { + default List> criteria(Ingredient item) { + List> instances = new ArrayList<>(); + if (item.isSimple()) { + for (Ingredient.Value entry : item.getValues()) { if (entry instanceof Ingredient.ItemValue value) { - instances.add(this.criterion(ItemPredicate.Builder.item().of(value.item.getItem()).build())); + instances.add(this.criterion(ItemPredicate.Builder.item().of(value.item().getItem()).build())); } else if (entry instanceof Ingredient.TagValue value) { - instances.add(this.criterion(ItemPredicate.Builder.item().of(value.tag).build())); + instances.add(this.criterion(ItemPredicate.Builder.item().of(value.tag()).build())); } } - } else if (item instanceof CompoundIngredient cmp) { - for (Ingredient i : cmp.getChildren()) { + } else if (item.getCustomIngredient() instanceof CompoundIngredient cmp) { + for (Ingredient i : cmp.children()) { instances.addAll(this.criteria(i)); } } else { diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeProviderBase.java index eda40637..607bcae4 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RecipeProviderBase.java @@ -1,19 +1,16 @@ package org.moddingx.libx.datagen.provider.recipe; -import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance; +import net.minecraft.advancements.Criterion; import net.minecraft.advancements.critereon.ItemPredicate; -import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.recipes.RecipeOutput; import net.minecraft.data.recipes.RecipeProvider; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.crafting.ConditionalRecipe; -import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.common.crafting.conditions.TrueCondition; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.conditions.ICondition; import org.moddingx.libx.datagen.DatagenContext; -import org.moddingx.libx.impl.crafting.recipe.EmptyRecipe; import org.moddingx.libx.mod.ModX; import javax.annotation.Nonnull; @@ -21,7 +18,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; -import java.util.function.Consumer; +import java.util.concurrent.CompletableFuture; /** * Provider for all kinds of recipes. By itself does not add support for any recipes. However you can @@ -32,10 +29,10 @@ public abstract class RecipeProviderBase extends RecipeProvider implements RecipeExtension { protected final ModX mod; - private Consumer consumer; + private RecipeOutput output; public RecipeProviderBase(DatagenContext ctx) { - super(ctx.output()); + super(ctx.output(), CompletableFuture.completedFuture(ctx.registries().registryAccess())); this.mod = ctx.mod(); } @@ -55,24 +52,8 @@ protected List conditions() { } @Override - protected final void buildRecipes(@Nonnull Consumer base) { - List conditions = List.copyOf(this.conditions()); - if (conditions.isEmpty()) { - this.consumer = base; - } else { - this.consumer = recipe -> { - if (recipe.getType() == EmptyRecipe.Serializer.INSTANCE) { - base.accept(recipe); - } else { - ConditionalRecipe.Builder builder = ConditionalRecipe.builder(); - conditions.forEach(builder::addCondition); - builder.addRecipe(recipe); - builder.addCondition(TrueCondition.INSTANCE); - builder.addRecipe(EmptyRecipe.empty(recipe.getId())); - builder.build(base, recipe.getId()); - } - }; - } + protected final void buildRecipes(@Nonnull RecipeOutput output) { + this.output = output.withConditions(this.conditions().toArray(ICondition[]::new)); this.setupExtensions(); this.setup(); } @@ -114,7 +95,7 @@ private void setupExtensions() { * and the path being the registry path of the given item. */ public ResourceLocation loc(ItemLike item) { - return new ResourceLocation(this.mod.modid, Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item.asItem())).getPath()); + return ResourceLocation.fromNamespaceAndPath(this.mod.modid, Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item.asItem())).getPath()); } /** @@ -123,7 +104,7 @@ public ResourceLocation loc(ItemLike item) { * given suffix. */ public ResourceLocation loc(ItemLike item, String suffix) { - return new ResourceLocation(this.mod.modid, Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item.asItem())).getPath() + "_" + suffix); + return ResourceLocation.fromNamespaceAndPath(this.mod.modid, Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item.asItem())).getPath() + "_" + suffix); } @Override @@ -132,22 +113,22 @@ public RecipeProviderBase provider() { } @Override - public Consumer consumer() { - return this.consumer; + public RecipeOutput output() { + return Objects.requireNonNull(this.output, "Recipe output not yet available."); } @Override - public AbstractCriterionTriggerInstance criterion(ItemLike item) { + public Criterion criterion(ItemLike item) { return has(item); } @Override - public AbstractCriterionTriggerInstance criterion(TagKey item) { + public Criterion criterion(TagKey item) { return has(item); } @Override - public AbstractCriterionTriggerInstance criterion(ItemPredicate... items) { + public Criterion criterion(ItemPredicate... items) { return inventoryTrigger(items); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RemovalExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RemovalExtension.java index 74a925c1..4c9a5ca7 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/RemovalExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/RemovalExtension.java @@ -6,6 +6,6 @@ public interface RemovalExtension extends RecipeExtension { default void remove(ResourceLocation recipe) { - this.consumer().accept(EmptyRecipe.empty(recipe)); + this.output().accept(recipe, EmptyRecipe.empty(), null); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmeltingExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmeltingExtension.java index 0b92cbad..19aedc43 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmeltingExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmeltingExtension.java @@ -223,7 +223,7 @@ default void campfire(RecipeCategory category, TagKey in, ItemLike out, fl default void smelting(ResourceLocation outputId, RecipeCategory category, ItemLike in, ItemLike out, float exp, int time) { SimpleCookingRecipeBuilder.smelting(Ingredient.of(in), category, out, exp, time) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "smelting/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "smelting/" + outputId.getPath())); } /** @@ -235,7 +235,7 @@ default void blasting(ResourceLocation outputId, RecipeCategory category, ItemLi this.smelting(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.blasting(Ingredient.of(in), category, out, exp, time / 2) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "blasting/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "blasting/" + outputId.getPath())); } /** @@ -247,7 +247,7 @@ default void cooking(ResourceLocation outputId, RecipeCategory category, ItemLik this.smelting(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.smoking(Ingredient.of(in), category, out, exp, time / 2) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "cooking/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "cooking/" + outputId.getPath())); } /** @@ -259,7 +259,7 @@ default void campfire(ResourceLocation outputId, RecipeCategory category, ItemLi this.cooking(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.campfireCooking(Ingredient.of(in), category, out, exp, time * 3) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "campfire/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "campfire/" + outputId.getPath())); } /** @@ -268,7 +268,7 @@ default void campfire(ResourceLocation outputId, RecipeCategory category, ItemLi default void smelting(ResourceLocation outputId, RecipeCategory category, TagKey in, ItemLike out, float exp, int time) { SimpleCookingRecipeBuilder.smelting(Ingredient.of(in), category, out, exp, time) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "smelting/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "smelting/" + outputId.getPath())); } /** @@ -280,7 +280,7 @@ default void blasting(ResourceLocation outputId, RecipeCategory category, TagKey this.smelting(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.blasting(Ingredient.of(in), category, out, exp, time / 2) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "blasting/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "blasting/" + outputId.getPath())); } /** @@ -292,7 +292,7 @@ default void cooking(ResourceLocation outputId, RecipeCategory category, TagKey< this.smelting(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.smoking(Ingredient.of(in), category, out, exp, time / 2) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "cooking/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "cooking/" + outputId.getPath())); } /** @@ -304,6 +304,6 @@ default void campfire(ResourceLocation outputId, RecipeCategory category, TagKey this.cooking(outputId, in, out, exp, time); SimpleCookingRecipeBuilder.campfireCooking(Ingredient.of(in), category, out, exp, time * 3) .unlockedBy("has_item", this.criterion(in)) - .save(this.consumer(), new ResourceLocation(outputId.getNamespace(), "campfire/" + outputId.getPath())); + .save(this.output(), ResourceLocation.fromNamespaceAndPath(outputId.getNamespace(), "campfire/" + outputId.getPath())); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmithingExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmithingExtension.java index 231a56a2..0f2406ad 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmithingExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/SmithingExtension.java @@ -1,6 +1,6 @@ package org.moddingx.libx.datagen.provider.recipe; -import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.Criterion; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.SmithingTransformRecipeBuilder; import net.minecraft.tags.TagKey; @@ -391,10 +391,10 @@ default void smithing(RecipeCategory category, Ingredient template, Ingredient b */ default void smithing(RecipeCategory category, Ingredient template, Ingredient base, Ingredient addition, ItemLike result) { SmithingTransformRecipeBuilder builder = SmithingTransformRecipeBuilder.smithing(template, base, addition, category, result.asItem()); - List criteria = this.criteria(base); + List> criteria = this.criteria(base); for (int i = 0; i < criteria.size(); i++) { builder.unlocks("has_item" + i, criteria.get(i)); } - builder.save(this.consumer(), this.provider().loc(result, "smithing")); + builder.save(this.output(), this.provider().loc(result, "smithing")); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/StoneCuttingExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/StoneCuttingExtension.java index 102f3aa3..4e9337be 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/StoneCuttingExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/StoneCuttingExtension.java @@ -1,13 +1,13 @@ package org.moddingx.libx.datagen.provider.recipe; -import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.Criterion; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.SingleItemRecipeBuilder; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.registries.ForgeRegistries; import java.util.List; import java.util.Objects; @@ -84,7 +84,7 @@ default void stoneCutting(RecipeCategory category, ItemLike input, ItemLike outp * Adds a stone cutting recipe with the given input, output and output amount. */ default void stoneCutting(RecipeCategory category, ItemLike input, ItemLike output, int amount) { - this.stoneCutting(category, Ingredient.of(input), output, amount, "stonecutting_from_" + Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(input.asItem())).getPath()); + this.stoneCutting(category, Ingredient.of(input), output, amount, "stonecutting_from_" + Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(input.asItem())).getPath()); } /** @@ -127,10 +127,10 @@ default void stoneCutting(RecipeCategory category, Ingredient input, ItemLike ou */ default void stoneCutting(RecipeCategory category, Ingredient input, ItemLike output, int amount, String suffix) { SingleItemRecipeBuilder builder = SingleItemRecipeBuilder.stonecutting(input, category, output, amount); - List criteria = this.criteria(input); + List> criteria = this.criteria(input); for (int i = 0; i < criteria.size(); i++) { builder.unlockedBy("has_item" + i, criteria.get(i)); } - builder.save(this.consumer(), this.provider().loc(output, suffix)); + builder.save(this.output(), this.provider().loc(output, suffix)); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/CompressionExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/CompressionExtension.java index fc067ed9..840d438a 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/CompressionExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/CompressionExtension.java @@ -30,13 +30,13 @@ default void compress(RecipeCategory recipeCategory, ItemLike item, ItemLike com .pattern("aaa") .pattern("aaa") .unlockedBy("has_item", this.criterion(item)) - .save(this.consumer(), this.provider().loc(item, "compress")); + .save(this.output(), this.provider().loc(item, "compress")); if (canRevert) { ShapelessRecipeBuilder.shapeless(recipeCategory, item, 9) .requires(compressed) .unlockedBy("has_item", this.criterion(compressed)) - .save(this.consumer(), this.provider().loc(compressed, "decompress")); + .save(this.output(), this.provider().loc(compressed, "decompress")); } } @@ -58,13 +58,13 @@ default void smallCompress(RecipeCategory recipeCategory, ItemLike item, ItemLik .pattern("aa") .pattern("aa") .unlockedBy("has_item", this.criterion(item)) - .save(this.consumer(), this.provider().loc(item, "small_compress")); + .save(this.output(), this.provider().loc(item, "small_compress")); if (canRevert) { ShapelessRecipeBuilder.shapeless(recipeCategory, item, 4) .requires(compressed) .unlockedBy("has_item", this.criterion(compressed)) - .save(this.consumer(), this.provider().loc(compressed, "small_decompress")); + .save(this.output(), this.provider().loc(compressed, "small_decompress")); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/ToolExtension.java b/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/ToolExtension.java index d2b3c5d0..d39e31ed 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/ToolExtension.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/recipe/crafting/ToolExtension.java @@ -1,10 +1,10 @@ package org.moddingx.libx.datagen.provider.recipe.crafting; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.Tags; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.Tags; import org.moddingx.libx.datagen.provider.recipe.RecipeExtension; import javax.annotation.Nullable; @@ -28,10 +28,10 @@ default void makeTools(ItemLike material, @Nullable ItemLike sword, @Nullable It .pattern("m") .pattern("m") .pattern("s") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_sword") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_sword") .unlockedBy("has_item0", this.criterion(Tags.Items.RODS_WOODEN)) .unlockedBy("has_item1", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material, "sword")); + .save(this.output(), this.provider().loc(material, "sword")); } if (axe != null) { @@ -41,10 +41,10 @@ default void makeTools(ItemLike material, @Nullable ItemLike sword, @Nullable It .pattern("mm") .pattern("sm") .pattern("s ") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_axe") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_axe") .unlockedBy("has_item0", this.criterion(Tags.Items.RODS_WOODEN)) .unlockedBy("has_item1", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material, "axe")); + .save(this.output(), this.provider().loc(material, "axe")); } if (pick != null) { @@ -54,10 +54,10 @@ default void makeTools(ItemLike material, @Nullable ItemLike sword, @Nullable It .pattern("mmm") .pattern(" s ") .pattern(" s ") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_pick") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_pick") .unlockedBy("has_item0", this.criterion(Tags.Items.RODS_WOODEN)) .unlockedBy("has_item1", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material, "pick")); + .save(this.output(), this.provider().loc(material, "pick")); } if (shovel != null) { @@ -67,10 +67,10 @@ default void makeTools(ItemLike material, @Nullable ItemLike sword, @Nullable It .pattern("m") .pattern("s") .pattern("s") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_shovel") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_shovel") .unlockedBy("has_item0", this.criterion(Tags.Items.RODS_WOODEN)) .unlockedBy("has_item1", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material, "shovel")); + .save(this.output(), this.provider().loc(material, "shovel")); } if (hoe != null) { @@ -80,10 +80,10 @@ default void makeTools(ItemLike material, @Nullable ItemLike sword, @Nullable It .pattern("mm") .pattern("s ") .pattern("s ") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_hoe") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_hoe") .unlockedBy("has_item0", this.criterion(Tags.Items.RODS_WOODEN)) .unlockedBy("has_item1", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material, "hoe")); + .save(this.output(), this.provider().loc(material, "hoe")); } } @@ -98,9 +98,9 @@ default void makeArmor(ItemLike material, @Nullable ItemLike helmet, @Nullable I .define('m', material) .pattern("mmm") .pattern("m m") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_helmet") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_helmet") .unlockedBy("has_item", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material.asItem(), "helmet")); + .save(this.output(), this.provider().loc(material.asItem(), "helmet")); } if (chestplate != null) { @@ -109,9 +109,9 @@ default void makeArmor(ItemLike material, @Nullable ItemLike helmet, @Nullable I .pattern("m m") .pattern("mmm") .pattern("mmm") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_chestplate") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_chestplate") .unlockedBy("has_item", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material.asItem(), "chestplate")); + .save(this.output(), this.provider().loc(material.asItem(), "chestplate")); } if (leggings != null) { @@ -120,9 +120,9 @@ default void makeArmor(ItemLike material, @Nullable ItemLike helmet, @Nullable I .pattern("mmm") .pattern("m m") .pattern("m m") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_leggings") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_leggings") .unlockedBy("has_item", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material.asItem(), "leggings")); + .save(this.output(), this.provider().loc(material.asItem(), "leggings")); } if (boots != null) { @@ -130,9 +130,9 @@ default void makeArmor(ItemLike material, @Nullable ItemLike helmet, @Nullable I .define('m', material) .pattern("m m") .pattern("m m") - .group(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(material.asItem())) + "_boots") + .group(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(material.asItem())) + "_boots") .unlockedBy("has_item", this.criterion(material)) - .save(this.consumer(), this.provider().loc(material.asItem(), "boots")); + .save(this.output(), this.provider().loc(material.asItem(), "boots")); } } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/AnyTemplateProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/AnyTemplateProviderBase.java index 02686925..bff1c4e7 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/AnyTemplateProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/AnyTemplateProviderBase.java @@ -7,6 +7,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraft.world.level.levelgen.structure.pools.*; +import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.DatagenStage; @@ -15,6 +16,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; /** * Base class for {@link TemplateProviderBase} and {@link TemplateExtensionProviderBase}. These have been split up as @@ -30,10 +32,12 @@ public abstract class TemplateBuilder> { private final List elements; private StructureTemplatePool.Projection currentProjection; + private Optional liquidOverride; protected TemplateBuilder() { this.elements = new ArrayList<>(); this.currentProjection = StructureTemplatePool.Projection.RIGID; + this.liquidOverride = Optional.empty(); } protected abstract T self(); @@ -50,6 +54,22 @@ public T projection(StructureTemplatePool.Projection projection) { return this.self(); } + /** + * Resets the {@link LiquidSettings liquid settings} override back to default. + */ + public T defaultLiquid() { + this.liquidOverride = Optional.empty(); + return this.self(); + } + + /** + * Overrides the {@link LiquidSettings liquid settings} used to place templates. + */ + public T overrideLiquid(LiquidSettings liquidSettings) { + this.liquidOverride = Optional.of(liquidSettings); + return this.self(); + } + /** * Add an empty template to this pool. */ @@ -145,7 +165,7 @@ public T single(String namespace, String path, Holder pr * Add a single pool element to this pool. */ public T single(int weight, String namespace, String path, Holder processor) { - return this.single(weight, new ResourceLocation(namespace, path), processor); + return this.single(weight, ResourceLocation.fromNamespaceAndPath(namespace, path), processor); } /** @@ -159,7 +179,7 @@ public T single(ResourceLocation templateId, Holder proc * Add a single pool element to this pool. */ public T single(int weight, ResourceLocation templateId, Holder processor) { - return this.element(weight, new SinglePoolElement(Either.left(templateId), processor, this.currentProjection)); + return this.element(weight, new SinglePoolElement(Either.left(templateId), processor, this.currentProjection, this.liquidOverride)); } /** @@ -226,7 +246,7 @@ public T legacy(String namespace, String path, Holder pr * Add a legacy pool element to this pool. */ public T legacy(int weight, String namespace, String path, Holder processor) { - return this.legacy(weight, new ResourceLocation(namespace, path), processor); + return this.legacy(weight, ResourceLocation.fromNamespaceAndPath(namespace, path), processor); } /** @@ -240,7 +260,7 @@ public T legacy(ResourceLocation templateId, Holder proc * Add a legacy pool element to this pool. */ public T legacy(int weight, ResourceLocation templateId, Holder processor) { - return this.element(weight, new LegacySinglePoolElement(Either.left(templateId), processor, this.currentProjection)); + return this.element(weight, new LegacySinglePoolElement(Either.left(templateId), processor, this.currentProjection, this.liquidOverride)); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/BiomeModifierProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/BiomeModifierProviderBase.java index 8334bfd4..8a7b2d13 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/BiomeModifierProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/BiomeModifierProviderBase.java @@ -2,15 +2,16 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.placement.PlacedFeature; -import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.common.world.ForgeBiomeModifiers; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.world.BiomeModifier; +import net.neoforged.neoforge.common.world.BiomeModifiers; +import net.neoforged.neoforge.registries.NeoForgeRegistries; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.DatagenStage; import org.moddingx.libx.datagen.provider.RegistryProviderBase; @@ -36,7 +37,7 @@ public final String getName() { } public Holder modifier(BiomeModifier modifier) { - return this.registries.writableRegistry(ForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); + return this.registries.writableRegistry(NeoForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); } /** @@ -124,11 +125,11 @@ public FeaturesBuilder feature(Holder feature) { public Holder build() { BiomeModifier modifier; if (this.remove) { - modifier = new ForgeBiomeModifiers.RemoveFeaturesBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.features)), Set.copyOf(this.steps)); + modifier = new BiomeModifiers.RemoveFeaturesBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.features)), Set.copyOf(this.steps)); } else { - modifier = new ForgeBiomeModifiers.AddFeaturesBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.features)), this.steps.iterator().next()); + modifier = new BiomeModifiers.AddFeaturesBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.features)), this.steps.iterator().next()); } - return BiomeModifierProviderBase.this.registries.writableRegistry(ForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); + return BiomeModifierProviderBase.this.registries.writableRegistry(NeoForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); } } @@ -159,8 +160,8 @@ public AddMobSpawnsBuilder spawn(MobSpawnSettings.SpawnerData spawn) { * {@code public}, non-{@code static} field inside the provider. */ public Holder build() { - BiomeModifier modifier = new ForgeBiomeModifiers.AddSpawnsBiomeModifier(this.biomes, List.copyOf(this.spawns)); - return BiomeModifierProviderBase.this.registries.writableRegistry(ForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); + BiomeModifier modifier = new BiomeModifiers.AddSpawnsBiomeModifier(this.biomes, List.copyOf(this.spawns)); + return BiomeModifierProviderBase.this.registries.writableRegistry(NeoForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); } } @@ -175,7 +176,7 @@ private RemoveMobSpawnsBuilder(HolderSet biomes) { } public RemoveMobSpawnsBuilder entity(EntityType type) { - this.entities.add(BiomeModifierProviderBase.this.holder(ForgeRegistries.ENTITY_TYPES.getResourceKey(type).orElseThrow())); + this.entities.add(BiomeModifierProviderBase.this.holder(BuiltInRegistries.ENTITY_TYPE.getResourceKey(type).orElseThrow())); return this; } @@ -187,8 +188,8 @@ public RemoveMobSpawnsBuilder entity(EntityType type) { * {@code public}, non-{@code static} field inside the provider. */ public Holder build() { - BiomeModifier modifier = new ForgeBiomeModifiers.RemoveSpawnsBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.entities))); - return BiomeModifierProviderBase.this.registries.writableRegistry(ForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); + BiomeModifier modifier = new BiomeModifiers.RemoveSpawnsBiomeModifier(this.biomes, HolderSet.direct(List.copyOf(this.entities))); + return BiomeModifierProviderBase.this.registries.writableRegistry(NeoForgeRegistries.Keys.BIOME_MODIFIERS).createIntrusiveHolder(modifier); } } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/DimensionTypeProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/DimensionTypeProviderBase.java index 7bb6738e..5b4eb6e7 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/DimensionTypeProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/DimensionTypeProviderBase.java @@ -134,7 +134,7 @@ public DimensionTypeBuilder effects(String path) { } public DimensionTypeBuilder effects(String namespace, String path) { - return this.effects(new ResourceLocation(namespace, path)); + return this.effects(ResourceLocation.fromNamespaceAndPath(namespace, path)); } public DimensionTypeBuilder effects(ResourceLocation id) { diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/NoiseProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/NoiseProviderBase.java index 560e3b56..9e4a8d57 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/NoiseProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/NoiseProviderBase.java @@ -4,9 +4,10 @@ import it.unimi.dsi.fastutil.doubles.DoubleList; import net.minecraft.core.Holder; import net.minecraft.core.HolderGetter; +import net.minecraft.core.RegistrationInfo; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; -import net.minecraft.data.worldgen.BootstapContext; +import net.minecraft.data.worldgen.BootstrapContext; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.block.Block; @@ -22,6 +23,7 @@ import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * SandBox provider for noise related data. @@ -381,13 +383,13 @@ private NoiseRouter build() { } } - private class Bootstrap implements BootstapContext { + private class Bootstrap implements BootstrapContext { @Nonnull @Override @SuppressWarnings({ "unchecked", "rawtypes", "RedundantCast" }) public Holder.Reference register(@Nonnull ResourceKey key, @Nonnull T value, @Nonnull Lifecycle lifecycle) { - return NoiseProviderBase.this.registries.writableRegistry((ResourceKey) ResourceKey.createRegistryKey(key.registry())).register(key, value, lifecycle); + return NoiseProviderBase.this.registries.writableRegistry((ResourceKey) ResourceKey.createRegistryKey(key.registry())).register(key, value, new RegistrationInfo(Optional.empty(), lifecycle)); } @Nonnull diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/StructureProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/StructureProviderBase.java index fc662814..c22ded97 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/StructureProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/StructureProviderBase.java @@ -3,6 +3,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.MobCategory; @@ -15,15 +16,16 @@ import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureSpawnOverride; import net.minecraft.world.level.levelgen.structure.TerrainAdjustment; +import net.minecraft.world.level.levelgen.structure.pools.DimensionPadding; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; +import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasBinding; import net.minecraft.world.level.levelgen.structure.structures.JigsawStructure; +import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.datagen.DatagenStage; import org.moddingx.libx.datagen.provider.RegistryProviderBase; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Function; /** @@ -66,6 +68,9 @@ public class JigsawBuilder { private HeightProvider startHeight; private Heightmap.Types heightRelativeTo; private boolean expansionHack; + private final List aliases; + private DimensionPadding dimensionPading; + private LiquidSettings liquidSettings; private JigsawBuilder(Holder startPool) { this.startPool = startPool; @@ -75,6 +80,9 @@ private JigsawBuilder(Holder startPool) { this.startHeight = ConstantHeight.of(VerticalAnchor.absolute(0)); this.heightRelativeTo = Heightmap.Types.WORLD_SURFACE_WG; this.expansionHack = false; + this.aliases = new ArrayList<>(); + this.dimensionPading = DimensionPadding.ZERO; + this.liquidSettings = LiquidSettings.APPLY_WATERLOGGING; } /** @@ -142,11 +150,46 @@ public JigsawBuilder expansionHack() { return this; } + /** + * Add a {@link PoolAliasBinding} to the list of aliases. + */ + public JigsawBuilder alias(ResourceKey newName, ResourceKey aliasedTo) { + this.aliases.add(PoolAliasBinding.direct(newName, aliasedTo)); + return this; + } + + /** + * Add a {@link PoolAliasBinding} to the list of aliases. + */ + public JigsawBuilder alias(PoolAliasBinding alias) { + this.aliases.add(alias); + return this; + } + + /** + * Set the minimum padding relative to the dimensions logical height. + */ + public JigsawBuilder dimensionPadding(int bottom, int top) { + this.dimensionPading = new DimensionPadding(bottom, top); + return this; + } + + /** + * Disable waterlogging of waterloggable blocks when they are be placed in water. + */ + public JigsawBuilder noWaterLogging() { + this.liquidSettings = LiquidSettings.IGNORE_WATERLOGGING; + return this; + } + /** * Returns a builder for the structure settings. */ public StructureSettingsBuilder structure() { - return StructureProviderBase.this.forFactory(settings -> new JigsawStructure(settings, this.startPool, Optional.ofNullable(this.centerJigsawBlockNameInStartPool), this.maxNestingDepth, this.startHeight, this.expansionHack, Optional.ofNullable(this.heightRelativeTo), this.maxDistanceFromCenter)); + return StructureProviderBase.this.forFactory(settings -> new JigsawStructure( + settings, this.startPool, Optional.ofNullable(this.centerJigsawBlockNameInStartPool), this.maxNestingDepth, + this.startHeight, this.expansionHack, Optional.ofNullable(this.heightRelativeTo), this.maxDistanceFromCenter, + List.copyOf(this.aliases), this.dimensionPading, this.liquidSettings)); } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/SurfaceProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/SurfaceProviderBase.java index c2bf959a..8d41b273 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/sandbox/SurfaceProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/sandbox/SurfaceProviderBase.java @@ -1,7 +1,7 @@ package org.moddingx.libx.datagen.provider.sandbox; -import com.mojang.serialization.Lifecycle; import net.minecraft.core.Holder; +import net.minecraft.core.RegistrationInfo; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; @@ -66,7 +66,7 @@ public Holder biome(Holder biome, SurfaceRules.RuleSource.. */ public Holder biome(ResourceKey biome, SurfaceRules.RuleSource... rules) { BiomeSurface surface = new BiomeSurface(of(rules)); - return this.registries.writableRegistry(SandBox.BIOME_SURFACE).register(ResourceKey.create(SandBox.BIOME_SURFACE, biome.location()), surface, Lifecycle.stable()); + return this.registries.writableRegistry(SandBox.BIOME_SURFACE).register(ResourceKey.create(SandBox.BIOME_SURFACE, biome.location()), surface, RegistrationInfo.BUILT_IN); } private static SurfaceRules.RuleSource of(SurfaceRules.RuleSource[] rules) { diff --git a/src/main/java/org/moddingx/libx/datagen/provider/tags/CommonTagsProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/tags/CommonTagsProviderBase.java index 9a398441..3717e4e1 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/tags/CommonTagsProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/tags/CommonTagsProviderBase.java @@ -1,6 +1,7 @@ package org.moddingx.libx.datagen.provider.tags; import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; @@ -14,9 +15,8 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.common.data.BlockTagsProvider; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.data.BlockTagsProvider; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.apache.commons.lang3.tuple.Pair; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.impl.datagen.tags.DecorationTags; @@ -68,7 +68,7 @@ public CommonTagsProviderBase(DatagenContext ctx) { private void doSetup() { if (this.getClass() == InternalTagProvider.class) this.initInternalTags(); this.setup(); - ForgeRegistries.BLOCKS.getEntries().stream() + BuiltInRegistries.BLOCK.entrySet().stream() .filter(entry -> this.mod.modid.equals(entry.getKey().location().getNamespace())) .sorted(Map.Entry.comparingByKey(Comparator.comparing(ResourceKey::location))) .map(Map.Entry::getValue) @@ -76,12 +76,12 @@ private void doSetup() { DecorationTags.addTags(block, this, this::initInternalTags); this.defaultBlockTags(block); }); - ForgeRegistries.ITEMS.getEntries().stream() + BuiltInRegistries.ITEM.entrySet().stream() .filter(entry -> this.mod.modid.equals(entry.getKey().location().getNamespace())) .sorted(Map.Entry.comparingByKey(Comparator.comparing(ResourceKey::location))) .map(Map.Entry::getValue) .forEach(this::defaultItemTags); - ForgeRegistries.FLUIDS.getEntries().stream() + BuiltInRegistries.FLUID.entrySet().stream() .filter(entry -> this.mod.modid.equals(entry.getKey().location().getNamespace())) .sorted(Map.Entry.comparingByKey(Comparator.comparing(ResourceKey::location))) .map(Map.Entry::getValue) @@ -192,10 +192,7 @@ protected void addTags(@Nonnull HolderLookup.Provider lookupProvider) { for (Pair, TagKey> copy : CommonTagsProviderBase.this.fluidCopies) { IntrinsicTagAppender builder = this.tag(copy.getRight()); for (ResourceLocation entry : CommonTagsProviderBase.this.fluidTags.getTagInfo(copy.getLeft())) { - Fluid fluid = ForgeRegistries.FLUIDS.getValue(entry); - if (fluid != null) { - builder.add(fluid.defaultFluidState().createLegacyBlock().getBlock()); - } + BuiltInRegistries.FLUID.getOptional(entry).ifPresent(fluid -> builder.add(fluid.defaultFluidState().createLegacyBlock().getBlock())); } } } diff --git a/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureBuilder.java b/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureBuilder.java index 5d60b23e..ceb3024f 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureBuilder.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureBuilder.java @@ -83,7 +83,7 @@ public TextureBuilder addImage(String loc, int defaultWidth, int defaultHeight) * Adds a required texture which has the given width and height by default. */ public TextureBuilder addTexture(ResourceLocation loc, int defaultWidth, int defaultHeight) { - return this.addImage(new ResourceLocation(loc.getNamespace(), "textures/" + loc.getPath() + ".png"), defaultWidth, defaultHeight); + return this.addImage(ResourceLocation.fromNamespaceAndPath(loc.getNamespace(), "textures/" + loc.getPath() + ".png"), defaultWidth, defaultHeight); } /** @@ -113,7 +113,7 @@ public TextureBuilder addFake(ResourceLocation loc, BufferedImage image, int sca * @param loc A fake image id. */ public TextureBuilder addFakeTexture(ResourceLocation loc, ResourceLocation texLoc, UnaryOperator image) { - return this.addFakeImage(loc, new ResourceLocation(texLoc.getNamespace(), "textures/" + texLoc.getPath() + ".png"), image); + return this.addFakeImage(loc, ResourceLocation.fromNamespaceAndPath(texLoc.getNamespace(), "textures/" + texLoc.getPath() + ".png"), image); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureProviderBase.java b/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureProviderBase.java index f18e2d79..61ce06c4 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureProviderBase.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/texture/TextureProviderBase.java @@ -1,12 +1,12 @@ package org.moddingx.libx.datagen.provider.texture; import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.properties.WoodType; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.datagen.DatagenContext; import org.moddingx.libx.impl.datagen.texture.HangingSignTextureFactory; import org.moddingx.libx.impl.datagen.texture.SignTextureFactory; @@ -90,7 +90,7 @@ public void image(String loc, TextureFactory factory) { * Adds a texture that should be generated. */ public void texture(ResourceLocation loc, TextureFactory factory) { - this.image(new ResourceLocation(loc.getNamespace(), "textures/" + loc.getPath() + ".png"), factory); + this.image(ResourceLocation.fromNamespaceAndPath(loc.getNamespace(), "textures/" + loc.getPath() + ".png"), factory); } /** @@ -104,11 +104,11 @@ public void image(ResourceLocation loc, TextureFactory factory) { * Generates a sign texture for the given {@link WoodType} with the given two blocks as log and planks. */ public void sign(WoodType wood, Block log, Block planks) { - ResourceLocation logId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(log)); - ResourceLocation planksId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(planks)); + ResourceLocation logId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(log)); + ResourceLocation planksId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(planks)); this.sign(wood, - new ResourceLocation(logId.getNamespace(), "block/" + logId.getPath()), - new ResourceLocation(planksId.getNamespace(), "block/" + planksId.getPath()) + ResourceLocation.fromNamespaceAndPath(logId.getNamespace(), "block/" + logId.getPath()), + ResourceLocation.fromNamespaceAndPath(planksId.getNamespace(), "block/" + planksId.getPath()) ); } @@ -116,8 +116,8 @@ public void sign(WoodType wood, Block log, Block planks) { * Generates a sign texture for the given {@link WoodType} with the given two textures as log and planks. */ public void sign(WoodType wood, ResourceLocation log, ResourceLocation planks) { - ResourceLocation woodId = new ResourceLocation(wood.name()); - this.sign(new ResourceLocation(woodId.getNamespace(), "entity/signs/" + woodId.getPath()), log, planks); + ResourceLocation woodId = ResourceLocation.parse(wood.name()); + this.sign(ResourceLocation.fromNamespaceAndPath(woodId.getNamespace(), "entity/signs/" + woodId.getPath()), log, planks); } /** @@ -131,16 +131,16 @@ public void sign(ResourceLocation signTexture, ResourceLocation log, ResourceLoc * Generates a hanging sign texture for the given {@link WoodType} with the given block as stripped log. */ public void hangingSign(WoodType wood, Block strippedLog) { - ResourceLocation logId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(strippedLog)); - this.hangingSign(wood, new ResourceLocation(logId.getNamespace(), "block/" + logId.getPath())); + ResourceLocation logId = Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(strippedLog)); + this.hangingSign(wood, ResourceLocation.fromNamespaceAndPath(logId.getNamespace(), "block/" + logId.getPath())); } /** * Generates a hanging sign texture for the given {@link WoodType} with the given texture as stripped log. */ public void hangingSign(WoodType wood, ResourceLocation strippedLog) { - ResourceLocation woodId = new ResourceLocation(wood.name()); - this.hangingSign(new ResourceLocation(woodId.getNamespace(), "entity/signs/hanging/" + woodId.getPath()), strippedLog); + ResourceLocation woodId = ResourceLocation.parse(wood.name()); + this.hangingSign(ResourceLocation.fromNamespaceAndPath(woodId.getNamespace(), "entity/signs/hanging/" + woodId.getPath()), strippedLog); } /** diff --git a/src/main/java/org/moddingx/libx/datagen/provider/texture/Textures.java b/src/main/java/org/moddingx/libx/datagen/provider/texture/Textures.java index 20b039d7..9af4177c 100644 --- a/src/main/java/org/moddingx/libx/datagen/provider/texture/Textures.java +++ b/src/main/java/org/moddingx/libx/datagen/provider/texture/Textures.java @@ -58,7 +58,7 @@ public int imageScale(String loc) { * scaled up to match the target scale. */ public int textureScale(ResourceLocation loc) { - return this.imageScale(new ResourceLocation(loc.getNamespace(), "textures/" + loc.getPath() + ".png")); + return this.imageScale(ResourceLocation.fromNamespaceAndPath(loc.getNamespace(), "textures/" + loc.getPath() + ".png")); } /** @@ -92,7 +92,7 @@ public BufferedImage image(String loc) { * Gets a preloaded source texture. */ public BufferedImage texture(ResourceLocation loc) { - return this.image(new ResourceLocation(loc.getNamespace(), "textures/" + loc.getPath() + ".png")); + return this.image(ResourceLocation.fromNamespaceAndPath(loc.getNamespace(), "textures/" + loc.getPath() + ".png")); } /** diff --git a/src/main/java/org/moddingx/libx/datapack/DataLoader.java b/src/main/java/org/moddingx/libx/datapack/DataLoader.java index d27cff7f..df0149e1 100644 --- a/src/main/java/org/moddingx/libx/datapack/DataLoader.java +++ b/src/main/java/org/moddingx/libx/datapack/DataLoader.java @@ -15,7 +15,6 @@ import net.minecraft.server.packs.resources.ResourceManager; import org.apache.commons.io.IOUtils; import org.moddingx.libx.LibX; -import org.moddingx.libx.codec.CodecHelper; import javax.annotation.Nullable; import java.io.IOException; @@ -51,7 +50,7 @@ public static Map loadJson(ResourceManager rm, String b return loadJson(rm, basePath, (id, json) -> { DataResult result = codec.decode(JsonOps.INSTANCE, json).map(Pair::getFirst); if (result.result().isPresent()) return result.result().get(); - String err = result.error().map(DataResult.PartialResult::message).orElse("Unknown error"); + String err = result.error().map(DataResult.Error::message).orElse("Unknown error"); if (err.length() > 100) err = err.substring(0, 100) + " ..."; LibX.logger.error("Failed to load data entry " + id + ": " + err); return null; @@ -98,7 +97,7 @@ public static Map collectText(List resou * resource are mapped to a {@link JsonElement} first. */ public static Map collectJson(List resources, Codec codec) throws IOException { - return collectJson(resources, (id, json) -> CodecHelper.JSON.read(codec, json)); + return collectJson(resources, (id, json) -> codec.decode(JsonOps.INSTANCE, json).getOrThrow(IOException::new).getFirst()); } /** @@ -160,8 +159,8 @@ public static List locate(ResourceManager rm, String fullPath, St Set namespaces = rm.getNamespaces(); ImmutableList.Builder list = ImmutableList.builder(); for (String namespace : namespaces) { - ResourceLocation location = new ResourceLocation(namespace, fullPath); - rm.getResource(location).ifPresent(res -> list.add(new ResourceEntry(new ResourceLocation(namespace, idPath), res))); + ResourceLocation location = ResourceLocation.fromNamespaceAndPath(namespace, fullPath); + rm.getResource(location).ifPresent(res -> list.add(new ResourceEntry(ResourceLocation.fromNamespaceAndPath(namespace, idPath), res))); } return list.build(); } @@ -185,7 +184,7 @@ public static List locate(ResourceManager rm, String basePath, @N if (suffix != null && !id.getPath().endsWith("." + suffix)) continue; String realPath = id.getPath().substring(basePath.length() + 1, id.getPath().length() - (suffix == null ? 0 : (suffix.length() + 1))); if (realPath.isEmpty() || (!recursive && realPath.contains("/"))) continue; - list.add(new ResourceEntry(new ResourceLocation(id.getNamespace(), realPath), entry.getValue())); + list.add(new ResourceEntry(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), realPath), entry.getValue())); } return list.build(); } diff --git a/src/main/java/org/moddingx/libx/datapack/DatapackHelper.java b/src/main/java/org/moddingx/libx/datapack/DatapackHelper.java index e8565e03..28e51616 100644 --- a/src/main/java/org/moddingx/libx/datapack/DatapackHelper.java +++ b/src/main/java/org/moddingx/libx/datapack/DatapackHelper.java @@ -7,14 +7,10 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.IoSupplier; -import net.minecraftforge.forgespi.locating.IModFile; import org.moddingx.libx.impl.datapack.LibXPack; import java.io.*; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Locale; /** * Adds some utilities for creating custom dynamic datapacks. @@ -45,14 +41,14 @@ public static String registryPath(ResourceKey key) { * Creates a supplier that can be repeatedly called to create new {@link InputStream}s for * a dynamically generated {@code pack.mcmeta} based on the given mod file. */ - public static IoSupplier generatePackMeta(IModFile file, String description, PackType packType) { + public static IoSupplier generatePackMeta(String description, PackType packType) { try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(bout, StandardCharsets.UTF_8); JsonObject packFile = new JsonObject(); JsonObject packSection = new JsonObject(); packSection.addProperty("description", description); - packSection.addProperty("pack_format", getPackFormat(file, packType)); + packSection.addProperty("pack_format", LibXPack.PACK_CONFIG.get(packType).version()); packFile.add("pack", packSection); writer.write(GSON.toJson(packFile) + "\n"); writer.close(); @@ -63,19 +59,4 @@ public static IoSupplier generatePackMeta(IModFile file, String des throw new RuntimeException("Failed to create dynamic pack.mcmeta", e); } } - - private static int getPackFormat(IModFile mod, PackType packType) { - try { - Path path = mod.findResource("pack.mcmeta"); - if (!Files.exists(path)) return LibXPack.PACK_CONFIG.get(packType).version(); - try (Reader in = Files.newBufferedReader(path)) { - JsonObject packInfo = GSON.fromJson(in, JsonObject.class).get("pack").getAsJsonObject(); - String specificKey = "forge:" + packType.name().toLowerCase(Locale.ROOT) + "_pack_format"; - if (packInfo.has(specificKey)) return packInfo.get(specificKey).getAsInt(); - return packInfo.get("pack_format").getAsInt(); - } - } catch (Exception e) { - return LibXPack.PACK_CONFIG.get(packType).version(); - } - } } diff --git a/src/main/java/org/moddingx/libx/datapack/DynamicPacks.java b/src/main/java/org/moddingx/libx/datapack/DynamicPacks.java index 37efd8ff..711f02f6 100644 --- a/src/main/java/org/moddingx/libx/datapack/DynamicPacks.java +++ b/src/main/java/org/moddingx/libx/datapack/DynamicPacks.java @@ -12,7 +12,7 @@ * the name of your dynamic resource pack. Inside this folder you can put the content that normally is in the * {@code assets} folder. The resource pack is shown in the resource pack selection menu and can be activated based * on the users preference. - * A {@code pack.mcmeta} file is not required and if you provide one it'll be ignored. + * A {@code pack.mcmeta} file is not required and if you provide one it'll be ignored. Neither are overlays. * * A dynamic datapack must be located in {@code libxdata/[name]} inside your JAR file where {@code [name]} is * the name of your dynamic datapack. Inside this folder you can put the content that normally is in the @@ -36,13 +36,13 @@ private DynamicPacks(DynamicPackLocator locator) { * Enables a dynamic pack. */ public void enablePack(String modId, String packName) { - this.locator.enablePack(new ResourceLocation(modId, packName)); + this.locator.enablePack(ResourceLocation.fromNamespaceAndPath(modId, packName)); } /** * Gets tests whether a dynamic pack is enabled. */ public boolean isEnabled(String modId, String packName) { - return this.locator.isEnabled(new ResourceLocation(modId, packName)); + return this.locator.isEnabled(ResourceLocation.fromNamespaceAndPath(modId, packName)); } } diff --git a/src/main/java/org/moddingx/libx/event/ConfigLoadedEvent.java b/src/main/java/org/moddingx/libx/event/ConfigLoadedEvent.java index 24e59d84..5aead0b7 100644 --- a/src/main/java/org/moddingx/libx/event/ConfigLoadedEvent.java +++ b/src/main/java/org/moddingx/libx/event/ConfigLoadedEvent.java @@ -1,7 +1,7 @@ package org.moddingx.libx.event; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.eventbus.api.Event; +import net.neoforged.bus.api.Event; import org.moddingx.libx.config.ConfigManager; import javax.annotation.Nullable; diff --git a/src/main/java/org/moddingx/libx/event/InteractBlockEmptyHandEvent.java b/src/main/java/org/moddingx/libx/event/InteractBlockEmptyHandEvent.java index e42f78b3..2a19eefa 100644 --- a/src/main/java/org/moddingx/libx/event/InteractBlockEmptyHandEvent.java +++ b/src/main/java/org/moddingx/libx/event/InteractBlockEmptyHandEvent.java @@ -5,8 +5,9 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.eventbus.api.Event; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; /** * Fired on right click with an empty hand but after the block action was processed. If this @@ -20,7 +21,7 @@ * propagate to the offhand. So in order to swing the main hand, the event for the main hand has to * return {@link InteractionResult#SUCCESS} and for the offhand {@link InteractionResult#PASS}. */ -public class InteractBlockEmptyHandEvent extends Event { +public class InteractBlockEmptyHandEvent extends Event implements ICancellableEvent { private final ServerPlayer player; private final Level level; @@ -60,9 +61,4 @@ public InteractionResult getCancellationResult() { public void setCancellationResult(InteractionResult cancellationResult) { this.cancellationResult = cancellationResult; } - - @Override - public boolean isCancelable() { - return true; - } } diff --git a/src/main/java/org/moddingx/libx/event/package-info.java b/src/main/java/org/moddingx/libx/event/package-info.java index e8ca8bf1..5c64adc8 100644 --- a/src/main/java/org/moddingx/libx/event/package-info.java +++ b/src/main/java/org/moddingx/libx/event/package-info.java @@ -1,4 +1,4 @@ /** - * Contains events that are fored on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS forge event bus} + * Contains events that are fored on the {@link net.neoforged.neoforge.common.NeoForge#EVENT_BUS neoforge event bus} */ -package org.moddingx.libx.event; \ No newline at end of file +package org.moddingx.libx.event; diff --git a/src/main/java/org/moddingx/libx/impl/BlockEntityUpdateQueue.java b/src/main/java/org/moddingx/libx/impl/BlockEntityUpdateQueue.java index 168dc161..80e1948f 100644 --- a/src/main/java/org/moddingx/libx/impl/BlockEntityUpdateQueue.java +++ b/src/main/java/org/moddingx/libx/impl/BlockEntityUpdateQueue.java @@ -1,8 +1,9 @@ package org.moddingx.libx.impl; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; -import net.minecraftforge.event.TickEvent; +import net.neoforged.neoforge.event.tick.ServerTickEvent; import org.moddingx.libx.LibX; import java.util.HashMap; @@ -12,25 +13,23 @@ public class BlockEntityUpdateQueue { - private static final Map> updateQueue = new HashMap<>(); + private static final Map> updateQueue = new HashMap<>(); public static void scheduleUpdate(Level level, BlockPos pos) { - if (!level.isClientSide) { - if (!updateQueue.containsKey(level)) { - updateQueue.put(level, new HashSet<>()); + if (!level.isClientSide && level instanceof ServerLevel serverLevel) { + if (!updateQueue.containsKey(serverLevel)) { + updateQueue.put(serverLevel, new HashSet<>()); } - updateQueue.get(level).add(pos); + updateQueue.get(serverLevel).add(pos); } } - public static void tick(TickEvent.ServerTickEvent event) { - if (event.phase == TickEvent.Phase.END) { - for (Map.Entry> entry : updateQueue.entrySet()) { - for (BlockPos pos : entry.getValue()) { - LibX.getNetwork().updateBE(entry.getKey(), pos); - } - entry.getValue().clear(); + public static void tick(ServerTickEvent.Post event) { + for (Map.Entry> entry : updateQueue.entrySet()) { + for (BlockPos pos : entry.getValue()) { + LibX.getNetwork().updateBE(entry.getKey(), pos); } + entry.getValue().clear(); } } } diff --git a/src/main/java/org/moddingx/libx/impl/ModInternal.java b/src/main/java/org/moddingx/libx/impl/ModInternal.java index 496b74a4..191ebad7 100644 --- a/src/main/java/org/moddingx/libx/impl/ModInternal.java +++ b/src/main/java/org/moddingx/libx/impl/ModInternal.java @@ -1,11 +1,12 @@ package org.moddingx.libx.impl; import com.mojang.serialization.Codec; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.javafmlmod.FMLModContainer; import org.moddingx.libx.datagen.DatagenSystem; -import org.moddingx.libx.impl.registration.RegistrationDispatcher; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.util.ClassUtil; @@ -22,20 +23,25 @@ public class ModInternal { private static final Map, ModInternal> MAP = new HashMap<>(); private static final Map ID_MAP = new HashMap<>(); - public static void init(ModX mod, FMLJavaModLoadingContext ctx) { + public static ModInternal init(ModX mod) { + ModContainer modContainer = ModLoadingContext.get().getActiveContainer(); + if (!Objects.equals(modContainer.getModId(), mod.modid)) { + throw new IllegalStateException("Mod entrypoint " + mod.modid + " (" + mod.getClass() + ") constructed while namespace " + modContainer.getModId() + " was active."); + } synchronized (LOCK) { if (!Modifier.isFinal(mod.getClass().getModifiers())) { throw new IllegalStateException("Mod class must be final. Report to the author of the " + mod.modid + " mod."); } if (MAP.containsKey(mod.getClass())) { - throw new IllegalStateException("ModInternal initialised twice for mod " + mod.getClass()); + throw new IllegalStateException("The same ModX class can't be an entrypoint twice."); } if (ID_MAP.containsKey(mod.modid)) { - throw new IllegalStateException("ModInternal initialised twice for modid " + mod.modid + " (Duplicate modid?)"); + throw new IllegalStateException("A mod can have multiple entry points but only one of them may be of instance ModX."); } - ModInternal modInternal = new ModInternal(mod, ctx); + ModInternal modInternal = new ModInternal(mod, modContainer); MAP.put(mod.getClass(), modInternal); ID_MAP.put(mod.modid, modInternal); + return modInternal; } } @@ -66,20 +72,23 @@ public static Optional get(String modid) { @Nullable private final Class modInitClass; + private final FMLModContainer modContainer; private final IEventBus modEventBus; private final List setupTasks; private final List queueSetupTasks; private final List> datagenConfiguration; - private RegistrationDispatcher registrationDispatcher; - private ModInternal(ModX mod, FMLJavaModLoadingContext ctx) { + private ModInternal(ModX mod, ModContainer modContainer) { + if (!(modContainer instanceof FMLModContainer fmlContainer)) { + throw new IllegalStateException("ModX needs the fmljava language loader, got " + modContainer.getModInfo().getLoader().name()); + } this.mod = mod; this.modInitClass = ClassUtil.forName(mod.getClass().getName() + "$"); - this.modEventBus = ctx.getModEventBus(); + this.modContainer = fmlContainer; + this.modEventBus = Objects.requireNonNull(fmlContainer.getEventBus(), "FML mod container has no event bus: " + this.mod.modid); this.setupTasks = new ArrayList<>(); this.queueSetupTasks = new ArrayList<>(); this.datagenConfiguration = new ArrayList<>(); - this.registrationDispatcher = null; this.modEventBus.addListener(this::runSetup); } @@ -88,14 +97,14 @@ public ModX instance() { return this.mod; } + public FMLModContainer modContainer() { + return this.modContainer; + } + public IEventBus modEventBus() { return this.modEventBus; } - public void initRegistration(RegistrationDispatcher dispatcher) { - this.registrationDispatcher = dispatcher; - } - public void addSetupTask(Runnable task, boolean enqueue) { if (enqueue) { this.queueSetupTasks.add(task); @@ -133,14 +142,6 @@ public Map, Codec> getCodecMap() { } } - public RegistrationDispatcher getRegistrationDispatcher() { - if (this.registrationDispatcher == null) { - throw new NoSuchElementException(this.mod.modid + " has no registration dispatcher. This is an error in LibX."); - } else { - return this.registrationDispatcher; - } - } - public boolean addDatagenConfiguration(Consumer configure) { boolean isFirst = this.datagenConfiguration.isEmpty(); this.datagenConfiguration.add(configure); diff --git a/src/main/java/org/moddingx/libx/impl/RendererOnDataGenException.java b/src/main/java/org/moddingx/libx/impl/RendererOnDataGenException.java deleted file mode 100644 index 9ae17d00..00000000 --- a/src/main/java/org/moddingx/libx/impl/RendererOnDataGenException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.moddingx.libx.impl; - -// Thrown by ItemStackRenderer.get while in datagen. -// Used by the item model provider to find out whether a mod uses ItemStackRenderer -// Hopefully this does not break... -public class RendererOnDataGenException extends RuntimeException { - - public RendererOnDataGenException() { - super("Attempted to retrieve ItemStackRenderer during data generation."); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/BaseMaterial.java b/src/main/java/org/moddingx/libx/impl/base/decoration/BaseMaterial.java index cb06efbe..1aee7358 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/BaseMaterial.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/BaseMaterial.java @@ -14,18 +14,67 @@ public record BaseMaterial(boolean isWood, boolean isStone, boolean isMetal, Fun public static final BaseMaterial GENERIC = new BaseMaterial(false, false, false, id -> new DecorationMaterial.MaterialProperties(null, null)); public static final BaseMaterial WOOD = new BaseMaterial(true, false, false, id -> { - BlockSetType setType = new BlockSetType(id.toString(), true, SoundType.WOOD, SoundEvents.WOODEN_DOOR_CLOSE, SoundEvents.WOODEN_DOOR_OPEN, SoundEvents.WOODEN_TRAPDOOR_CLOSE, SoundEvents.WOODEN_TRAPDOOR_OPEN, SoundEvents.WOODEN_PRESSURE_PLATE_CLICK_OFF, SoundEvents.WOODEN_PRESSURE_PLATE_CLICK_ON, SoundEvents.WOODEN_BUTTON_CLICK_OFF, SoundEvents.WOODEN_BUTTON_CLICK_ON); - WoodType woodType = new WoodType(id.toString(), setType, SoundType.WOOD, SoundType.HANGING_SIGN, SoundEvents.FENCE_GATE_CLOSE, SoundEvents.FENCE_GATE_OPEN); + BlockSetType setType = new BlockSetType( + id.toString(), true, true, true, + BlockSetType.PressurePlateSensitivity.EVERYTHING, SoundType.WOOD, + SoundEvents.WOODEN_DOOR_CLOSE, SoundEvents.WOODEN_DOOR_OPEN, + SoundEvents.WOODEN_TRAPDOOR_CLOSE, SoundEvents.WOODEN_TRAPDOOR_OPEN, + SoundEvents.WOODEN_PRESSURE_PLATE_CLICK_OFF, SoundEvents.WOODEN_PRESSURE_PLATE_CLICK_ON, + SoundEvents.WOODEN_BUTTON_CLICK_OFF, SoundEvents.WOODEN_BUTTON_CLICK_ON + ); + WoodType woodType = new WoodType( + id.toString(), setType, SoundType.WOOD, SoundType.HANGING_SIGN, + SoundEvents.FENCE_GATE_CLOSE, SoundEvents.FENCE_GATE_OPEN + ); + return new DecorationMaterial.MaterialProperties(setType, woodType); + }); + + public static final BaseMaterial NETHER_WOOD = new BaseMaterial(true, false, false, id -> { + BlockSetType setType = new BlockSetType( + id.toString(), true, true, true, + BlockSetType.PressurePlateSensitivity.EVERYTHING, SoundType.NETHER_WOOD, + SoundEvents.NETHER_WOOD_DOOR_CLOSE, SoundEvents.NETHER_WOOD_DOOR_OPEN, + SoundEvents.NETHER_WOOD_TRAPDOOR_CLOSE, SoundEvents.NETHER_WOOD_TRAPDOOR_OPEN, + SoundEvents.NETHER_WOOD_PRESSURE_PLATE_CLICK_OFF, SoundEvents.NETHER_WOOD_PRESSURE_PLATE_CLICK_ON, + SoundEvents.NETHER_WOOD_BUTTON_CLICK_OFF, SoundEvents.NETHER_WOOD_BUTTON_CLICK_ON + ); + WoodType woodType = new WoodType( + id.toString(), setType, SoundType.NETHER_WOOD, SoundType.NETHER_WOOD_HANGING_SIGN, + SoundEvents.NETHER_WOOD_FENCE_GATE_CLOSE, SoundEvents.NETHER_WOOD_FENCE_GATE_OPEN + ); return new DecorationMaterial.MaterialProperties(setType, woodType); }); public static final BaseMaterial STONE = new BaseMaterial(false, true, false, id -> { - BlockSetType setType = new BlockSetType(id.toString(), false, SoundType.STONE, SoundEvents.IRON_DOOR_CLOSE, SoundEvents.IRON_DOOR_OPEN, SoundEvents.IRON_TRAPDOOR_CLOSE, SoundEvents.IRON_TRAPDOOR_OPEN, SoundEvents.STONE_PRESSURE_PLATE_CLICK_OFF, SoundEvents.STONE_PRESSURE_PLATE_CLICK_ON, SoundEvents.STONE_BUTTON_CLICK_OFF, SoundEvents.STONE_BUTTON_CLICK_ON); + BlockSetType setType = new BlockSetType( + id.toString(), true, false, false, + BlockSetType.PressurePlateSensitivity.MOBS, SoundType.STONE, + SoundEvents.IRON_DOOR_CLOSE, SoundEvents.IRON_DOOR_OPEN, + SoundEvents.IRON_TRAPDOOR_CLOSE, SoundEvents.IRON_TRAPDOOR_OPEN, + SoundEvents.STONE_PRESSURE_PLATE_CLICK_OFF, SoundEvents.STONE_PRESSURE_PLATE_CLICK_ON, + SoundEvents.STONE_BUTTON_CLICK_OFF, SoundEvents.STONE_BUTTON_CLICK_ON); return new DecorationMaterial.MaterialProperties(setType, null); }); - public static final BaseMaterial METAL = new BaseMaterial(false, true, true, id -> { - BlockSetType setType = new BlockSetType(id.toString(), false, SoundType.METAL, SoundEvents.IRON_DOOR_CLOSE, SoundEvents.IRON_DOOR_OPEN, SoundEvents.IRON_TRAPDOOR_CLOSE, SoundEvents.IRON_TRAPDOOR_OPEN, SoundEvents.METAL_PRESSURE_PLATE_CLICK_OFF, SoundEvents.METAL_PRESSURE_PLATE_CLICK_ON, SoundEvents.STONE_BUTTON_CLICK_OFF, SoundEvents.STONE_BUTTON_CLICK_ON); + public static final BaseMaterial IRON = new BaseMaterial(false, false, true, id -> { + BlockSetType setType = new BlockSetType( + id.toString(), false, false, false, + BlockSetType.PressurePlateSensitivity.EVERYTHING, SoundType.METAL, + SoundEvents.IRON_DOOR_CLOSE, SoundEvents.IRON_DOOR_OPEN, + SoundEvents.IRON_TRAPDOOR_CLOSE, SoundEvents.IRON_TRAPDOOR_OPEN, + SoundEvents.METAL_PRESSURE_PLATE_CLICK_OFF, SoundEvents.METAL_PRESSURE_PLATE_CLICK_ON, + SoundEvents.STONE_BUTTON_CLICK_OFF, SoundEvents.STONE_BUTTON_CLICK_ON); + return new DecorationMaterial.MaterialProperties(setType, null); + }); + + public static final BaseMaterial COPPER = new BaseMaterial(false, false, true, id -> { + BlockSetType setType = new BlockSetType( + id.toString(), true, true, false, + BlockSetType.PressurePlateSensitivity.EVERYTHING, SoundType.COPPER, + SoundEvents.COPPER_DOOR_CLOSE, SoundEvents.COPPER_DOOR_OPEN, + SoundEvents.COPPER_TRAPDOOR_CLOSE, SoundEvents.COPPER_TRAPDOOR_OPEN, + SoundEvents.METAL_PRESSURE_PLATE_CLICK_OFF, SoundEvents.METAL_PRESSURE_PLATE_CLICK_ON, + SoundEvents.STONE_BUTTON_CLICK_OFF, SoundEvents.STONE_BUTTON_CLICK_ON); return new DecorationMaterial.MaterialProperties(setType, null); }); diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/BlockDecorationType.java b/src/main/java/org/moddingx/libx/impl/base/decoration/BlockDecorationType.java index 7b0dd46f..414c9572 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/BlockDecorationType.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/BlockDecorationType.java @@ -15,6 +15,7 @@ import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.RegistrationContext; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.OverridingMethodsMustInvokeSuper; import java.util.function.BiFunction; @@ -82,7 +83,7 @@ public DecoratedBlockItem(Block block, DecoratedBlock parent, double burnTimeMod } @Override - public int getBurnTime(ItemStack stack, @Nullable RecipeType recipeType) { + public int getBurnTime(@Nonnull ItemStack stack, @Nullable RecipeType recipeType) { if (this.burnTimeModifier == 0) return 0; int burnTime = this.parent.getBurnTime(stack, recipeType); if (burnTime < 0) return burnTime; diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/DecorationTypes.java b/src/main/java/org/moddingx/libx/impl/base/decoration/DecorationTypes.java index 36561113..0c77ec06 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/DecorationTypes.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/DecorationTypes.java @@ -1,7 +1,6 @@ package org.moddingx.libx.impl.base.decoration; import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.block.PressurePlateBlock; import org.moddingx.libx.base.decoration.DecoratedBlock; import org.moddingx.libx.base.decoration.DecorationType; import org.moddingx.libx.impl.base.decoration.blocks.*; @@ -26,8 +25,7 @@ public class DecorationTypes { public static final DecorationType FENCE_GATE = new BlockDecorationType<>("fence_gate", Registries.BLOCK, 1, DecoratedFenceGateBlock::new); public static final DecorationType WOOD_BUTTON = new BlockDecorationType<>("button", Registries.BLOCK, 1/3d, block -> new DecoratedButton(block, true)); public static final DecorationType STONE_BUTTON = new BlockDecorationType<>("button", Registries.BLOCK, 1/3d, block -> new DecoratedButton(block, false)); - public static final DecorationType WOOD_PRESSURE_PLATE = new BlockDecorationType<>("pressure_plate", Registries.BLOCK, 1, block -> new DecoratedPressurePlate(PressurePlateBlock.Sensitivity.EVERYTHING, block)); - public static final DecorationType STONE_PRESSURE_PLATE = new BlockDecorationType<>("pressure_plate", Registries.BLOCK, 1, block -> new DecoratedPressurePlate(PressurePlateBlock.Sensitivity.MOBS, block)); + public static final DecorationType PRESSURE_PLATE = new BlockDecorationType<>("pressure_plate", Registries.BLOCK, 1, DecoratedPressurePlate::new); public static final DecorationType DOOR = new BlockDecorationType<>("door", Registries.BLOCK, 2/3d, DecoratedDoorBlock::new); public static final DecorationType TRAPDOOR = new BlockDecorationType<>("trapdoor", Registries.BLOCK, 1, DecoratedTrapdoorBlock::new); public static final DecorationType SIGN = new BaseDecorationType<>("sign", null, (mod, context, block) -> new DecoratedSign(mod, block)); diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedButton.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedButton.java index 35491028..97848339 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedButton.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedButton.java @@ -15,7 +15,7 @@ public class DecoratedButton extends ButtonBlock { public final DecoratedBlock parent; public DecoratedButton(DecoratedBlock parent, boolean wooden) { - super(Properties.copy(parent), parent.getMaterialProperties().blockSetType(), wooden ? 30 : 20, wooden); + super(parent.getMaterialProperties().blockSetType(), wooden ? 30 : 20, Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedDoorBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedDoorBlock.java index 2960c281..d72a5f4c 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedDoorBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedDoorBlock.java @@ -16,7 +16,7 @@ public class DecoratedDoorBlock extends DoorBlock implements Registerable { public final DecoratedBlock parent; public DecoratedDoorBlock(DecoratedBlock parent) { - super(Properties.copy(parent), parent.getMaterialProperties().blockSetType()); + super(parent.getMaterialProperties().blockSetType(), Properties.ofFullCopy(parent)); this.parent = parent; } @@ -32,13 +32,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceBlock.java index 9cda480c..a51f090f 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceBlock.java @@ -15,7 +15,7 @@ public class DecoratedFenceBlock extends FenceBlock { public final DecoratedBlock parent; public DecoratedFenceBlock(DecoratedBlock parent) { - super(Properties.copy(parent)); + super(Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceGateBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceGateBlock.java index 216df6c2..997d7095 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceGateBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedFenceGateBlock.java @@ -15,7 +15,7 @@ public class DecoratedFenceGateBlock extends FenceGateBlock { public final DecoratedBlock parent; public DecoratedFenceGateBlock(DecoratedBlock parent) { - super(Properties.copy(parent), parent.getMaterialProperties().woodType()); + super(parent.getMaterialProperties().woodType(), Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedHangingSign.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedHangingSign.java index e4e65ac7..074764a4 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedHangingSign.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedHangingSign.java @@ -14,8 +14,8 @@ import net.minecraft.world.level.block.entity.HangingSignBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.WoodType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.base.decoration.DecoratedBlock; import org.moddingx.libx.base.decoration.HangingSignAccess; import org.moddingx.libx.mod.ModX; @@ -24,6 +24,7 @@ import org.moddingx.libx.registration.SetupContext; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.OverridingMethodsMustInvokeSuper; import java.util.Set; import java.util.function.Supplier; @@ -60,7 +61,7 @@ public void registerAdditional(RegistrationContext ctx, EntryCollector builder) @Override @OnlyIn(Dist.CLIENT) - public void registerClient(SetupContext ctx) { + public void setupClient(SetupContext ctx) { BlockEntityRenderers.register(this.beType, HangingSignRenderer::new); // Add sign texture to sheet. ctx.enqueue(() -> Sheets.addWoodType(this.parent.getMaterialProperties().woodType())); @@ -96,12 +97,14 @@ public static class Ceiling extends CeilingHangingSignBlock { private final Supplier> beType; public Ceiling(DecoratedBlock parent, Supplier> beType, WoodType wood) { - super(Properties.copy(parent), wood); + super(wood, Properties.ofFullCopy(parent)); this.parent = parent; this.beType = beType; } + @Nullable @Override + @SuppressWarnings("NullableProblems") public BlockEntity newBlockEntity(@Nonnull BlockPos pos, @Nonnull BlockState state) { return this.beType.get().create(pos, state); } @@ -113,12 +116,14 @@ public static class Wall extends WallHangingSignBlock { private final Supplier> beType; public Wall(DecoratedBlock parent, Supplier> beType, WoodType wood) { - super(Properties.copy(parent), wood); + super(wood, Properties.ofFullCopy(parent)); this.parent = parent; this.beType = beType; } - + + @Nullable @Override + @SuppressWarnings("NullableProblems") public BlockEntity newBlockEntity(@Nonnull BlockPos pos, @Nonnull BlockState state) { return this.beType.get().create(pos, state); } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedPressurePlate.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedPressurePlate.java index 4477177d..8b0dd894 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedPressurePlate.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedPressurePlate.java @@ -13,12 +13,10 @@ public class DecoratedPressurePlate extends PressurePlateBlock { public final DecoratedBlock parent; - public final PressurePlateBlock.Sensitivity sensitivity; - public DecoratedPressurePlate(PressurePlateBlock.Sensitivity sensitivity, DecoratedBlock parent) { - super(sensitivity, Properties.copy(parent), parent.getMaterialProperties().blockSetType()); + public DecoratedPressurePlate(DecoratedBlock parent) { + super(parent.getMaterialProperties().blockSetType(), Properties.ofFullCopy(parent)); this.parent = parent; - this.sensitivity = sensitivity; } @Override @@ -33,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSign.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSign.java index 65f32c99..13b0f01a 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSign.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSign.java @@ -14,8 +14,8 @@ import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.WoodType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.base.decoration.DecoratedBlock; import org.moddingx.libx.base.decoration.SignAccess; import org.moddingx.libx.mod.ModX; @@ -24,6 +24,7 @@ import org.moddingx.libx.registration.SetupContext; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.OverridingMethodsMustInvokeSuper; import java.util.Set; import java.util.function.Supplier; @@ -60,7 +61,7 @@ public void registerAdditional(RegistrationContext ctx, EntryCollector builder) @Override @OnlyIn(Dist.CLIENT) - public void registerClient(SetupContext ctx) { + public void setupClient(SetupContext ctx) { BlockEntityRenderers.register(this.beType, SignRenderer::new); // Add sign texture to sheet. ctx.enqueue(() -> Sheets.addWoodType(this.parent.getMaterialProperties().woodType())); @@ -96,12 +97,14 @@ public static class Standing extends StandingSignBlock { private final Supplier> beType; public Standing(DecoratedBlock parent, Supplier> beType, WoodType wood) { - super(Properties.copy(parent), wood); + super(wood, Properties.ofFullCopy(parent)); this.parent = parent; this.beType = beType; } + @Nullable @Override + @SuppressWarnings("NullableProblems") public BlockEntity newBlockEntity(@Nonnull BlockPos pos, @Nonnull BlockState state) { return this.beType.get().create(pos, state); } @@ -113,12 +116,14 @@ public static class Wall extends WallSignBlock { private final Supplier> beType; public Wall(DecoratedBlock parent, Supplier> beType, WoodType wood) { - super(Properties.copy(parent), wood); + super(wood, Properties.ofFullCopy(parent)); this.parent = parent; this.beType = beType; } + @Nullable @Override + @SuppressWarnings("NullableProblems") public BlockEntity newBlockEntity(@Nonnull BlockPos pos, @Nonnull BlockState state) { return this.beType.get().create(pos, state); } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSlabBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSlabBlock.java index c3b8cf39..2e9285a5 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSlabBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedSlabBlock.java @@ -15,7 +15,7 @@ public class DecoratedSlabBlock extends SlabBlock { public final DecoratedBlock parent; public DecoratedSlabBlock(DecoratedBlock parent) { - super(Properties.copy(parent)); + super(Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedStairBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedStairBlock.java index 987fdda8..3bdfb0d2 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedStairBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedStairBlock.java @@ -15,7 +15,7 @@ public class DecoratedStairBlock extends StairBlock { public final DecoratedBlock parent; public DecoratedStairBlock(DecoratedBlock parent) { - super(parent::defaultBlockState, Properties.copy(parent)); + super(parent.defaultBlockState(), Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedTrapdoorBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedTrapdoorBlock.java index 9d7febb3..b1183afc 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedTrapdoorBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedTrapdoorBlock.java @@ -16,7 +16,7 @@ public class DecoratedTrapdoorBlock extends TrapDoorBlock implements Registerabl public final DecoratedBlock parent; public DecoratedTrapdoorBlock(DecoratedBlock parent) { - super(Properties.copy(parent), parent.getMaterialProperties().blockSetType()); + super(parent.getMaterialProperties().blockSetType(), Properties.ofFullCopy(parent)); this.parent = parent; } @@ -32,13 +32,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWallBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWallBlock.java index 41fa0324..85452340 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWallBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWallBlock.java @@ -15,7 +15,7 @@ public class DecoratedWallBlock extends WallBlock { public final DecoratedBlock parent; public DecoratedWallBlock(DecoratedBlock parent) { - super(Properties.copy(parent)); + super(Properties.ofFullCopy(parent)); this.parent = parent; } @@ -31,13 +31,12 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } } diff --git a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWoodBlock.java b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWoodBlock.java index eb553391..25204a3d 100644 --- a/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWoodBlock.java +++ b/src/main/java/org/moddingx/libx/impl/base/decoration/blocks/DecoratedWoodBlock.java @@ -9,8 +9,8 @@ import net.minecraft.world.level.block.RotatedPillarBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraftforge.common.ToolAction; -import net.minecraftforge.common.ToolActions; +import net.neoforged.neoforge.common.ItemAbilities; +import net.neoforged.neoforge.common.ItemAbility; import org.moddingx.libx.base.decoration.DecoratedBlock; import org.moddingx.libx.base.decoration.DecorationType; @@ -24,7 +24,7 @@ public class DecoratedWoodBlock extends RotatedPillarBlock { @Nullable public final DecorationType stripped; public DecoratedWoodBlock(DecoratedBlock parent, @Nullable DecorationType log, @Nullable DecorationType stripped) { - super(Properties.copy(parent)); + super(Properties.ofFullCopy(parent)); this.parent = parent; this.log = log; this.stripped = stripped; @@ -42,24 +42,23 @@ public float getExplosionResistance() { } @Override - @SuppressWarnings("deprecation") public int getLightBlock(@Nonnull BlockState state, @Nonnull BlockGetter level, @Nonnull BlockPos pos) { return this.parent.getLightBlock(state, level, pos); } @Override - public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) { + public int getLightEmission(@Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos) { return this.parent.getLightEmission(state, world, pos); } @Nullable @Override - public BlockState getToolModifiedState(BlockState state, UseOnContext context, ToolAction toolAction, boolean simulate) { - if (toolAction == ToolActions.AXE_STRIP && this.stripped != null && this.parent.has(this.stripped)) { + public BlockState getToolModifiedState(@Nonnull BlockState state, @Nonnull UseOnContext context, @Nonnull ItemAbility itemAbility, boolean simulate) { + if (itemAbility == ItemAbilities.AXE_STRIP && this.stripped != null && this.parent.has(this.stripped)) { Block strippedBlock = this.parent.get(this.stripped); return strippedBlock.defaultBlockState().setValue(BlockStateProperties.AXIS, state.getValue(BlockStateProperties.AXIS)); } else { - return super.getToolModifiedState(state, context, toolAction, simulate); + return super.getToolModifiedState(state, context, itemAbility, simulate); } } } diff --git a/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultBucketItem.java b/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultBucketItem.java new file mode 100644 index 00000000..709bf8de --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultBucketItem.java @@ -0,0 +1,47 @@ +package org.moddingx.libx.impl.base.fluid; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.BucketItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.material.Fluid; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.fluids.capability.wrappers.FluidBucketWrapper; +import org.moddingx.libx.registration.Registerable; +import org.moddingx.libx.registration.RegistrationContext; +import org.moddingx.libx.registration.util.CapabilityInfo; + +import javax.annotation.Nonnull; +import javax.annotation.OverridingMethodsMustInvokeSuper; + +public class DefaultBucketItem extends BucketItem implements Registerable { + + public DefaultBucketItem(Fluid content, Properties properties) { + super(content, properties); + } + + @Override + @OverridingMethodsMustInvokeSuper + public void registerAdditional(RegistrationContext ctx, EntryCollector builder) { + builder.register(null, new CapabilityInfo.Item<>(this, Capabilities.FluidHandler.ITEM, (stack, ignored) -> new FluidBucketWrapper(stack))); + } + + @Nonnull + @Override + protected String getOrCreateDescriptionId() { + return "libx.tooltip.fluid_base.bucket"; + } + + @Nonnull + @Override + public Component getName(@Nonnull ItemStack stack) { + return Component.translatable("libx.tooltip.fluid_base.bucket", this.content.getFluidType().getDescription(new FluidStack(this.content, FluidType.BUCKET_VOLUME))); + } + + @Nonnull + @Override + public Component getDescription() { + return Component.translatable("libx.tooltip.fluid_base.bucket", this.content.getFluidType().getDescription(new FluidStack(this.content, FluidType.BUCKET_VOLUME))); + } +} diff --git a/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultClientExtensions.java b/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultClientExtensions.java index c763189a..fd187ffe 100644 --- a/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultClientExtensions.java +++ b/src/main/java/org/moddingx/libx/impl/base/fluid/DefaultClientExtensions.java @@ -1,27 +1,29 @@ package org.moddingx.libx.impl.base.fluid; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import javax.annotation.Nonnull; public class DefaultClientExtensions implements IClientFluidTypeExtensions { - private final ResourceLocation texture; + private final ResourceLocation stillTexture; + private final ResourceLocation flowingTexture; - public DefaultClientExtensions(ResourceLocation texture) { - this.texture = texture; + public DefaultClientExtensions(ResourceLocation stillTexture, ResourceLocation flowingTexture) { + this.stillTexture = stillTexture; + this.flowingTexture = flowingTexture; } @Nonnull @Override public ResourceLocation getStillTexture() { - return this.texture; + return this.stillTexture; } @Nonnull @Override public ResourceLocation getFlowingTexture() { - return this.texture; + return this.flowingTexture; } } diff --git a/src/main/java/org/moddingx/libx/impl/base/fluid/FluidTypeBase.java b/src/main/java/org/moddingx/libx/impl/base/fluid/FluidTypeBase.java deleted file mode 100644 index 1b3abddb..00000000 --- a/src/main/java/org/moddingx/libx/impl/base/fluid/FluidTypeBase.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.moddingx.libx.impl.base.fluid; - -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.fluids.FluidType; -import net.minecraftforge.fml.DistExecutor; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class FluidTypeBase extends FluidType { - - private final Supplier> clientExtensions; - - public FluidTypeBase(Properties properties, Supplier> clientExtensions) { - super(properties); - this.clientExtensions = clientExtensions; - } - - @Override - public void initializeClient(Consumer consumer) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> consumer.accept(this.clientExtensions.get().get())); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/codec/EnumCodec.java b/src/main/java/org/moddingx/libx/impl/codec/EnumCodec.java index e93cfabf..ac5d8337 100644 --- a/src/main/java/org/moddingx/libx/impl/codec/EnumCodec.java +++ b/src/main/java/org/moddingx/libx/impl/codec/EnumCodec.java @@ -4,7 +4,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import net.minecraftforge.common.IExtensibleEnum; +import net.neoforged.fml.common.asm.enumextension.IExtensibleEnum; import org.moddingx.libx.codec.CodecHelper; import java.util.HashMap; @@ -23,7 +23,7 @@ public static synchronized > EnumCodec get(Class clazz) private final boolean extensible; private EnumCodec(Class clazz) { - if (!clazz.isEnum()) throw new IllegalArgumentException("Can't create enum codec for non-enum class: " + clazz); + if (!clazz.isEnum()) throw new IllegalArgumentException("Can't create enum streamCodec for non-enum class: " + clazz); this.clazz = clazz; this.extensible = IExtensibleEnum.class.isAssignableFrom(this.clazz); } diff --git a/src/main/java/org/moddingx/libx/impl/codec/FixedCodec.java b/src/main/java/org/moddingx/libx/impl/codec/FixedCodec.java index c13839a7..c665cd75 100644 --- a/src/main/java/org/moddingx/libx/impl/codec/FixedCodec.java +++ b/src/main/java/org/moddingx/libx/impl/codec/FixedCodec.java @@ -17,7 +17,6 @@ public FixedCodec(Dynamic serializedValue) { this.serializedValue = serializedValue; } - @Override public DataResult encode(Unit unit, DynamicOps ops, T prefix) { return ops.mergeToPrimitive(prefix, this.serializedValue.convert(ops).getValue()); @@ -29,7 +28,7 @@ public DataResult> decode(DynamicOps ops, T input) { if (Objects.equals(this.serializedValue, dynamic)) { return DataResult.success(Pair.of(Unit.INSTANCE, ops.empty())); } else { - return DataResult.error(() -> "Wrong value in fixed codec."); + return DataResult.error(() -> "Wrong value in fixed streamCodec."); } } diff --git a/src/main/java/org/moddingx/libx/impl/codec/MapDispatchedCodec.java b/src/main/java/org/moddingx/libx/impl/codec/MapDispatchedCodec.java index a002de7c..09d8135b 100644 --- a/src/main/java/org/moddingx/libx/impl/codec/MapDispatchedCodec.java +++ b/src/main/java/org/moddingx/libx/impl/codec/MapDispatchedCodec.java @@ -25,25 +25,25 @@ public DataResult encode(A input, DynamicOps ops, T prefix) { Pair pair = this.decompose.apply(input); //noinspection unchecked return ((DataResult>) (DataResult) this.valueCodecs.apply(pair.getFirst())) - .mapError(err -> "No value codec available for " + pair.getFirst() + ": " + err) + .mapError(err -> "No value streamCodec available for " + pair.getFirst() + ": " + err) .flatMap(valueCodec -> valueCodec .encode(pair.getSecond(), ops, prefix) .mapError(err -> "Could not encode base element for key " + pair.getFirst() + ": " + err) ) .flatMap(encoded -> ops.getMap(encoded) - .mapError(err -> "Map dispatched base codec encoded a value with is not a MapLike for key " + pair.getFirst()) + .mapError(err -> "Map dispatched base streamCodec encoded a value with is not a MapLike for key " + pair.getFirst()) ) .flatMap(base -> this.keyCodec.keys(ops) .filter(key -> base.get(key) != null).findFirst() - .map(dupKey -> DataResult.>error(() -> "Key was encoded by base codec: " + dupKey + " (for " + pair.getFirst() + ")")) + .map(dupKey -> DataResult.>error(() -> "Key was encoded by base streamCodec: " + dupKey + " (for " + pair.getFirst() + ")")) .orElseGet(() -> DataResult.success(base)) ) .flatMap(base -> { RecordBuilder keys = this.keyCodec.encode(pair.getFirst(), ops, ops.mapBuilder()); return keys.build(ops.empty()) - .mapError(err -> "Failed to build key map in map dispatched codec for key " + pair.getFirst() + ": " + err) + .mapError(err -> "Failed to build key map in map dispatched streamCodec for key " + pair.getFirst() + ": " + err) .flatMap(keyMap -> ops.mergeToMap(keyMap, base) - .mapError(err -> "Failed to merge base and key in map dispatched codec for " + pair.getFirst() + ": " + err) + .mapError(err -> "Failed to merge base and key in map dispatched streamCodec for " + pair.getFirst() + ": " + err) ); }); } @@ -57,7 +57,7 @@ public DataResult> decode(DynamicOps ops, T input) { .map(key -> Pair.of(key, map)) ) .flatMap(pair -> this.valueCodecs.apply(pair.getFirst()) - .mapError(err -> "No value codec available for " + pair.getFirst() + ": " + err) + .mapError(err -> "No value streamCodec available for " + pair.getFirst() + ": " + err) .flatMap(valueCodec -> ops.mergeToMap(ops.emptyMap(), pair.getSecond()) .flatMap(merged -> valueCodec.decode(ops, merged)) .mapError(err -> "Failed to decode dispatched value for key " + pair.getFirst() + ": " + err) diff --git a/src/main/java/org/moddingx/libx/impl/codec/OptionCodec.java b/src/main/java/org/moddingx/libx/impl/codec/OptionCodec.java index a1e67bb2..718cea56 100644 --- a/src/main/java/org/moddingx/libx/impl/codec/OptionCodec.java +++ b/src/main/java/org/moddingx/libx/impl/codec/OptionCodec.java @@ -4,7 +4,6 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.Lifecycle; import java.util.Objects; import java.util.Optional; @@ -40,7 +39,7 @@ public DataResult, T>> decode(DynamicOps ops, T input) { if (Objects.equals(pair.getSecond(), ops.empty())) { return DataResult.success(Pair.of(Optional.of(pair.getFirst()), ops.empty())); } else { - return DataResult.error(() -> "Can't decode option: child codec left over some data"); + return DataResult.error(() -> "Can't decode option: child streamCodec left over some data"); } }); } else { diff --git a/src/main/java/org/moddingx/libx/impl/codec/TypeMappedCodec.java b/src/main/java/org/moddingx/libx/impl/codec/TypeMappedCodec.java index 9598c1e7..26ceef90 100644 --- a/src/main/java/org/moddingx/libx/impl/codec/TypeMappedCodec.java +++ b/src/main/java/org/moddingx/libx/impl/codec/TypeMappedCodec.java @@ -31,7 +31,7 @@ public DataResult encode(A input, DynamicOps ops, T prefix) { } } if (this.fallback == null) { - return DataResult.error(() -> "No fallback in type mapped codec: Can't encode to elements of type " + ops.empty().getClass()); + return DataResult.error(() -> "No fallback in type mapped streamCodec: Can't encode to elements of type " + ops.empty().getClass()); } else { return this.fallback.encode(input, ops, prefix); } @@ -46,7 +46,7 @@ public DataResult> decode(DynamicOps ops, T input) { } } if (this.fallback == null) { - return DataResult.error(() -> "No fallback in type mapped codec: Can't decode elements of type " + input.getClass()); + return DataResult.error(() -> "No fallback in type mapped streamCodec: Can't decode elements of type " + input.getClass()); } else { return this.fallback.decode(ops, input); } diff --git a/src/main/java/org/moddingx/libx/impl/commands/client/ClientCommandsImpl.java b/src/main/java/org/moddingx/libx/impl/command/client/ClientCommandsImpl.java similarity index 83% rename from src/main/java/org/moddingx/libx/impl/commands/client/ClientCommandsImpl.java rename to src/main/java/org/moddingx/libx/impl/command/client/ClientCommandsImpl.java index f2db95d8..030ce844 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/client/ClientCommandsImpl.java +++ b/src/main/java/org/moddingx/libx/impl/command/client/ClientCommandsImpl.java @@ -1,7 +1,7 @@ -package org.moddingx.libx.impl.commands.client; +package org.moddingx.libx.impl.command.client; import net.minecraft.commands.Commands; -import net.minecraftforge.client.event.RegisterClientCommandsEvent; +import net.neoforged.neoforge.client.event.RegisterClientCommandsEvent; public class ClientCommandsImpl { diff --git a/src/main/java/org/moddingx/libx/impl/commands/client/ModListCommand.java b/src/main/java/org/moddingx/libx/impl/command/client/ModListCommand.java similarity index 89% rename from src/main/java/org/moddingx/libx/impl/commands/client/ModListCommand.java rename to src/main/java/org/moddingx/libx/impl/command/client/ModListCommand.java index f36ad923..2a2ec4ff 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/client/ModListCommand.java +++ b/src/main/java/org/moddingx/libx/impl/command/client/ModListCommand.java @@ -1,4 +1,4 @@ -package org.moddingx.libx.impl.commands.client; +package org.moddingx.libx.impl.command.client; import com.google.common.collect.Streams; import com.mojang.brigadier.Command; @@ -8,8 +8,8 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; import net.minecraft.network.chat.TextColor; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.forgespi.language.IModInfo; +import net.neoforged.fml.ModList; +import net.neoforged.neoforgespi.language.IModInfo; import org.moddingx.libx.util.game.ComponentUtil; import java.util.Comparator; @@ -39,7 +39,7 @@ public int run(CommandContext context) { + (this.detailed && !mod.getDescription().trim().isEmpty() ? ": " + mod.getDescription().split("\n")[0].trim() : "")) .map(Component::literal); - List lines = Streams.mapWithIndex(lineStream, (line, idx) -> Objects.requireNonNull(line).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(idx % 2 == 0 ? 0xBDBD28 : 0x8C4489)))).toList(); + List lines = Streams.mapWithIndex(lineStream, (line, idx) -> Objects.requireNonNull(line).withStyle(Style.EMPTY.withColor(TextColor.fromRgb(idx % 2 == 0 ? 0xFFFFFF : 0xA0A0A0)))).toList(); String copyToClipboard = lines.stream() .map(Component::getString) .collect(Collectors.joining("\n")); diff --git a/src/main/java/org/moddingx/libx/impl/commands/client/ReloadClientCommand.java b/src/main/java/org/moddingx/libx/impl/command/client/ReloadClientCommand.java similarity index 92% rename from src/main/java/org/moddingx/libx/impl/commands/client/ReloadClientCommand.java rename to src/main/java/org/moddingx/libx/impl/command/client/ReloadClientCommand.java index 87cc9250..43a3200a 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/client/ReloadClientCommand.java +++ b/src/main/java/org/moddingx/libx/impl/command/client/ReloadClientCommand.java @@ -1,4 +1,4 @@ -package org.moddingx.libx.impl.commands.client; +package org.moddingx.libx.impl.command.client; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; diff --git a/src/main/java/org/moddingx/libx/impl/commands/common/CommandsImpl.java b/src/main/java/org/moddingx/libx/impl/command/common/CommandsImpl.java similarity index 73% rename from src/main/java/org/moddingx/libx/impl/commands/common/CommandsImpl.java rename to src/main/java/org/moddingx/libx/impl/command/common/CommandsImpl.java index 19883f8c..6385af59 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/common/CommandsImpl.java +++ b/src/main/java/org/moddingx/libx/impl/command/common/CommandsImpl.java @@ -1,18 +1,15 @@ -package org.moddingx.libx.impl.commands.common; +package org.moddingx.libx.impl.command.common; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.CompoundTagArgument; import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.NbtPathArgument; -import net.minecraftforge.event.RegisterCommandsEvent; +import net.neoforged.neoforge.event.RegisterCommandsEvent; public class CommandsImpl { public static void registerCommands(RegisterCommandsEvent event) { event.getDispatcher().register(Commands.literal("libx").then( - Commands.literal("hand").requires(source -> source.hasPermission(2)).executes(new HandCommand()).then( - Commands.argument("nbt_path", NbtPathArgument.nbtPath()).executes(new HandCommand()) - ) + Commands.literal("hand").requires(source -> source.hasPermission(2)).executes(new HandCommand()) ).then( Commands.literal("entitydata").requires(source -> source.hasPermission(2)).then( Commands.argument("entities", EntityArgument.entities()) diff --git a/src/main/java/org/moddingx/libx/impl/commands/common/EntityDataCommand.java b/src/main/java/org/moddingx/libx/impl/command/common/EntityDataCommand.java similarity index 88% rename from src/main/java/org/moddingx/libx/impl/commands/common/EntityDataCommand.java rename to src/main/java/org/moddingx/libx/impl/command/common/EntityDataCommand.java index e9a1aae3..1492cd52 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/common/EntityDataCommand.java +++ b/src/main/java/org/moddingx/libx/impl/command/common/EntityDataCommand.java @@ -1,4 +1,4 @@ -package org.moddingx.libx.impl.commands.common; +package org.moddingx.libx.impl.command.common; import com.google.common.base.Suppliers; import com.mojang.brigadier.Command; @@ -31,7 +31,7 @@ public int run(CommandContext context) throws CommandSyntaxE for (Entity entity : entities) { if (entity instanceof Player) { if (!context.getSource().hasPermission(4)) { - throw new SimpleCommandExceptionType(Component.translatable("libx.command.entitydata.player_modify_no_permission")).create(); + throw new SimpleCommandExceptionType(Component.translatable("libx.command.entity_data.player_modify_no_permission")).create(); } else { players = true; } @@ -45,7 +45,7 @@ public int run(CommandContext context) throws CommandSyntaxE entity.load(entityNBT); entity.setUUID(uid); } - context.getSource().sendSuccess(Suppliers.ofInstance(Component.translatable(players ? "libx.command.entitydata.modified_player" : "libx.command.entitydata.modified", entities.size())), true); + context.getSource().sendSuccess(Suppliers.ofInstance(Component.translatable(players ? "libx.command.entity_data.modified_player" : "libx.command.entity_data.modified", entities.size())), true); return 0; } diff --git a/src/main/java/org/moddingx/libx/impl/commands/common/HandCommand.java b/src/main/java/org/moddingx/libx/impl/command/common/HandCommand.java similarity index 52% rename from src/main/java/org/moddingx/libx/impl/commands/common/HandCommand.java rename to src/main/java/org/moddingx/libx/impl/command/common/HandCommand.java index d34ad49e..02305883 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/common/HandCommand.java +++ b/src/main/java/org/moddingx/libx/impl/command/common/HandCommand.java @@ -1,65 +1,56 @@ -package org.moddingx.libx.impl.commands.common; +package org.moddingx.libx.impl.command.common; import com.google.common.base.Suppliers; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.NbtPathArgument; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.nbt.Tag; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraftforge.registries.ForgeRegistries; -import org.moddingx.libx.command.CommandUtil; import org.moddingx.libx.util.game.ComponentUtil; -import java.util.List; -import java.util.Objects; - -// Not a client command as the client does not have the full stack tag +// Not a client command as the client does not have the full stack data public class HandCommand implements Command { + private static final ResourceKey AIR = ResourceKey.create(Registries.ITEM, ResourceLocation.withDefaultNamespace("air")); + @Override public int run(CommandContext ctx) throws CommandSyntaxException { ServerPlayer player = ctx.getSource().getPlayerOrException(); ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); - Item item; + ResourceKey item = BuiltInRegistries.ITEM.getResourceKey(stack.getItem()).orElse(AIR); int count; - CompoundTag nbt; + DataComponentPatch components; - if (stack.isEmpty() || ForgeRegistries.ITEMS.getKey(stack.getItem()) == null) { - item = Items.AIR; + if (stack.isEmpty() || item.equals(AIR)) { + item = AIR; count = 0; - nbt = null; + components = DataComponentPatch.EMPTY; } else { - item = stack.getItem(); count = stack.getCount(); - nbt = stack.getTag(); + components = stack.getComponentsPatch(); } - - NbtPathArgument.NbtPath path = CommandUtil.getArgumentOrDefault(ctx, "nbt_path", NbtPathArgument.NbtPath.class, null); - - ResourceLocation id = Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)); - MutableComponent message = ComponentUtil.withCopyAction(Component.literal(id.toString()), id.toString()).copy(); + + MutableComponent message = ComponentUtil.withCopyAction(Component.literal(item.location().toString()), item.location().toString()).copy(); if (count != 1) { message = message.append(Component.literal(" ")).append(Component.literal(Integer.toString(count))); } - if (nbt != null && !nbt.isEmpty()) { - List printNBT = path == null ? List.of(nbt) : path.get(nbt); - for (Tag element : printNBT) { - message = message.append(Component.literal(" ")).append(ComponentUtil.withCopyAction(NbtUtils.toPrettyComponent(element), element.toString())); - } + if (components.size() != 0) { + Component componentsText = ComponentUtil.toPrettyComponent(Registries.DATA_COMPONENT_TYPE, components); + componentsText = ComponentUtil.withCopyAction(componentsText, componentsText.getString()); + message = message.append(Component.literal(" ")).append(componentsText); } ctx.getSource().sendSuccess(Suppliers.ofInstance(message), true); diff --git a/src/main/java/org/moddingx/libx/impl/commands/common/ReloadCommonCommand.java b/src/main/java/org/moddingx/libx/impl/command/common/ReloadCommonCommand.java similarity index 68% rename from src/main/java/org/moddingx/libx/impl/commands/common/ReloadCommonCommand.java rename to src/main/java/org/moddingx/libx/impl/command/common/ReloadCommonCommand.java index 5286ea94..88592333 100644 --- a/src/main/java/org/moddingx/libx/impl/commands/common/ReloadCommonCommand.java +++ b/src/main/java/org/moddingx/libx/impl/command/common/ReloadCommonCommand.java @@ -1,11 +1,11 @@ -package org.moddingx.libx.impl.commands.common; +package org.moddingx.libx.impl.command.common; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.loading.FMLEnvironment; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLLoader; import org.moddingx.libx.config.ConfigManager; public class ReloadCommonCommand implements Command { @@ -13,8 +13,8 @@ public class ReloadCommonCommand implements Command { @Override public int run(CommandContext context) { ConfigManager.reloadCommon(); - if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) { - ConfigManager.forceResync(null); + if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) { + ConfigManager.synchronize(context.getSource().getServer()); } context.getSource().sendSuccess(() -> Component.translatable("libx.command.reload.common"), true); return 0; diff --git a/src/main/java/org/moddingx/libx/impl/config/ConfigEvents.java b/src/main/java/org/moddingx/libx/impl/config/ConfigEvents.java index 9561872e..8ceda689 100644 --- a/src/main/java/org/moddingx/libx/impl/config/ConfigEvents.java +++ b/src/main/java/org/moddingx/libx/impl/config/ConfigEvents.java @@ -2,13 +2,13 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.loading.FMLEnvironment; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; import org.moddingx.libx.config.ConfigManager; public class ConfigEvents { @@ -16,15 +16,15 @@ public class ConfigEvents { @OnlyIn(Dist.DEDICATED_SERVER) @SubscribeEvent(priority = EventPriority.HIGHEST) public void serverPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { - if (!event.getEntity().level().isClientSide && event.getEntity() instanceof ServerPlayer serverPlayer && FMLEnvironment.dist == Dist.DEDICATED_SERVER) { - ConfigManager.forceResync(serverPlayer); + if (!event.getEntity().level().isClientSide && event.getEntity() instanceof ServerPlayer serverPlayer && FMLLoader.getDist() == Dist.DEDICATED_SERVER) { + ConfigManager.synchronize(serverPlayer); } } @OnlyIn(Dist.CLIENT) @SubscribeEvent(priority = EventPriority.HIGHEST) public void clientPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { - if (!event.getEntity().level().isClientSide && FMLEnvironment.dist == Dist.CLIENT) { + if (!event.getEntity().level().isClientSide && FMLLoader.getDist() == Dist.CLIENT) { for (ConfigImpl config : ConfigImpl.getAllConfigs()) { config.reloadClientWorldState(); } diff --git a/src/main/java/org/moddingx/libx/impl/config/ConfigImpl.java b/src/main/java/org/moddingx/libx/impl/config/ConfigImpl.java index d0c8388c..bb9b18df 100644 --- a/src/main/java/org/moddingx/libx/impl/config/ConfigImpl.java +++ b/src/main/java/org/moddingx/libx/impl/config/ConfigImpl.java @@ -12,10 +12,9 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.loading.FMLEnvironment; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.common.NeoForge; import org.moddingx.libx.LibX; import org.moddingx.libx.config.mapper.ValueMapper; import org.moddingx.libx.event.ConfigLoadedEvent; @@ -136,7 +135,7 @@ public ConfigState readState(FriendlyByteBuf buffer) { if (key == null) { throw new IllegalStateException("Config between client and server mismatch. Server sent unknown or non-config field. Ignoring"); } - Object value = key.mapper.fromNetwork(buffer); + Object value = key.streamCodec.decode(buffer); values.put(key, value); keysLeft.remove(key); } @@ -286,7 +285,7 @@ public void shadowBy(ConfigState state) { } private void shadowBy(ConfigState state, boolean local, @Nullable Path loadPath) { - if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) { + if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) { LibX.logger.error("Config shadow was called on a dedicated server. This should not happen!"); } if (!this.shadowed && this.savedState == null) { @@ -297,7 +296,7 @@ private void shadowBy(ConfigState state, boolean local, @Nullable Path loadPath) this.shadowedLocal = local; state.apply(); ConfigLoadedEvent.LoadReason reason = local ? ConfigLoadedEvent.LoadReason.LOCAL_SHADOW : ConfigLoadedEvent.LoadReason.SHADOW; - MinecraftForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, reason, this.clientConfig, this.path, loadPath)); + NeoForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, reason, this.clientConfig, this.path, loadPath)); } public void restore() { @@ -308,14 +307,14 @@ public void restore() { } this.shadowed = false; this.shadowedLocal = false; - MinecraftForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, ConfigLoadedEvent.LoadReason.RESTORE, this.clientConfig, this.path, this.path)); + NeoForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, ConfigLoadedEvent.LoadReason.RESTORE, this.clientConfig, this.path, this.path)); } public void reloadClientWorldState() { - if (FMLEnvironment.dist == Dist.CLIENT) { + if (FMLLoader.getDist() == Dist.CLIENT) { if (!this.shadowed || this.shadowedLocal) { - Level clientLevel = DistExecutor.unsafeRunForDist(() -> () -> Minecraft.getInstance().level, () -> () -> null); - MinecraftServer server = DistExecutor.unsafeRunForDist(() -> Minecraft.getInstance()::getSingleplayerServer, () -> () -> null); + Level clientLevel = ClientCallbacks.getClientLevel(); + MinecraftServer server = ClientCallbacks.getSinglePlayerServer(); if (clientLevel != null && server != null) { Path configDir = server.storageSource.getWorldDir().resolve("config"); Path configPath = resolveConfigPath(configDir, this.id); @@ -358,7 +357,7 @@ public void applyInGameChanges(ConfigState newState) { LibX.logger.warn("Failed to save config file from InGame values: " + e.getMessage(), e); } if (!this.shadowed) { - MinecraftForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, ConfigLoadedEvent.LoadReason.INGAME_CHANGES, this.clientConfig, this.path, null)); + NeoForge.EVENT_BUS.post(new ConfigLoadedEvent(this.id, this.baseClass, ConfigLoadedEvent.LoadReason.INGAME_CHANGES, this.clientConfig, this.path, null)); } } @@ -374,7 +373,7 @@ public void setDefaultState(ConfigState defaultState) { } public ConfigState cachedOrCurrent() { - if (FMLEnvironment.dist != Dist.DEDICATED_SERVER) { + if (FMLLoader.getDist() != Dist.DEDICATED_SERVER) { LibX.logger.error("Config cached or current method was called on a physical client. This should not happen!"); } if (this.savedState == null) { @@ -391,4 +390,17 @@ public boolean isShadowed() { public static Path resolveConfigPath(Path configDir, ResourceLocation id) { return id.getPath().equals("config") ? configDir.resolve(id.getNamespace() + ".json5") : configDir.resolve(id.getNamespace()).resolve(id.getPath() + ".json5"); } + + private static class ClientCallbacks { + + @Nullable + public static Level getClientLevel() { + return Minecraft.getInstance().level; + } + + @Nullable + public static MinecraftServer getSinglePlayerServer() { + return Minecraft.getInstance().getSingleplayerServer(); + } + } } diff --git a/src/main/java/org/moddingx/libx/impl/config/ConfigKey.java b/src/main/java/org/moddingx/libx/impl/config/ConfigKey.java index 58fce5a7..5a08daed 100644 --- a/src/main/java/org/moddingx/libx/impl/config/ConfigKey.java +++ b/src/main/java/org/moddingx/libx/impl/config/ConfigKey.java @@ -1,6 +1,8 @@ package org.moddingx.libx.impl.config; import com.google.common.collect.ImmutableList; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import org.moddingx.libx.config.Config; import org.moddingx.libx.config.mapper.ValueMapper; import org.moddingx.libx.config.validator.ValidatorInfo; @@ -21,6 +23,7 @@ public class ConfigKey { public final Field field; public final ValueMapper mapper; + public final StreamCodec streamCodec; public final List path; public final List comment; private final ConfiguredValidator validator; @@ -28,6 +31,7 @@ public class ConfigKey { private ConfigKey(Field field, ValueMapper mapper, ImmutableList path, ImmutableList comment, ConfiguredValidator validator) { this.field = field; this.mapper = mapper; + this.streamCodec = mapper.streamCodec(); this.path = path; ImmutableList.Builder commentBuilder = ImmutableList.builder(); commentBuilder.addAll(comment); diff --git a/src/main/java/org/moddingx/libx/impl/config/ConfigState.java b/src/main/java/org/moddingx/libx/impl/config/ConfigState.java index c07162eb..9e0b9220 100644 --- a/src/main/java/org/moddingx/libx/impl/config/ConfigState.java +++ b/src/main/java/org/moddingx/libx/impl/config/ConfigState.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import org.moddingx.libx.config.mapper.ValueMapper; import javax.annotation.Nonnull; @@ -58,7 +59,7 @@ public void write(FriendlyByteBuf buffer) { buffer.writeUtf(key.field.getDeclaringClass().getName(), 0x7fff); buffer.writeUtf(key.field.getName(), 0x7fff); //noinspection unchecked - ((ValueMapper) key.mapper).toNetwork(value, buffer); + ((StreamCodec) key.streamCodec).encode(buffer, value); } } diff --git a/src/main/java/org/moddingx/libx/impl/config/ModMappers.java b/src/main/java/org/moddingx/libx/impl/config/ModMappers.java index 5a4ceeda..f44a845e 100644 --- a/src/main/java/org/moddingx/libx/impl/config/ModMappers.java +++ b/src/main/java/org/moddingx/libx/impl/config/ModMappers.java @@ -2,11 +2,11 @@ import com.google.common.collect.ImmutableMap; import com.google.gson.JsonElement; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.api.distmarker.OnlyIns; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.loading.FMLEnvironment; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.OnlyIns; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.loading.FMLLoader; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.moddingx.libx.LibX; @@ -18,12 +18,15 @@ import org.moddingx.libx.config.validator.ConfigValidator; import org.moddingx.libx.impl.config.gui.ModConfigGuiAdapter; import org.moddingx.libx.impl.config.mappers.SimpleValueMappers; -import org.moddingx.libx.impl.config.mappers.advanced.*; +import org.moddingx.libx.impl.config.mappers.advanced.ComponentValueMapper; +import org.moddingx.libx.impl.config.mappers.advanced.ResourceListValueMapper; +import org.moddingx.libx.impl.config.mappers.advanced.ResourceValueMapper; +import org.moddingx.libx.impl.config.mappers.advanced.UidValueMapper; import org.moddingx.libx.impl.config.mappers.generic.ListValueMapper; import org.moddingx.libx.impl.config.mappers.generic.MapValueMapper; import org.moddingx.libx.impl.config.mappers.generic.OptionValueMapper; import org.moddingx.libx.impl.config.mappers.generic.SetValueMapper; -import org.moddingx.libx.impl.config.mappers.special.EnumValueMappers; +import org.moddingx.libx.impl.config.mappers.special.EnumValueMapper; import org.moddingx.libx.impl.config.mappers.special.PairValueMapper; import org.moddingx.libx.impl.config.mappers.special.RecordValueMapper; import org.moddingx.libx.impl.config.mappers.special.TripleValueMapper; @@ -71,10 +74,8 @@ public static ModMappers get(String modid) { SimpleValueMappers.DOUBLE, SimpleValueMappers.STRING, ResourceValueMapper.INSTANCE, - IngredientValueMapper.INSTANCE, ComponentValueMapper.INSTANCE, ResourceListValueMapper.INSTANCE, - IngredientStackValueMapper.INSTANCE, UidValueMapper.INSTANCE ).collect(ImmutableMap.toImmutableMap(ValueMapper::type, Function.identity())); @@ -160,8 +161,8 @@ public void registerConfigValidator(ConfigValidator validator) { } else if (globalGenericMappers.containsKey(cls)) { return this.resolveGeneric(globalGenericMappers.get(cls), type); } else if (cls.isEnum()) { - //noinspection unchecked - return EnumValueMappers.getMapper((Class>) cls); + //noinspection unchecked,rawtypes + return EnumValueMapper.getMapper((Class) cls); } else if (cls == Pair.class) { return new PairValueMapper<>(this.getWrappedMapperUnsafe(type, 0), this.getWrappedMapperUnsafe(type, 1)); } else if (cls == Triple.class) { @@ -209,17 +210,13 @@ public Type getGenericType() { } private static Class getTypeClass(Type type) { - if (type instanceof Class cls) { - return cls; - } else if (type instanceof ParameterizedType ptype) { - return getTypeClass(ptype.getRawType()); - } else if (type instanceof TypeVariable) { - throw new IllegalStateException("Type variables are not allowed in config field types."); - } else if (type instanceof WildcardType) { - throw new IllegalStateException("Wildcard types are not allowed in config field types."); - } else { - throw new IllegalStateException("Unknown declared type of config field: " + type); - } + return switch (type) { + case Class cls -> cls; + case ParameterizedType ptype -> getTypeClass(ptype.getRawType()); + case TypeVariable typeVariable -> throw new IllegalStateException("Type variables are not allowed in config field types."); + case WildcardType wildcardType -> throw new IllegalStateException("Wildcard types are not allowed in config field types."); + case null, default -> throw new IllegalStateException("Unknown declared type of config field: " + type); + }; } @Nullable @@ -248,9 +245,9 @@ public ConfigValidator getValidatorByAnnotation(Cla } } - public void initAdapter(ModLoadingContext context) { - if (this.adapter == null && FMLEnvironment.dist == Dist.CLIENT) { - this.adapter = new ModConfigGuiAdapter(this.modid, context.getActiveContainer()); + public void initAdapter(ModContainer modContainer) { + if (this.adapter == null && FMLLoader.getDist() == Dist.CLIENT) { + this.adapter = new ModConfigGuiAdapter(this.modid, modContainer); } } diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/ModConfigGuiAdapter.java b/src/main/java/org/moddingx/libx/impl/config/gui/ModConfigGuiAdapter.java index 16b0693f..3974a142 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/ModConfigGuiAdapter.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/ModConfigGuiAdapter.java @@ -2,8 +2,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; -import net.minecraftforge.client.ConfigScreenHandler; -import net.minecraftforge.fml.ModContainer; +import net.neoforged.fml.ModContainer; +import net.neoforged.neoforge.client.gui.IConfigScreenFactory; import org.moddingx.libx.impl.config.ConfigImpl; import org.moddingx.libx.impl.config.gui.screen.ConfigScreenManager; import org.moddingx.libx.impl.config.gui.screen.ConfigSelectScreen; @@ -29,11 +29,11 @@ public ModConfigGuiAdapter(String modid, ModContainer context) { public synchronized void checkRegister() { if (!this.hasRegisteredExt && ConfigImpl.getAllConfigs().stream().anyMatch(config -> this.modid.equals(config.id.getNamespace()))) { this.hasRegisteredExt = true; - this.context.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory(this::createScreen)); + this.context.registerExtensionPoint(IConfigScreenFactory.class, this::createScreen); } } - public Screen createScreen(Minecraft minecraft, Screen modListScreen) { + public Screen createScreen(ModContainer modContainer, Screen modListScreen) { List configs = ConfigImpl.getAllConfigs().stream() .filter(config -> this.modid.equals(config.id.getNamespace())) .sorted(Comparator.comparing(config -> "config".equals(config.id.getPath()) ? "" : config.id.getPath())) @@ -41,9 +41,9 @@ public Screen createScreen(Minecraft minecraft, Screen modListScreen) { if (configs.isEmpty()) { return modListScreen; } else if (configs.size() == 1) { - return this.factory(minecraft, modListScreen).apply(configs.get(0)); + return this.factory(modListScreen.getMinecraft(), modListScreen).apply(configs.get(0)); } else { - return new ConfigSelectScreen(this.factory(minecraft, modListScreen), configs, modListScreen); + return new ConfigSelectScreen(this.factory(modListScreen.getMinecraft(), modListScreen), configs, modListScreen); } } diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/editor/CheckEditor.java b/src/main/java/org/moddingx/libx/impl/config/gui/editor/CheckEditor.java index bee86da6..6876880b 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/editor/CheckEditor.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/editor/CheckEditor.java @@ -22,27 +22,27 @@ public Boolean defaultValue() { @Override public AbstractWidget createWidget(Screen screen, Boolean initialValue, WidgetProperties properties) { - int padding = Math.max(0, properties.width() - 20) / 2; - return new Checkbox(padding + properties.x(), properties.y(), 20, properties.height(), Component.empty(), initialValue, false) { - @Override - public void onPress() { - super.onPress(); - properties.inputChanged().accept(this.selected()); - } - }; + int paddingX = Math.max(0, properties.width() - 20) / 2; + int paddingY = Math.max(0, properties.height() - 20) / 2; + return Checkbox.builder(Component.empty(), screen.getMinecraft().font) + .pos(paddingX + properties.x(), paddingY + properties.y()) + .maxWidth(properties.width()) + .selected(initialValue) + .onValueChange((c, sel) -> properties.inputChanged().accept(sel)) + .build(); } @Override public AbstractWidget updateWidget(Screen screen, AbstractWidget oldWidget, WidgetProperties properties) { if (oldWidget instanceof Checkbox old) { - int padding = Math.max(0, properties.width() - 20) / 2; - return new Checkbox(padding + properties.x(), properties.y(), 20, properties.height(), Component.empty(), old.selected(), false) { - @Override - public void onPress() { - super.onPress(); - properties.inputChanged().accept(this.selected()); - } - }; + int paddingX = Math.max(0, properties.width() - 20) / 2; + int paddingY = Math.max(0, properties.height() - 20) / 2; + return Checkbox.builder(Component.empty(), screen.getMinecraft().font) + .pos(paddingX + properties.x(), paddingY + properties.y()) + .maxWidth(properties.width()) + .selected(old.selected()) + .onValueChange((c, sel) -> properties.inputChanged().accept(sel)) + .build(); } else { return this.createWidget(screen, this.defaultValue(), properties); } diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/editor/OptionEditor.java b/src/main/java/org/moddingx/libx/impl/config/gui/editor/OptionEditor.java index fa6d09dd..b58f62bd 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/editor/OptionEditor.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/editor/OptionEditor.java @@ -56,14 +56,15 @@ private OptionWidget(Screen screen, ConfigEditor editor, WidgetProperties { + EditorOps.wrap(OptionWidget.this.widget).enabled(sel); + OptionWidget.this.update(null); + }) + .build(); WidgetProperties modified = new WidgetProperties<>(22, 0, properties.width(), properties.height(), this::update); this.widget = EditorHelper.create(screen, editor, this.value, old, modified); diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/screen/ConfigBaseScreen.java b/src/main/java/org/moddingx/libx/impl/config/gui/screen/ConfigBaseScreen.java index d6377e90..75fef984 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/screen/ConfigBaseScreen.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/screen/ConfigBaseScreen.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.datafixers.util.Either; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -19,7 +20,7 @@ import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.client.gui.widget.ScrollPanel; +import net.neoforged.neoforge.client.gui.widget.ScrollPanel; import org.apache.commons.lang3.tuple.Pair; import org.joml.Matrix4f; import org.lwjgl.glfw.GLFW; @@ -116,7 +117,7 @@ protected int getContentHeight() { } @Override - public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { ConfigBaseScreen.this.isCapturingTooltips = true; graphics.pose().pushPose(); super.render(new TooltipCapturingGuiGraphics(graphics), mouseX, mouseY, partialTicks); @@ -125,7 +126,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi ConfigBaseScreen.this.capturedTooltips.forEach(pair -> { graphics.pose().pushPose(); graphics.pose().setIdentity(); - graphics.pose().mulPoseMatrix(pair.getLeft()); + graphics.pose().mulPose(pair.getLeft()); pair.getRight().accept(graphics); graphics.pose().popPose(); }); @@ -133,12 +134,12 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi } @Override - protected void drawPanel(GuiGraphics graphics, int entryRight, int relativeY, Tesselator tess, int mouseX, int mouseY) { + protected void drawPanel(@Nonnull GuiGraphics graphics, int entryRight, int relativeY, @Nonnull Tesselator tesselator, int mouseX, int mouseY) { ConfigBaseScreen.this.currentScrollOffset = relativeY; graphics.pose().pushPose(); graphics.pose().translate(0, relativeY, 0); for (AbstractWidget widget : widgets) { - widget.render(graphics, mouseX, mouseY - relativeY, ConfigBaseScreen.this.mc.getDeltaFrameTime()); + widget.render(graphics, mouseX, mouseY - relativeY, ConfigBaseScreen.this.mc.getTimer().getGameTimeDeltaTicks()); } graphics.pose().popPose(); ConfigBaseScreen.this.currentScrollOffset = 0; @@ -209,7 +210,7 @@ public ConfigScreenManager getCurrentManager() { @Override public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { - this.renderDirtBackground(graphics); + this.renderMenuBackground(graphics); super.render(graphics, mouseX, mouseY, partialTicks); RenderHelper.resetColor(); graphics.drawString(this.font, this.getTitle(), (this.width - this.mc.font.width(this.getTitle())) / 2, 11, 0xFFFFFF, true); @@ -335,5 +336,14 @@ public void renderTooltip(@Nonnull Font font, @Nonnull List> elements, int mouseX, int mouseY, @Nonnull ItemStack stack) { + if (ConfigBaseScreen.this.isCapturingTooltips) { + ConfigBaseScreen.this.captureTooltip(this.pose().last(), (graphics, scrollOffset) -> super.renderComponentTooltipFromElements(font, elements, mouseX, mouseY + scrollOffset, stack)); + } else { + super.renderComponentTooltipFromElements(font, elements, mouseX, mouseY, stack); + } + } } } diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/ResourceListContent.java b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/ResourceListContent.java index e59bcc5e..e85793b1 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/ResourceListContent.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/ResourceListContent.java @@ -117,9 +117,9 @@ public void buildGui(Screen screen, ScreenManager manager, String search, Consum Component.translatable("libx.config.gui.resource_list.info").withStyle(Style.EMPTY.withUnderlined(true).withColor(ChatFormatting.BLUE)), List.of()) { @Override - public void onClick(double mouseX, double mouseY) { + public void onClick(double mouseX, double mouseY, int button) { try { - Util.getPlatform().openUrl(ResourceListValueMapper.INFO_URL); + Util.getPlatform().openUri(ResourceListValueMapper.INFO_URL); } catch (Exception e) { // } diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/ComponentContent.java b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/ComponentContent.java index 074369fe..3fc70c3c 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/ComponentContent.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/ComponentContent.java @@ -253,15 +253,16 @@ public void buildGui(Screen screen, ScreenManager manager, String search, Consum y += 25; - Checkbox hasColorWidget = new Checkbox(14, y + ((ColorPicker.HEIGHT - 20) / 2), 20, 20, Component.empty(), this.hasColor, false) { - @Override - public void onPress() { - super.onPress(); - ComponentContent.this.hasColor = this.selected(); - EditorOps.wrap(ComponentContent.this.colorWidget).enabled(ComponentContent.this.hasColor); - ComponentContent.this.update(); - } - }; + Checkbox hasColorWidget = Checkbox.builder(Component.empty(), screen.getMinecraft().font) + .pos(14, y + ((ColorPicker.HEIGHT - 20) / 2)) + .maxWidth(20) + .selected(this.hasColor) + .onValueChange((checkbox, value) -> { + ComponentContent.this.hasColor = value; + EditorOps.wrap(ComponentContent.this.colorWidget).enabled(ComponentContent.this.hasColor); + ComponentContent.this.update(); + }) + .build(); consumer.accept(hasColorWidget); this.colorWidget = new ColorPicker(37, y, this.colorWidget); diff --git a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/type/TextComponentType.java b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/type/TextComponentType.java index ed7a596f..c48a095c 100644 --- a/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/type/TextComponentType.java +++ b/src/main/java/org/moddingx/libx/impl/config/gui/screen/content/component/type/TextComponentType.java @@ -3,9 +3,8 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentContents; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; +import net.minecraft.network.chat.contents.PlainTextContents; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.gui.ConfigScreenContent; import org.moddingx.libx.config.gui.WidgetProperties; @@ -43,11 +42,11 @@ public MutableComponent defaultValue() { @Override public MutableComponent init(Component component, Consumer inputChanged) { this.inputChanged = inputChanged; - if (component.getContents() == ComponentContents.EMPTY) { + if (component.getContents() == PlainTextContents.EMPTY) { this.value = ""; return component.plainCopy(); - } else if (component.getContents() instanceof LiteralContents lc) { - this.value = lc.text(); + } else if (component.getContents() instanceof PlainTextContents pc) { + this.value = pc.text(); return component.plainCopy(); } else { return null; diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/SimpleValueMappers.java b/src/main/java/org/moddingx/libx/impl/config/mappers/SimpleValueMappers.java index 800c7b4b..4076fb56 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/SimpleValueMappers.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/SimpleValueMappers.java @@ -2,9 +2,11 @@ import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.gui.InputProperties; import org.moddingx.libx.config.mapper.ValueMapper; @@ -41,13 +43,8 @@ public JsonPrimitive toJson(Boolean value) { } @Override - public Boolean fromNetwork(FriendlyByteBuf buffer) { - return buffer.readBoolean(); - } - - @Override - public void toNetwork(Boolean value, FriendlyByteBuf buffer) { - buffer.writeBoolean(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.BOOL; } @Override @@ -80,13 +77,8 @@ public JsonPrimitive toJson(Byte value) { } @Override - public Byte fromNetwork(FriendlyByteBuf buffer) { - return buffer.readByte(); - } - - @Override - public void toNetwork(Byte value, FriendlyByteBuf buffer) { - buffer.writeByte(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.BYTE; } @Override @@ -119,13 +111,8 @@ public JsonPrimitive toJson(Short value) { } @Override - public Short fromNetwork(FriendlyByteBuf buffer) { - return buffer.readShort(); - } - - @Override - public void toNetwork(Short value, FriendlyByteBuf buffer) { - buffer.writeShort(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.SHORT; } @Override @@ -166,13 +153,8 @@ public JsonPrimitive toJson(Integer value) { } @Override - public Integer fromNetwork(FriendlyByteBuf buffer) { - return buffer.readVarInt(); - } - - @Override - public void toNetwork(Integer value, FriendlyByteBuf buffer) { - buffer.writeVarInt(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.VAR_INT; } @Override @@ -213,13 +195,8 @@ public JsonPrimitive toJson(Long value) { } @Override - public Long fromNetwork(FriendlyByteBuf buffer) { - return buffer.readVarLong(); - } - - @Override - public void toNetwork(Long value, FriendlyByteBuf buffer) { - buffer.writeVarLong(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.VAR_LONG; } @Override @@ -260,13 +237,8 @@ public JsonPrimitive toJson(Float value) { } @Override - public Float fromNetwork(FriendlyByteBuf buffer) { - return buffer.readFloat(); - } - - @Override - public void toNetwork(Float value, FriendlyByteBuf buffer) { - buffer.writeFloat(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.FLOAT; } @Override @@ -307,13 +279,8 @@ public JsonPrimitive toJson(Double value) { } @Override - public Double fromNetwork(FriendlyByteBuf buffer) { - return buffer.readDouble(); - } - - @Override - public void toNetwork(Double value, FriendlyByteBuf buffer) { - buffer.writeDouble(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.DOUBLE; } @Override @@ -354,13 +321,8 @@ public JsonPrimitive toJson(String value) { } @Override - public String fromNetwork(FriendlyByteBuf buffer) { - return buffer.readUtf(); - } - - @Override - public void toNetwork(String value, FriendlyByteBuf buffer) { - buffer.writeUtf(value); + public StreamCodec streamCodec() { + return ByteBufCodecs.STRING_UTF8; } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ComponentValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ComponentValueMapper.java index f546ef57..90ba209f 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ComponentValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ComponentValueMapper.java @@ -2,12 +2,13 @@ import com.google.gson.JsonElement; import net.minecraft.network.chat.Component; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.ValueMapper; import org.moddingx.libx.config.validator.ValidatorInfo; import org.moddingx.libx.impl.config.gui.screen.content.component.ComponentContent; +import org.moddingx.libx.impl.registration.BuiltinRegistryHelper; public class ComponentValueMapper implements ValueMapper { @@ -29,12 +30,12 @@ public Class element() { @Override public Component fromJson(JsonElement json) { - return Component.Serializer.fromJson(json); + return Component.Serializer.deserialize(json, BuiltinRegistryHelper.BUILTIN_REGISTRY_LOOKUP); } @Override public JsonElement toJson(Component value) { - return Component.Serializer.toJsonTree(value); + return Component.Serializer.serialize(value, BuiltinRegistryHelper.BUILTIN_REGISTRY_LOOKUP); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientStackValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientStackValueMapper.java deleted file mode 100644 index bfb0eed5..00000000 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientStackValueMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.moddingx.libx.impl.config.mappers.advanced; - -import com.google.gson.JsonObject; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import org.moddingx.libx.config.gui.ConfigEditor; -import org.moddingx.libx.config.mapper.ValueMapper; -import org.moddingx.libx.config.validator.ValidatorInfo; -import org.moddingx.libx.crafting.IngredientStack; - -public class IngredientStackValueMapper implements ValueMapper { - - public static final IngredientStackValueMapper INSTANCE = new IngredientStackValueMapper(); - - private IngredientStackValueMapper() { - - } - - @Override - public Class type() { - return IngredientStack.class; - } - - @Override - public Class element() { - return JsonObject.class; - } - - @Override - public IngredientStack fromJson(JsonObject json) { - return IngredientStack.fromJson(json); - } - - @Override - public JsonObject toJson(IngredientStack value) { - return value.toJson(); - } - - @Override - public IngredientStack fromNetwork(FriendlyByteBuf buffer) { - return IngredientStack.fromNetwork(buffer); - } - - @Override - public void toNetwork(IngredientStack value, FriendlyByteBuf buffer) { - value.toNetwork(buffer); - } - - @Override - @OnlyIn(Dist.CLIENT) - public ConfigEditor createEditor(ValidatorInfo validator) { - return ConfigEditor.unsupported(IngredientStack.EMPTY); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientValueMapper.java deleted file mode 100644 index be1a2137..00000000 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/IngredientValueMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.moddingx.libx.impl.config.mappers.advanced; - -import com.google.gson.JsonElement; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import org.moddingx.libx.config.gui.ConfigEditor; -import org.moddingx.libx.config.mapper.ValueMapper; -import org.moddingx.libx.config.validator.ValidatorInfo; - -public class IngredientValueMapper implements ValueMapper { - - public static final IngredientValueMapper INSTANCE = new IngredientValueMapper(); - - private IngredientValueMapper() { - - } - - @Override - public Class type() { - return Ingredient.class; - } - - @Override - public Class element() { - return JsonElement.class; - } - - @Override - public Ingredient fromJson(JsonElement json) { - return Ingredient.fromJson(json); - } - - @Override - public JsonElement toJson(Ingredient value) { - return value.toJson(); - } - - @Override - public Ingredient fromNetwork(FriendlyByteBuf buffer) { - return Ingredient.fromNetwork(buffer); - } - - @Override - public void toNetwork(Ingredient value, FriendlyByteBuf buffer) { - value.toNetwork(buffer); - } - - @Override - @OnlyIn(Dist.CLIENT) - public ConfigEditor createEditor(ValidatorInfo validator) { - return ConfigEditor.unsupported(Ingredient.EMPTY); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceListValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceListValueMapper.java index cbf51330..363de2d2 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceListValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceListValueMapper.java @@ -2,31 +2,23 @@ import com.google.gson.JsonObject; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.ValueMapper; import org.moddingx.libx.config.validator.ValidatorInfo; import org.moddingx.libx.impl.config.gui.screen.content.ResourceListContent; import org.moddingx.libx.util.data.ResourceList; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; import java.util.List; public class ResourceListValueMapper implements ValueMapper { public static final ResourceListValueMapper INSTANCE = new ResourceListValueMapper(); - public static final URL INFO_URL; - - static { - try { - INFO_URL = new URL("https://moddingx.org/libx/org/moddingx/libx/util/data/ResourceList.html#use_resource_lists_in_configs"); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } + public static final URI INFO_URL = URI.create("https://moddingx.org/libx/org/moddingx/libx/util/data/ResourceList.html#use_resource_lists_in_configs"); private static final List COMMENT = List.of("This is a resource list. See " + INFO_URL); @@ -55,13 +47,8 @@ public JsonObject toJson(ResourceList value) { } @Override - public ResourceList fromNetwork(FriendlyByteBuf buffer) { - return new ResourceList(buffer); - } - - @Override - public void toNetwork(ResourceList value, FriendlyByteBuf buffer) { - value.toNetwork(buffer); + public StreamCodec streamCodec() { + return ResourceList.STREAM_CODEC; } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceValueMapper.java index 6651cc73..59d8061a 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/ResourceValueMapper.java @@ -2,9 +2,10 @@ import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.gui.InputProperties; import org.moddingx.libx.config.mapper.ValueMapper; @@ -33,7 +34,7 @@ public boolean isValid(String str) { @Override public ResourceLocation valueOf(String str) { - return new ResourceLocation(str); + return ResourceLocation.parse(str); } }; @@ -53,7 +54,7 @@ public Class element() { @Override public ResourceLocation fromJson(JsonPrimitive json) { - return new ResourceLocation(json.getAsString()); + return ResourceLocation.parse(json.getAsString()); } @Override @@ -62,13 +63,8 @@ public JsonPrimitive toJson(ResourceLocation value) { } @Override - public ResourceLocation fromNetwork(FriendlyByteBuf buffer) { - return buffer.readResourceLocation(); - } - - @Override - public void toNetwork(ResourceLocation value, FriendlyByteBuf buffer) { - buffer.writeResourceLocation(value); + public StreamCodec streamCodec() { + return ResourceLocation.STREAM_CODEC; } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/UidValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/UidValueMapper.java index b1f58940..67b0c7b7 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/UidValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/advanced/UidValueMapper.java @@ -2,8 +2,9 @@ import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.gui.InputProperties; import org.moddingx.libx.config.mapper.ValueMapper; @@ -29,7 +30,6 @@ public boolean canInputChar(char chr) { @Override public boolean isValid(String str) { try { - //noinspection ResultOfMethodCallIgnored UUID.fromString(str); return true; } catch (IllegalArgumentException e) { @@ -68,16 +68,8 @@ public JsonPrimitive toJson(UUID value) { } @Override - public UUID fromNetwork(FriendlyByteBuf buffer) { - long mostSignificantBits = buffer.readLong(); - long leastSignificantBits = buffer.readLong(); - return new UUID(mostSignificantBits, leastSignificantBits); - } - - @Override - public void toNetwork(UUID value, FriendlyByteBuf buffer) { - buffer.writeLong(value.getMostSignificantBits()); - buffer.writeLong(value.getLeastSignificantBits()); + public StreamCodec streamCodec() { + return StreamCodec.of((buf, uid) -> buf.writeUUID(uid), buf -> buf.readUUID()); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/ListValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/ListValueMapper.java index f8a013a6..a5a98136 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/ListValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/ListValueMapper.java @@ -4,8 +4,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.moddingx.libx.codec.MoreStreamCodecs; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -61,21 +63,8 @@ public JsonArray toJson(List value, ValueMapper mapper) { } @Override - public List fromNetwork(FriendlyByteBuf buffer, ValueMapper mapper) { - int size = buffer.readVarInt(); - ImmutableList.Builder builder = ImmutableList.builder(); - for (int i = 0; i < size; i++) { - builder.add(mapper.fromNetwork(buffer)); - } - return builder.build(); - } - - @Override - public void toNetwork(List value, FriendlyByteBuf buffer, ValueMapper mapper) { - buffer.writeVarInt(value.size()); - for (T element : value) { - mapper.toNetwork(element, buffer); - } + public StreamCodec> streamCodec(ValueMapper mapper) { + return MoreStreamCodecs.listOf(mapper.streamCodec()); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/MapValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/MapValueMapper.java index cc2a98ca..ce9a77be 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/MapValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/MapValueMapper.java @@ -4,8 +4,11 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.moddingx.libx.codec.MoreStreamCodecs; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -59,22 +62,8 @@ public JsonObject toJson(Map value, ValueMapper mappe } @Override - public Map fromNetwork(FriendlyByteBuf buffer, ValueMapper mapper) { - int size = buffer.readVarInt(); - ImmutableMap.Builder builder = ImmutableMap.builder(); - for (int i = 0; i < size; i++) { - builder.put(buffer.readUtf(0x7fff), mapper.fromNetwork(buffer)); - } - return builder.build(); - } - - @Override - public void toNetwork(Map value, FriendlyByteBuf buffer, ValueMapper mapper) { - buffer.writeVarInt(value.size()); - for (Map.Entry entry : value.entrySet()) { - buffer.writeUtf(entry.getKey(), 0x7fff); - mapper.toNetwork(entry.getValue(), buffer); - } + public StreamCodec> streamCodec(ValueMapper mapper) { + return MoreStreamCodecs.mapOf(ByteBufCodecs.STRING_UTF8, mapper.streamCodec()); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/OptionValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/OptionValueMapper.java index 478e2a3d..7c7a7f40 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/OptionValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/OptionValueMapper.java @@ -3,8 +3,10 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.moddingx.libx.codec.MoreStreamCodecs; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -57,22 +59,8 @@ public JsonElement toJson(Optional value, ValueMapper mapper) } @Override - public Optional fromNetwork(FriendlyByteBuf buffer, ValueMapper mapper) { - if (!buffer.readBoolean()) { - return Optional.empty(); - } else { - return Optional.of(mapper.fromNetwork(buffer)); - } - } - - @Override - public void toNetwork(Optional value, FriendlyByteBuf buffer, ValueMapper mapper) { - if (value.isEmpty()) { - buffer.writeBoolean(false); - } else { - buffer.writeBoolean(true); - mapper.toNetwork(value.get(), buffer); - } + public StreamCodec> streamCodec(ValueMapper mapper) { + return MoreStreamCodecs.maybe(mapper.streamCodec()); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/SetValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/SetValueMapper.java index 319ab8d3..cce80247 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/generic/SetValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/generic/SetValueMapper.java @@ -4,8 +4,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.moddingx.libx.codec.MoreStreamCodecs; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -77,21 +79,8 @@ public JsonArray toJson(Set value, ValueMapper mapper) { } @Override - public Set fromNetwork(FriendlyByteBuf buffer, ValueMapper mapper) { - int size = buffer.readVarInt(); - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (int i = 0; i < size; i++) { - builder.add(mapper.fromNetwork(buffer)); - } - return builder.build(); - } - - @Override - public void toNetwork(Set value, FriendlyByteBuf buffer, ValueMapper mapper) { - buffer.writeVarInt(value.size()); - for (T element : value) { - mapper.toNetwork(element, buffer); - } + public StreamCodec> streamCodec(ValueMapper mapper) { + return MoreStreamCodecs.listOf(mapper.streamCodec()).map(Set::copyOf, List::copyOf); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMappers.java b/src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMapper.java similarity index 63% rename from src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMappers.java rename to src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMapper.java index 0f3f51e5..2f168b1d 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMappers.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/special/EnumValueMapper.java @@ -5,8 +5,10 @@ import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.ValueMapper; @@ -15,34 +17,34 @@ import java.util.*; import java.util.stream.Collectors; -public class EnumValueMappers implements ValueMapper, JsonPrimitive> { +public class EnumValueMapper> implements ValueMapper { - private static final Map>, EnumValueMappers> mappers = new HashMap<>(); + private static final Map>, EnumValueMapper> mappers = new HashMap<>(); - public static EnumValueMappers getMapper(Class> enumClass) { + public static > EnumValueMapper getMapper(Class enumClass) { if (!enumClass.isEnum()) { throw new IllegalArgumentException("Can't get enum serializer for non-enum class: " + enumClass); } else if (enumClass.getEnumConstants().length == 0) { throw new IllegalArgumentException("Can't get enum serializer for empty enum: " + enumClass); } else if (mappers.containsKey(enumClass)) { - return mappers.get(enumClass); + //noinspection unchecked + return (EnumValueMapper) mappers.get(enumClass); } else { - EnumValueMappers mapper = new EnumValueMappers(enumClass); + EnumValueMapper mapper = new EnumValueMapper<>(enumClass); mappers.put(enumClass, mapper); return mapper; } } - private final Class> clazz; + private final Class cls; - public EnumValueMappers(Class> clazz) { - this.clazz = clazz; + public EnumValueMapper(Class cls) { + this.cls = cls; } @Override - public Class> type() { - //noinspection unchecked - return (Class>) (Class) Enum.class; + public Class type() { + return this.cls; } @Override @@ -51,10 +53,10 @@ public Class element() { } @Override - public Enum fromJson(JsonPrimitive json) { + public T fromJson(JsonPrimitive json) { String str = json.getAsString().toLowerCase(Locale.ROOT).strip(); - Enum[] enums = this.clazz.getEnumConstants(); - for (Enum e : enums) { + T[] enums = this.cls.getEnumConstants(); + for (T e : enums) { if (e.name().toLowerCase(Locale.ROOT).equals(str)) { return e; } @@ -63,26 +65,21 @@ public Enum fromJson(JsonPrimitive json) { } @Override - public JsonPrimitive toJson(Enum value) { + public JsonPrimitive toJson(T value) { return new JsonPrimitive(value.name().toLowerCase(Locale.ROOT)); } @Override - public Enum fromNetwork(FriendlyByteBuf buffer) { - return this.clazz.getEnumConstants()[buffer.readVarInt()]; + public StreamCodec streamCodec() { + return NeoForgeStreamCodecs.enumCodec(this.cls); } @Override - public void toNetwork(Enum value, FriendlyByteBuf buffer) { - buffer.writeVarInt(value.ordinal()); - } - - @Override - public Optional> correct(JsonElement json, ConfigCorrection> correction) { + public Optional correct(JsonElement json, ConfigCorrection correction) { if (json.isJsonPrimitive() || json.isJsonNull()) { String str = json.isJsonNull() ? "null" : json.getAsString().toLowerCase(Locale.ROOT).strip(); - Enum[] enums = this.clazz.getEnumConstants(); - for (Enum e : enums) { + T[] enums = this.cls.getEnumConstants(); + for (T e : enums) { if (e.name().toLowerCase(Locale.ROOT).equals(str) || str.startsWith(e.name()) || str.endsWith(e.name())) { return Optional.of(e); } @@ -104,7 +101,7 @@ public Optional> correct(JsonElement json, ConfigCorrection> cor @Override public List comment() { - return List.of("Allowed values: " + Arrays.stream(this.clazz.getEnumConstants()) + return List.of("Allowed values: " + Arrays.stream(this.cls.getEnumConstants()) .map(e -> e.name().toLowerCase(Locale.ROOT)) .collect(Collectors.joining(", ")) ); @@ -112,7 +109,7 @@ public List comment() { @Override @OnlyIn(Dist.CLIENT) - public ConfigEditor> createEditor(ValidatorInfo validator) { - return ConfigEditor.toggle(ImmutableList.copyOf(this.clazz.getEnumConstants()), e -> Component.literal(e.name().toLowerCase(Locale.ROOT))); + public ConfigEditor createEditor(ValidatorInfo validator) { + return ConfigEditor.toggle(ImmutableList.copyOf(this.cls.getEnumConstants()), e -> Component.literal(e.name().toLowerCase(Locale.ROOT))); } } diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/special/PairValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/special/PairValueMapper.java index 5bd3a316..e797a452 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/special/PairValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/special/PairValueMapper.java @@ -4,8 +4,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; @@ -55,14 +56,12 @@ public JsonArray toJson(Pair value) { } @Override - public Pair fromNetwork(FriendlyByteBuf buffer) { - return Pair.of(this.mapper1.fromNetwork(buffer), this.mapper2.fromNetwork(buffer)); - } - - @Override - public void toNetwork(Pair value, FriendlyByteBuf buffer) { - this.mapper1.toNetwork(value.getLeft(), buffer); - this.mapper2.toNetwork(value.getRight(), buffer); + public StreamCodec> streamCodec() { + return StreamCodec.composite( + this.mapper1.streamCodec(), Pair::getLeft, + this.mapper2.streamCodec(), Pair::getRight, + Pair::of + ); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/special/RecordValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/special/RecordValueMapper.java index 65329de2..27540035 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/special/RecordValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/special/RecordValueMapper.java @@ -4,8 +4,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.LibX; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; @@ -16,6 +17,7 @@ import org.moddingx.libx.impl.config.wrapper.TypesafeMapper; import org.moddingx.libx.util.ClassUtil; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.lang.reflect.*; import java.util.List; @@ -26,16 +28,16 @@ public class RecordValueMapper implements ValueMapper { - private final Class clazz; + private final Class cls; private final List entries; private final Constructor ctor; - public RecordValueMapper(String modid, Class clazz, Function> mapperFunc) { - this.clazz = clazz; - if (!clazz.isRecord()) { + public RecordValueMapper(String modid, Class cls, Function> mapperFunc) { + this.cls = cls; + if (!cls.isRecord()) { throw new IllegalArgumentException("Can't create record config value mapper for non-record class."); } - RecordComponent[] parts = this.clazz.getRecordComponents(); + RecordComponent[] parts = this.cls.getRecordComponents(); Class[] types = new Class[parts.length]; ImmutableList.Builder entries = ImmutableList.builder(); for (int i = 0; i < parts.length; i++) { @@ -51,16 +53,16 @@ public RecordValueMapper(String modid, Class clazz, Function type() { - return this.clazz; + return this.cls; } @Override @@ -70,7 +72,7 @@ public Class element() { @Override public T fromJson(JsonObject json) { - RecordComponent[] parts = this.clazz.getRecordComponents(); + RecordComponent[] parts = this.cls.getRecordComponents(); Object[] values = new Object[parts.length]; for (int i = 0; i < parts.length; i++) { values[i] = this.entries.get(i).mapper().fromJson(json.get(parts[i].getName())); @@ -85,7 +87,7 @@ public T fromJson(JsonObject json) { @Override public JsonObject toJson(T value) { JsonObject json = new JsonObject(); - RecordComponent[] parts = this.clazz.getRecordComponents(); + RecordComponent[] parts = this.cls.getRecordComponents(); for (int i = 0; i < parts.length; i++) { try { json.add(parts[i].getName(), this.entries.get(i).mapper().toJson(accessComponent(parts[i], value))); @@ -97,7 +99,7 @@ public JsonObject toJson(T value) { } public T validate(T value, String action, List path, @Nullable AtomicBoolean needsCorrection) { - RecordComponent[] parts = this.clazz.getRecordComponents(); + RecordComponent[] parts = this.cls.getRecordComponents(); Object[] values = new Object[parts.length]; for (int i = 0; i < parts.length; i++) { try { @@ -135,34 +137,13 @@ public T validate(T value, String action, List path, @Nullable AtomicBoo } @Override - public T fromNetwork(FriendlyByteBuf buffer) { - RecordComponent[] parts = this.clazz.getRecordComponents(); - Object[] values = new Object[parts.length]; - for (int i = 0; i < parts.length; i++) { - values[i] = this.entries.get(i).mapper().fromNetwork(buffer); - } - try { - return this.ctor.newInstance(values); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Failed to create record for config.", e); - } - } - - @Override - public void toNetwork(T value, FriendlyByteBuf buffer) { - RecordComponent[] parts = this.clazz.getRecordComponents(); - for (int i = 0; i < parts.length; i++) { - try { - this.entries.get(i).mapper().toNetwork(accessComponent(parts[i], value), buffer); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Failed to get record value for config.", e); - } - } + public StreamCodec streamCodec() { + return new RecordStreamCodec(this.entries.stream().>map(entry -> entry.mapper.streamCodec()).toList()); } @Override public Optional correct(JsonElement json, ConfigCorrection correction) { - RecordComponent[] parts = this.clazz.getRecordComponents(); + RecordComponent[] parts = this.cls.getRecordComponents(); if (json.isJsonObject()) { // We have a json object. Just correct every key from it. Object[] args = new Object[parts.length]; @@ -211,7 +192,7 @@ public Optional correct(JsonElement json, ConfigCorrection correction) { @Override @OnlyIn(Dist.CLIENT) public ConfigEditor createEditor(ValidatorInfo validator) { - return new RecordEditor<>(this.clazz, this.entries, this.ctor); + return new RecordEditor<>(this.cls, this.entries, this.ctor); } public static Object accessComponent(RecordComponent component, Object instance) throws InvocationTargetException, IllegalAccessException { @@ -221,4 +202,48 @@ public static Object accessComponent(RecordComponent component, Object instance) } public record EntryData(TypesafeMapper mapper, @Nullable ConfiguredValidator validator) {} + + private class RecordStreamCodec implements StreamCodec { + + private final List> streamCodecs; + + public RecordStreamCodec(List> streamCodecs) { + this.streamCodecs = List.copyOf(streamCodecs); + if (RecordValueMapper.this.entries.size() != this.streamCodecs.size()) { + throw new IllegalArgumentException("Stream codec count does not match entry count in RecordValueMapper. This is a bug in LibX."); + } + } + + @Nonnull + @Override + public T decode(@Nonnull FriendlyByteBuf buffer) { + RecordComponent[] parts = RecordValueMapper.this.cls.getRecordComponents(); + Object[] values = new Object[parts.length]; + for (int i = 0; i < parts.length; i++) { + values[i] = this.streamCodecs.get(i).decode(buffer); + } + try { + return RecordValueMapper.this.ctor.newInstance(values); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Failed to create record for config.", e); + } + } + + @Override + public void encode(@Nonnull FriendlyByteBuf buffer, @Nonnull T value) { + RecordComponent[] parts = RecordValueMapper.this.cls.getRecordComponents(); + for (int i = 0; i < parts.length; i++) { + try { + this.streamCodecs.get(i).encode(buffer, accessComponent(parts[i], value)); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Failed to get record value for config.", e); + } + } + } + + @Override + public String toString() { + return "RecordStreamCodec[" + RecordValueMapper.this.cls.getName() + "]"; + } + } } diff --git a/src/main/java/org/moddingx/libx/impl/config/mappers/special/TripleValueMapper.java b/src/main/java/org/moddingx/libx/impl/config/mappers/special/TripleValueMapper.java index 878d2464..5db109b6 100644 --- a/src/main/java/org/moddingx/libx/impl/config/mappers/special/TripleValueMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/mappers/special/TripleValueMapper.java @@ -3,8 +3,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Triple; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; @@ -56,15 +57,13 @@ public JsonArray toJson(Triple value) { } @Override - public Triple fromNetwork(FriendlyByteBuf buffer) { - return Triple.of(this.mapper1.fromNetwork(buffer), this.mapper2.fromNetwork(buffer), this.mapper3.fromNetwork(buffer)); - } - - @Override - public void toNetwork(Triple value, FriendlyByteBuf buffer) { - this.mapper1.toNetwork(value.getLeft(), buffer); - this.mapper2.toNetwork(value.getMiddle(), buffer); - this.mapper3.toNetwork(value.getRight(), buffer); + public StreamCodec> streamCodec() { + return StreamCodec.composite( + this.mapper1.streamCodec(), Triple::getLeft, + this.mapper2.streamCodec(), Triple::getMiddle, + this.mapper3.streamCodec(), Triple::getRight, + Triple::of + ); } @Override @@ -92,6 +91,5 @@ public ConfigEditor> createEditor(ValidatorInfo validator) { this.mapper2.createEditor(ValidatorInfo.empty()), this.mapper3.createEditor(ValidatorInfo.empty()) ); - } } diff --git a/src/main/java/org/moddingx/libx/impl/config/wrapper/JsonTypesafeMapper.java b/src/main/java/org/moddingx/libx/impl/config/wrapper/JsonTypesafeMapper.java index cb962637..ea5c569f 100644 --- a/src/main/java/org/moddingx/libx/impl/config/wrapper/JsonTypesafeMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/wrapper/JsonTypesafeMapper.java @@ -2,8 +2,9 @@ import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.ValueMapper; @@ -46,13 +47,8 @@ public JsonElement toJson(C value) { } @Override - public C fromNetwork(FriendlyByteBuf buffer) { - return this.wrapped.fromNetwork(buffer); - } - - @Override - public void toNetwork(C value, FriendlyByteBuf buffer) { - this.wrapped.toNetwork(value, buffer); + public StreamCodec streamCodec() { + return this.wrapped.streamCodec(); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/config/wrapper/TypesafeMapper.java b/src/main/java/org/moddingx/libx/impl/config/wrapper/TypesafeMapper.java index d7d5592d..828b26dd 100644 --- a/src/main/java/org/moddingx/libx/impl/config/wrapper/TypesafeMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/wrapper/TypesafeMapper.java @@ -2,6 +2,7 @@ import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import org.moddingx.libx.config.mapper.ValueMapper; public class TypesafeMapper extends JsonTypesafeMapper { @@ -29,11 +30,17 @@ public JsonElement toJson(Object value) { } @Override - public void toNetwork(Object value, FriendlyByteBuf buffer) { - if (this.wrapped.type().isAssignableFrom(value.getClass())) { - this.wrapped.toNetwork(value, buffer); - } else { - throw new IllegalArgumentException("Type mismatch in config mapper write: Expected " + this.wrapped.type() + ", got " + value.getClass()); - } + public StreamCodec streamCodec() { + StreamCodec codec = this.wrapped.streamCodec(); + return StreamCodec.of( + (FriendlyByteBuf buf, Object value) -> { + if (this.wrapped.type().isAssignableFrom(value.getClass())) { + codec.encode(buf, value); + } else { + throw new IllegalArgumentException("Type mismatch in config mapper write: Expected " + this.wrapped.type() + ", got " + value.getClass()); + } + }, + codec::decode + ); } } diff --git a/src/main/java/org/moddingx/libx/impl/config/wrapper/WrappedGenericMapper.java b/src/main/java/org/moddingx/libx/impl/config/wrapper/WrappedGenericMapper.java index 4fa6493d..5f6852d2 100644 --- a/src/main/java/org/moddingx/libx/impl/config/wrapper/WrappedGenericMapper.java +++ b/src/main/java/org/moddingx/libx/impl/config/wrapper/WrappedGenericMapper.java @@ -2,8 +2,9 @@ import com.google.gson.JsonElement; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.config.correct.ConfigCorrection; import org.moddingx.libx.config.gui.ConfigEditor; import org.moddingx.libx.config.mapper.GenericValueMapper; @@ -44,13 +45,8 @@ public E toJson(T value) { } @Override - public T fromNetwork(FriendlyByteBuf buffer) { - return this.parent.fromNetwork(buffer, this.mapper); - } - - @Override - public void toNetwork(T value, FriendlyByteBuf buffer) { - this.parent.toNetwork(value, buffer, this.mapper); + public StreamCodec streamCodec() { + return this.parent.streamCodec(this.mapper); } @Override diff --git a/src/main/java/org/moddingx/libx/impl/crafting/recipe/EmptyRecipe.java b/src/main/java/org/moddingx/libx/impl/crafting/recipe/EmptyRecipe.java index 92a24a06..198ddfd8 100644 --- a/src/main/java/org/moddingx/libx/impl/crafting/recipe/EmptyRecipe.java +++ b/src/main/java/org/moddingx/libx/impl/crafting/recipe/EmptyRecipe.java @@ -1,43 +1,35 @@ package org.moddingx.libx.impl.crafting.recipe; -import com.google.gson.JsonObject; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; -import net.minecraft.core.RegistryAccess; -import net.minecraft.data.recipes.FinishedRecipe; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeSerializer; -import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.*; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import org.moddingx.libx.LibX; +import org.moddingx.libx.codec.MoreStreamCodecs; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -public class EmptyRecipe implements Recipe { +public class EmptyRecipe implements Recipe { public static final ResourceLocation ID = LibX.getInstance().resource("empty"); public static final RecipeType TYPE = RecipeType.simple(ID); - - private final ResourceLocation id; - public EmptyRecipe(ResourceLocation id) { - this.id = id; - } + private EmptyRecipe() {} @Override - public boolean matches(@Nonnull Container inv, @Nonnull Level level) { + public boolean matches(@Nonnull RecipeInput inv, @Nonnull Level level) { return false; } @Nonnull @Override - public ItemStack assemble(@Nonnull Container inv, @Nonnull RegistryAccess registryAccess) { + public ItemStack assemble(@Nonnull RecipeInput input, @Nonnull HolderLookup.Provider registries) { return ItemStack.EMPTY; } @@ -48,14 +40,14 @@ public boolean canCraftInDimensions(int width, int height) { @Nonnull @Override - public ItemStack getResultItem(@Nonnull RegistryAccess registryAccess) { + public ItemStack getResultItem(@Nonnull HolderLookup.Provider registries) { return ItemStack.EMPTY; } @Nonnull @Override - public ResourceLocation getId() { - return this.id; + public RecipeType getType() { + return TYPE; } @Nonnull @@ -66,14 +58,9 @@ public RecipeSerializer getSerializer() { @Nonnull @Override - public RecipeType getType() { - return TYPE; - } - - @Nonnull - @Override - public NonNullList getRemainingItems(@Nonnull Container inv) { - return NonNullList.withSize(inv.getContainerSize(), ItemStack.EMPTY); + public NonNullList getRemainingItems(@Nonnull RecipeInput input) { + return NonNullList.withSize(input.size(), ItemStack.EMPTY); + } @Nonnull @@ -93,6 +80,10 @@ public ItemStack getToastSymbol() { return new ItemStack(Blocks.BARRIER); } + public static EmptyRecipe empty() { + return new EmptyRecipe(); + } + public static class Serializer implements RecipeSerializer { public static final Serializer INSTANCE = new Serializer(); @@ -100,57 +91,17 @@ public static class Serializer implements RecipeSerializer { private Serializer() { } - - @Nonnull - @Override - public EmptyRecipe fromJson(@Nonnull ResourceLocation recipeId, @Nonnull JsonObject json) { - return new EmptyRecipe(recipeId); - } - @Nullable + @Nonnull @Override - public EmptyRecipe fromNetwork(@Nonnull ResourceLocation recipeId, @Nonnull FriendlyByteBuf buffer) { - return new EmptyRecipe(recipeId); + public MapCodec codec() { + return MapCodec.unit(EmptyRecipe::new); } + @Nonnull @Override - public void toNetwork(@Nonnull FriendlyByteBuf buffer, @Nonnull EmptyRecipe recipe) { - // + public StreamCodec streamCodec() { + return MoreStreamCodecs.unit(EmptyRecipe::new); } } - - public static FinishedRecipe empty(ResourceLocation id) { - - return new FinishedRecipe() { - - @Override - public void serializeRecipeData(@Nonnull JsonObject json) { - // - } - - @Nonnull - @Override - public ResourceLocation getId() { - return id; - } - - @Nonnull - @Override - public RecipeSerializer getType() { - return Serializer.INSTANCE; - } - - @Nullable - @Override - public JsonObject serializeAdvancement() { - return null; - } - - @Nullable - @Override - public ResourceLocation getAdvancementId() { - return null; - } - }; - } } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenFontLoader.java b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenFontLoader.java index d8dbb27f..8cc3aa85 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenFontLoader.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenFontLoader.java @@ -9,15 +9,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.moddingx.libx.LibX; import org.moddingx.libx.impl.reflect.ReflectionHacks; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -42,17 +39,18 @@ public static StringSplitter getFontMetrics(@Nullable ExistingFileHelper fileHel FontManager.Preparation preparation = mgr.prepare(rm, Runnable::run).get(0, TimeUnit.NANOSECONDS); // Reverse all glyph provider lists as vanilla sorts higher priorities to the end of the list. - Map> providerMap = preparation.providers().entrySet().stream().map(entry -> { + Map> providerMap = preparation.fontSets().entrySet().stream().map(entry -> { ResourceLocation fontId = entry.getKey(); - List list = new ArrayList<>(entry.getValue()); + List list = new ArrayList<>(entry.getValue()); Collections.reverse(list); return Map.entry(fontId, Collections.unmodifiableList(list)); }).collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); - List defaultGlyphProviders = providerMap.getOrDefault(Style.DEFAULT_FONT, List.of()); + List defaultGlyphProviders = providerMap.getOrDefault(Style.DEFAULT_FONT, List.of()); fontMetrics = new StringSplitter((cp, style) -> { if (ZERO_WIDTH_FONT.equals(style.getFont())) return 0; - for (GlyphProvider provider : providerMap.getOrDefault(style.getFont(), defaultGlyphProviders)) { - GlyphInfo glyph = provider.getGlyph(cp); + for (GlyphProvider.Conditional conditional : providerMap.getOrDefault(style.getFont(), defaultGlyphProviders)) { + if (!conditional.filter().apply(Set.of())) continue; + GlyphInfo glyph = conditional.provider().getGlyph(cp); if (glyph != null) return glyph.getAdvance(style.isBold()); } return SpecialGlyphs.MISSING.getAdvance(style.isBold()); diff --git a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenLoader.java b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenLoader.java index 9672e78d..8a80b3a0 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenLoader.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenLoader.java @@ -2,7 +2,7 @@ import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import java.lang.reflect.Field; diff --git a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenRegistryLoader.java b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenRegistryLoader.java index 98331199..8ae04d8b 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenRegistryLoader.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/load/DatagenRegistryLoader.java @@ -6,8 +6,8 @@ import net.minecraft.server.RegistryLayer; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.registries.DataPackRegistriesHooks; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.registries.DataPackRegistriesHooks; import org.moddingx.libx.LibX; import org.moddingx.libx.impl.libxcore.CoreRegistryLoad; @@ -19,14 +19,14 @@ public class DatagenRegistryLoader { // Hacky code to load a registry access during datagen from a resource manager // See WorldLoader#load - public static RegistryAccess.Frozen loadRegistries(ExistingFileHelper fileHelper) { + public static RegistryAccess.Frozen loadRegistries(ExistingFileHelper fileHelper, RegistrySelector selector) { LibX.logger.info("Start loading registries for datagen"); ResourceManager mgr = DatagenLoader.resources(fileHelper, PackType.SERVER_DATA); LayeredRegistryAccess access = RegistryLayer.createRegistryAccess(); - access = loadLayer(mgr, access, RegistryLayer.WORLDGEN, getDataPackRegistries(RegistryLayer.WORLDGEN)); + access = loadLayer(mgr, access, RegistryLayer.WORLDGEN, getDataPackRegistries(RegistryLayer.WORLDGEN, selector)); // Invoke our coremod patch here CoreRegistryLoad.afterWorldGenLayerLoad(access); - access = loadLayer(mgr, access, RegistryLayer.DIMENSIONS, getDataPackRegistries(RegistryLayer.DIMENSIONS)); + access = loadLayer(mgr, access, RegistryLayer.DIMENSIONS, getDataPackRegistries(RegistryLayer.DIMENSIONS, selector)); LibX.logger.info("Finished loading registries for datagen"); return access.compositeAccess(); } @@ -36,17 +36,29 @@ private static LayeredRegistryAccess loadLayer(ResourceManager mg } @SuppressWarnings("UnstableApiUsage") - public static List> getDataPackRegistries(@Nullable RegistryLayer layer) { + public static List> getDataPackRegistries(@Nullable RegistryLayer layer, @Nullable RegistrySelector selector) { if (layer == null) { return Stream.concat( - Stream.concat(getDataPackRegistries(RegistryLayer.STATIC).stream(), getDataPackRegistries(RegistryLayer.WORLDGEN).stream()), - Stream.concat(getDataPackRegistries(RegistryLayer.DIMENSIONS).stream(), getDataPackRegistries(RegistryLayer.RELOADABLE).stream()) + Stream.concat( + getDataPackRegistries(RegistryLayer.STATIC, selector).stream(), + getDataPackRegistries(RegistryLayer.WORLDGEN, selector).stream() + ), + Stream.concat( + getDataPackRegistries(RegistryLayer.DIMENSIONS, selector).stream(), + getDataPackRegistries(RegistryLayer.RELOADABLE, selector).stream() + ) ).toList(); } - return switch (layer) { + List> defaultRegistries = switch (layer) { case STATIC, RELOADABLE -> List.of(); - case WORLDGEN -> DataPackRegistriesHooks.getDataPackRegistries(); - case DIMENSIONS -> RegistryDataLoader.DIMENSION_REGISTRIES; + case WORLDGEN -> List.copyOf(DataPackRegistriesHooks.getDataPackRegistries()); + case DIMENSIONS -> List.copyOf(RegistryDataLoader.DIMENSION_REGISTRIES); }; + return selector == null ? defaultRegistries : List.copyOf(selector.selectRegistries(layer, defaultRegistries)); + } + + @FunctionalInterface + public interface RegistrySelector { + List> selectRegistries(RegistryLayer layer, List> registries); } } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/loot/LootData.java b/src/main/java/org/moddingx/libx/impl/datagen/loot/LootData.java index ee220277..d8b9dc62 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/loot/LootData.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/loot/LootData.java @@ -1,13 +1,15 @@ package org.moddingx.libx.impl.datagen.loot; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.entries.EmptyLootItem; import net.minecraft.world.level.storage.loot.entries.LootItem; import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer; +import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction; +import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction; import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; import net.minecraft.world.level.storage.loot.functions.SetItemDamageFunction; -import net.minecraft.world.level.storage.loot.functions.SetNbtFunction; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import java.util.List; @@ -24,9 +26,9 @@ public static LootPoolSingletonContainer.Builder stack(ItemStack stack) { float damage = (stack.getMaxDamage() - stack.getDamageValue()) / (float) stack.getMaxDamage(); entry.apply(SetItemDamageFunction.setDamage(ConstantValue.exactly(damage))); } - if (stack.hasTag()) { - //noinspection deprecation - entry.apply(SetNbtFunction.setTag(stack.getOrCreateTag())); + DataComponentPatch components = stack.getComponentsPatch(); + if (!components.isEmpty()) { + entry.apply(LootItemConditionalFunction.simpleBuilder(conditions -> new SetComponentsFunction(conditions, components))); } return entry; } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/model/TypedBlockModelProvider.java b/src/main/java/org/moddingx/libx/impl/datagen/model/TypedBlockModelProvider.java index 3999f0e5..df86d957 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/model/TypedBlockModelProvider.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/model/TypedBlockModelProvider.java @@ -3,10 +3,11 @@ import net.minecraft.data.CachedOutput; import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.generators.BlockModelBuilder; -import net.minecraftforge.client.model.generators.BlockModelProvider; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.client.model.generators.BlockModelBuilder; +import net.neoforged.neoforge.client.model.generators.BlockModelProvider; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import javax.annotation.Nonnull; import java.util.concurrent.CompletableFuture; public class TypedBlockModelProvider extends BlockModelProvider { @@ -18,18 +19,21 @@ public TypedBlockModelProvider(PackOutput packOutput, String modid, ExistingFile this.renderTypes = renderTypes; } + @Nonnull @Override - public BlockModelBuilder getBuilder(String path) { + public BlockModelBuilder getBuilder(@Nonnull String path) { return super.getBuilder(path).renderType(this.renderTypes); } + @Nonnull @Override // Method is protected in superclass - public CompletableFuture generateAll(CachedOutput cache) { + public CompletableFuture generateAll(@Nonnull CachedOutput cache) { return super.generateAll(cache); } + @Nonnull @Override - public CompletableFuture run(CachedOutput cache) { + public CompletableFuture run(@Nonnull CachedOutput cache) { return CompletableFuture.completedFuture(null); } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/patchouli/content/EntityContent.java b/src/main/java/org/moddingx/libx/impl/datagen/patchouli/content/EntityContent.java index a22fa797..4357aee5 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/patchouli/content/EntityContent.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/patchouli/content/EntityContent.java @@ -1,8 +1,8 @@ package org.moddingx.libx.impl.datagen.patchouli.content; import com.google.gson.JsonObject; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.EntityType; -import net.minecraftforge.registries.ForgeRegistries; import org.moddingx.libx.datagen.provider.patchouli.content.CaptionContent; import org.moddingx.libx.datagen.provider.patchouli.page.PageBuilder; @@ -36,7 +36,7 @@ protected CaptionContent withCaption(String caption) { protected void specialPage(PageBuilder builder, @Nullable String caption) { JsonObject json = new JsonObject(); json.addProperty("type", "patchouli:entity"); - json.addProperty("entity", Objects.requireNonNull(ForgeRegistries.ENTITY_TYPES.getKey(this.entity), "Entity not registered: " + this.entity).toString()); + json.addProperty("entity", Objects.requireNonNull(BuiltInRegistries.ENTITY_TYPE.getKey(this.entity), "Entity not registered: " + this.entity).toString()); if (caption != null) { json.addProperty("text", builder.translate(caption)); } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/recipe/DecorationRecipes.java b/src/main/java/org/moddingx/libx/impl/datagen/recipe/DecorationRecipes.java index 307f4b3b..173d0ca5 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/recipe/DecorationRecipes.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/recipe/DecorationRecipes.java @@ -1,13 +1,13 @@ package org.moddingx.libx.impl.datagen.recipe; -import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.Criterion; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.SingleItemRecipeBuilder; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; -import net.minecraftforge.common.Tags; +import net.neoforged.neoforge.common.Tags; import org.moddingx.libx.base.decoration.DecoratedBlock; import org.moddingx.libx.base.decoration.DecorationType; import org.moddingx.libx.datagen.provider.recipe.RecipeExtension; @@ -65,10 +65,10 @@ public static void defaultRecipes(Block block, RecipeExtension ext) { private static void stoneCutting(RecipeExtension ext, Ingredient input, ItemLike output, int amount) { SingleItemRecipeBuilder builder = SingleItemRecipeBuilder.stonecutting(input, RecipeCategory.BUILDING_BLOCKS, output, amount); - List criteria = ext.criteria(input); + List> criteria = ext.criteria(input); for (int i = 0; i < criteria.size(); i++) { builder.unlockedBy("has_item" + i, criteria.get(i)); } - builder.save(ext.consumer(), ext.provider().loc(output, "stonecutting")); + builder.save(ext.output(), ext.provider().loc(output, "stonecutting")); } } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/recipe/ObjectCraftingBuilder.java b/src/main/java/org/moddingx/libx/impl/datagen/recipe/ObjectCraftingBuilder.java index 45ab6558..7c9e2602 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/recipe/ObjectCraftingBuilder.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/recipe/ObjectCraftingBuilder.java @@ -1,6 +1,6 @@ package org.moddingx.libx.impl.datagen.recipe; -import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.Criterion; import net.minecraft.core.registries.Registries; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; @@ -11,7 +11,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.crafting.CompoundIngredient; +import net.neoforged.neoforge.common.crafting.CompoundIngredient; import org.apache.commons.lang3.tuple.Pair; import org.moddingx.libx.datagen.provider.recipe.RecipeExtension; @@ -36,7 +36,7 @@ public static void buildShaped(RecipeExtension ext, Object[] objects) { builder.pattern(line); } addShapedIngredients(ext, builder, reader); - builder.save(ext.consumer(), id); + builder.save(ext.output(), id); } public static void buildShapeless(RecipeExtension ext, Object[] objects) { @@ -47,7 +47,7 @@ public static void buildShapeless(RecipeExtension ext, Object[] objects) { if (id == null) id = ext.provider().loc(output.getLeft()); ShapelessRecipeBuilder builder = ShapelessRecipeBuilder.shapeless(recipeCategory, output.getLeft(), output.getRight()); addShapelessIngredients(ext, builder, reader); - builder.save(ext.consumer(), id); + builder.save(ext.output(), id); } @Nullable @@ -84,8 +84,8 @@ private static void addShapelessIngredients(RecipeExtension ext, ShapelessRecipe } } - private static int addCriteriaToBuilder(BiConsumer triggers, List criteria, int nextId) { - for (CriterionTriggerInstance criterion : criteria) { + private static int addCriteriaToBuilder(BiConsumer> triggers, List> criteria, int nextId) { + for (Criterion criterion : criteria) { triggers.accept("criterion" + (nextId++), criterion); } return nextId; diff --git a/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistry.java b/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistry.java index 5ce0ccd3..448e300b 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistry.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistry.java @@ -59,7 +59,7 @@ private DatagenRegistry(ResourceKey> registryKey, DatagenR } } for (Map.Entry, T> entry : parentElements.entrySet()) { - this.register(entry.getKey(), entry.getValue(), Lifecycle.stable()); + this.register(entry.getKey(), entry.getValue(), RegistrationInfo.BUILT_IN); } } @@ -77,13 +77,13 @@ public HolderLookup.RegistryLookup asLookup() { @Nonnull @Override - public Holder.Reference registerMapping(int id, @Nonnull ResourceKey key, @Nonnull T value, @Nonnull Lifecycle lifecycle) { + public Holder.Reference register(int id, @Nonnull ResourceKey key, @Nonnull T value, @Nonnull RegistrationInfo info) { if (this.unregisteredIntrusiveHolders != null && !this.unregisteredIntrusiveHolders.containsKey(value)) { // We allow intrusive holders, however this implies, every value must have an intrusive holder // which is not the case. Create one on the fly. this.createIntrusiveHolder(value); } - Holder.Reference holder = super.registerMapping(id, key, value, Lifecycle.stable()); + Holder.Reference holder = super.register(id, key, value, RegistrationInfo.BUILT_IN); if (this.propagateNewElementsToChildren) { // Register to all children (can't keep ids consistent) Set> activeChildren = this.registrySet.collectActiveChildRegistries(this.key()); @@ -93,7 +93,7 @@ public Holder.Reference registerMapping(int id, @Nonnull ResourceKey key, } } for (DatagenRegistry child : activeChildren) { - child.registerOnlyThisRegistry(key, value, lifecycle); + child.registerOnlyThisRegistry(key, value, info); } } this.registrySet.trackHolderTarget(holder, this.key()); @@ -110,10 +110,10 @@ public Holder.Reference createIntrusiveHolder(@Nonnull T value) { } @SuppressWarnings("UnusedReturnValue") - private Holder.Reference registerOnlyThisRegistry(ResourceKey key, T value, Lifecycle lifecycle) { + private Holder.Reference registerOnlyThisRegistry(ResourceKey key, T value, RegistrationInfo info) { try { this.propagateNewElementsToChildren = false; - return this.register(key, value, lifecycle); + return this.register(key, value, info); } finally { this.propagateNewElementsToChildren = true; } @@ -150,7 +150,7 @@ public void writeOwnElements(PackTarget target, CachedOutput output) { for (Map.Entry, T> entry : this.entrySet()) { if (parents.stream().noneMatch(reg -> reg.containsKey(entry.getKey()))) { try { - JsonElement json = this.codec.encodeStart(ops, entry.getValue()).getOrThrow(false, msg -> {}); + JsonElement json = this.codec.encodeStart(ops, entry.getValue()).getOrThrow(RuntimeException::new); DataProvider.saveStable(output, json, outputPath.get().resolve(DatapackHelper.registryPath(entry.getKey()))); } catch (Exception e) { throw new RuntimeException("Failed to serialise element " + entry.getKey() + " in datagen registry", e); diff --git a/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistrySet.java b/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistrySet.java index aae7d861..3647d77e 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistrySet.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/registries/DatagenRegistrySet.java @@ -1,9 +1,8 @@ package org.moddingx.libx.impl.datagen.registries; -import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; import net.minecraft.core.*; -import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.data.CachedOutput; import net.minecraft.resources.RegistryDataLoader; import net.minecraft.resources.ResourceKey; @@ -11,25 +10,31 @@ import org.moddingx.libx.datagen.DatagenSystem; import org.moddingx.libx.datagen.PackTarget; import org.moddingx.libx.datagen.RegistrySet; -import org.moddingx.libx.impl.datagen.load.DatagenRegistryLoader; +import org.moddingx.libx.util.Ref; import javax.annotation.Nullable; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; public class DatagenRegistrySet implements RegistrySet { private final RegistryAccess rootAccess; + private final KnownRegistries knownRegistries; private final DatagenRegistrySet root; private final List parents; private final List children; - private final Map, ResourceKey>> holderMap; + // NeoForge patches the holder equals and hashCode to access the key which is impossible for intrusive holders + // Therefore we need to use Ref here. + private final Map>, ResourceKey>> holderMap; private DatagenStage stage; private final Map>, DatagenRegistry> registries; private RegistryAccess localAccess; - public DatagenRegistrySet(RegistryAccess access) { + public DatagenRegistrySet(RegistryAccess access, KnownRegistries knownRegistries) { this.rootAccess = access; + this.knownRegistries = knownRegistries; this.root = this; this.parents = List.of(); this.children = new ArrayList<>(); @@ -47,6 +52,7 @@ public DatagenRegistrySet(List parents) { if (roots.size() != 1) throw new IllegalArgumentException("Registry set can only have a single root"); this.root = roots.get(0); this.rootAccess = this.root.rootAccess; + this.knownRegistries = this.root.knownRegistries; for (DatagenRegistrySet parent : this.parents) { if (parent.stage != DatagenStage.REGISTRY_SETUP) { throw new IllegalStateException("New registry sets ca only be created in registry setup phase"); @@ -95,14 +101,14 @@ public RegistryAccess registryAccess() { @Nullable @Override public ResourceKey> findRegistryFor(Holder.Reference holder) { + Ref> key = new Ref<>(holder); //noinspection unchecked - return (ResourceKey>) this.holderMap.getOrDefault(holder, null); + return (ResourceKey>) this.holderMap.getOrDefault(key, null); } public Optional> getDatagenRegistry(ResourceKey> registryKey, boolean forWrite) { if (forWrite && this.stage == DatagenStage.DATAGEN) return Optional.empty(); - Optional> data = DatagenRegistryLoader.getDataPackRegistries(null).stream() - .filter(rd -> Objects.equals(rd.key(), registryKey)).findFirst(); + Optional> data = this.knownRegistries.query(registryKey); if (data.isEmpty()) return Optional.empty(); if (forWrite && DatagenSystem.extensionRegistries().contains(registryKey) != (this.stage == DatagenStage.EXTENSION_SETUP)) { return Optional.empty(); @@ -111,9 +117,8 @@ public Optional> getDatagenRegistry(ResourceKey) this.registries.computeIfAbsent(registryKey, k -> { - //noinspection unchecked DatagenRegistry reg = DatagenRegistry.createRoot( - registryKey, this, (Codec) data.get().elementCodec(), + registryKey, this, data.get().elementCodec(), this.rootAccess.registry(registryKey).orElseThrow(() -> new IllegalStateException("Could not setup " + registryKey + " registry: Root registry not available") ) @@ -125,9 +130,8 @@ public Optional> getDatagenRegistry(ResourceKey) this.registries.computeIfAbsent(registryKey, k -> { - //noinspection unchecked DatagenRegistry reg = DatagenRegistry.create( - registryKey, this, (Codec) data.get().elementCodec(), + registryKey, this, data.get().elementCodec(), this.getDirectParents().stream().map(parent -> parent.getDatagenRegistry(registryKey, false).orElseThrow(() -> new IllegalStateException("Could not setup " + registryKey + " registry: Parent registry not available") @@ -159,7 +163,7 @@ private void addActiveChildRegistries(ResourceKey> re } public void trackHolderTarget(Holder.Reference holder, ResourceKey> registryKey) { - this.holderMap.put(holder, registryKey); + this.holderMap.put(new Ref<>(holder), registryKey); } public void transition(DatagenStage stage) { @@ -232,9 +236,9 @@ private boolean shouldBeFrozen(DatagenStage stage, ResourceKey> makeRegistryOfRegistries() { - WritableRegistry> rootRegistry = new MappedRegistry<>(ResourceKey.createRegistryKey(BuiltInRegistries.ROOT_REGISTRY_NAME), Lifecycle.stable()); + WritableRegistry> rootRegistry = new MappedRegistry<>(ResourceKey.createRegistryKey(Registries.ROOT_REGISTRY_NAME), Lifecycle.stable()); for (ResourceKey> key : this.rootAccess.registries().map(RegistryAccess.RegistryEntry::key).toList()) { - ((WritableRegistry) rootRegistry).register(key, this.registry((ResourceKey) key), Lifecycle.stable()); + ((WritableRegistry) rootRegistry).register(key, this.registry((ResourceKey) key), RegistrationInfo.BUILT_IN); } return rootRegistry; } @@ -250,4 +254,24 @@ public void writeElements(PackTarget target, CachedOutput output) { registry.writeOwnElements(target, output); } } + + public static class KnownRegistries { + + private final List> knownRegistries; + private final Map>, RegistryDataLoader.RegistryData> knownRegistriesMap; + + public KnownRegistries(List> knownRegistries) { + this.knownRegistries = List.copyOf(knownRegistries); + this.knownRegistriesMap = this.knownRegistries.stream().collect(Collectors.toUnmodifiableMap(RegistryDataLoader.RegistryData::key, Function.identity())); + } + + public List> list() { + return this.knownRegistries; + } + + public Optional> query(ResourceKey> registryKey) { + //noinspection unchecked + return Optional.ofNullable((RegistryDataLoader.RegistryData) this.knownRegistriesMap.get(registryKey)); + } + } } diff --git a/src/main/java/org/moddingx/libx/impl/datagen/resource/ResourceLocator.java b/src/main/java/org/moddingx/libx/impl/datagen/resource/ResourceLocator.java index 74691fc0..8c4b4905 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/resource/ResourceLocator.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/resource/ResourceLocator.java @@ -2,7 +2,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; -import net.minecraftforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.common.data.ExistingFileHelper; import org.moddingx.libx.datagen.PackTarget; import org.moddingx.libx.util.lazy.LazyValue; @@ -44,7 +44,7 @@ public PackTarget.Resource getResource(ExistingFileHelper fileHelper, ResourceLo } } if (this.prefix != null) { - ResourceLocation resolved = new ResourceLocation(res.getNamespace(), this.prefix + "/" + res.getPath()); + ResourceLocation resolved = ResourceLocation.fromNamespaceAndPath(res.getNamespace(), this.prefix + "/" + res.getPath()); for (ResourceLocator parent : this.parents) { PackTarget.Resource resource = parent.getResource(fileHelper, resolved); if (resource != null) return resource; diff --git a/src/main/java/org/moddingx/libx/impl/datagen/tags/DecorationTags.java b/src/main/java/org/moddingx/libx/impl/datagen/tags/DecorationTags.java index 71272462..3281552a 100644 --- a/src/main/java/org/moddingx/libx/impl/datagen/tags/DecorationTags.java +++ b/src/main/java/org/moddingx/libx/impl/datagen/tags/DecorationTags.java @@ -63,7 +63,7 @@ public static void addTags(Block block, CommonTagsProviderBase provider, Runnabl } else if (block instanceof DecoratedPressurePlate decorated) { initInternal.run(); provider.block(InternalTags.Blocks.PRESSURE_PLATES).add(decorated); - switch (decorated.sensitivity) { + switch (decorated.parent.getMaterialProperties().blockSetType().pressurePlateSensitivity()) { case EVERYTHING -> provider.block(InternalTags.Blocks.WOODEN_PRESSURE_PLATES).add(decorated); case MOBS -> provider.block(InternalTags.Blocks.STONE_PRESSURE_PLATES).add(decorated); default -> {} diff --git a/src/main/java/org/moddingx/libx/impl/datapack/DynamicPackLocator.java b/src/main/java/org/moddingx/libx/impl/datapack/DynamicPackLocator.java index f0cad05c..17274d50 100644 --- a/src/main/java/org/moddingx/libx/impl/datapack/DynamicPackLocator.java +++ b/src/main/java/org/moddingx/libx/impl/datapack/DynamicPackLocator.java @@ -1,14 +1,17 @@ package org.moddingx.libx.impl.datapack; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackLocationInfo; +import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.repository.RepositorySource; -import net.minecraftforge.event.AddPackFindersEvent; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.forgespi.language.IModFileInfo; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.ModList; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.neoforge.event.AddPackFindersEvent; +import net.neoforged.neoforgespi.language.IModFileInfo; +import net.neoforged.neoforgespi.language.IModInfo; import org.moddingx.libx.LibX; import org.moddingx.libx.util.lazy.LazyValue; @@ -49,20 +52,33 @@ public synchronized boolean isEnabled(ResourceLocation id) { @Override public void loadPacks(@Nonnull Consumer packs) { for (ResourceLocation id : this.enabledPacks) { - String packId = LibXPack.PACK_CONFIG.get(this.type).prefix() + "/" + id.getNamespace() + ":" + id.getPath(); - IModFileInfo fileInfo = ModList.get().getModFileById(id.getNamespace()); - if (fileInfo == null || fileInfo.getFile() == null) { - LibX.logger.warn("Can't create dynamic pack " + id + ": Invalid mod file: " + fileInfo); + IModInfo modInfo = ModList.get().getModContainerById(id.getNamespace()).map(ModContainer::getModInfo).orElse(null); + IModFileInfo modFileInfo = modInfo == null ? null : modInfo.getOwningFile(); + if (modInfo == null || modFileInfo == null || modFileInfo.getFile() == null) { + LibX.logger.error("Can't create dynamic pack " + id + ": Invalid mod file: " + id.getNamespace() + " (" + modFileInfo + ")"); } else { - LazyValue resources = new LazyValue<>(() -> new LibXPack(fileInfo.getFile(), this.type, id.getPath())); - Pack pack = Pack.readMetaAndCreate(packId, Component.literal(packId), false, - anotherId -> resources.get(), this.type, Pack.Position.BOTTOM, - LibXPack.PACK_CONFIG.get(this.type).source() - ); + PackLocationInfo location = LibXPack.generateLocationInfo(modInfo, this.type, id.getPath()); + LazyValue resources = new LazyValue<>(() -> new LibXPack(location, this.type, modInfo, modFileInfo.getFile(), id.getPath())); + Pack pack = Pack.readMetaAndCreate(location, new SimpleResourceSupplier(resources), this.type, LibXPack.PACK_CONFIG.get(this.type).selection()); if (pack != null) { packs.accept(pack); } } } } + + private record SimpleResourceSupplier(LazyValue resources) implements Pack.ResourcesSupplier { + + @Nonnull + @Override + public PackResources openPrimary(@Nonnull PackLocationInfo location) { + return this.resources().get(); + } + + @Nonnull + @Override + public PackResources openFull(@Nonnull PackLocationInfo location, @Nonnull Pack.Metadata metadata) { + return this.resources().get(); + } + } } diff --git a/src/main/java/org/moddingx/libx/impl/datapack/LibXPack.java b/src/main/java/org/moddingx/libx/impl/datapack/LibXPack.java index 2d37a4f5..84676237 100644 --- a/src/main/java/org/moddingx/libx/impl/datapack/LibXPack.java +++ b/src/main/java/org/moddingx/libx/impl/datapack/LibXPack.java @@ -1,13 +1,19 @@ package org.moddingx.libx.impl.datapack; import net.minecraft.SharedConstants; +import net.minecraft.network.chat.Component; +import net.minecraft.server.packs.PackLocationInfo; +import net.minecraft.server.packs.PackSelectionConfig; import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.PathPackResources; +import net.minecraft.server.packs.repository.KnownPack; +import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.repository.PackSource; import net.minecraft.server.packs.resources.IoSupplier; -import net.minecraftforge.forgespi.locating.IModFile; -import net.minecraftforge.resource.PathPackResources; +import net.neoforged.neoforgespi.language.IModInfo; +import net.neoforged.neoforgespi.locating.IModFile; +import org.moddingx.libx.LibX; import org.moddingx.libx.datapack.DatapackHelper; -import org.moddingx.libx.util.lazy.LazyValue; import javax.annotation.Nonnull; import java.io.InputStream; @@ -15,77 +21,53 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; +import java.util.Optional; public class LibXPack extends PathPackResources { @SuppressWarnings("deprecation") public static final Map PACK_CONFIG = Map.of( - PackType.CLIENT_RESOURCES, new PackTypeConfig(PackSource.FEATURE, "libxassets", SharedConstants.RESOURCE_PACK_FORMAT), - PackType.SERVER_DATA, new PackTypeConfig(PackSource.DEFAULT, "libxdata", SharedConstants.DATA_PACK_FORMAT) + PackType.CLIENT_RESOURCES, new PackTypeConfig(PackSource.FEATURE, new PackSelectionConfig(false, Pack.Position.BOTTOM, false), "libxassets", SharedConstants.RESOURCE_PACK_FORMAT), + PackType.SERVER_DATA, new PackTypeConfig(PackSource.DEFAULT, new PackSelectionConfig(true, Pack.Position.BOTTOM, true), "libxdata", SharedConstants.DATA_PACK_FORMAT) ); - private final String packId; private final PackType type; - private final LazyValue> packMcmeta; + private final IoSupplier packMcmeta; - public LibXPack(IModFile mod, PackType type, String packId) { + public LibXPack(PackLocationInfo location, PackType type, IModInfo mod, IModFile modFile, String packId) { // Get the base part of the mod in there and the override resolve - super(mod.getFileName() + "/" + packId, true, mod.findResource(PACK_CONFIG.get(type).prefix())); - this.packId = packId; + super(location, modFile.findResource(PACK_CONFIG.get(type).prefix()).resolve(packId)); this.type = type; - this.packMcmeta = new LazyValue<>(() -> { - String description = "Dynamic " + type.getDirectory() + ": " + mod.getFileName() + "/" + packId; - try { - Path descPath = this.getSource().resolve(this.packId).resolve("description.txt"); - if (Files.isRegularFile(descPath)) description = Files.readString(descPath, StandardCharsets.UTF_8).strip(); - } catch (Exception e) { - // - } - return DatapackHelper.generatePackMeta(mod, description, type); - }); + + String description = mod.getDisplayName() + " (" + packId + ")"; + try { + Path descPath = modFile.findResource(PACK_CONFIG.get(type).prefix()).resolve(packId).resolve("description.txt"); + if (Files.isRegularFile(descPath)) description = Files.readString(descPath, StandardCharsets.UTF_8).strip(); + } catch (Exception e) { + // + } + this.packMcmeta = DatapackHelper.generatePackMeta(description, type); + } + + public static PackLocationInfo generateLocationInfo(IModInfo mod, PackType type, String packId) { + PackTypeConfig config = PACK_CONFIG.get(type); + return new PackLocationInfo( + mod.getModId() + "/" + packId, + Component.literal(mod.getDisplayName() + " (" + packId + ")"), + PACK_CONFIG.get(type).source(), + Optional.of(new KnownPack(LibX.getInstance().modid, config.prefix() + "/" + mod.getModId() + "/" + packId, mod.getVersion().toString())) + ); } @Override public IoSupplier getRootResource(@Nonnull String... names) { - return names[0].equals(PACK_META) ? this.packMcmeta.get() : super.getRootResource(names); + return names[0].equals(PACK_META) ? this.packMcmeta : super.getRootResource(names); } @Override public boolean isHidden() { return this.type == PackType.SERVER_DATA; } - - @Nonnull - @Override - protected Path resolve(@Nonnull String... pathParts) { - String pathStr = switch (pathParts.length) { - case 0 -> ""; - case 1 -> pathParts[0]; - default -> { - StringBuilder sb = new StringBuilder(); - for (String pathPart : pathParts) sb.append("/").append(pathPart); - yield sb.toString(); - } - }; - while (pathStr.contains("//")) pathStr = pathStr.replace("//", "/"); - if (pathStr.startsWith("/")) pathStr = pathStr.substring(1); - if (pathStr.endsWith("/")) pathStr = pathStr.substring(0, pathStr.length() - 1); - String[] paths = pathStr.split("/"); - if (paths.length == 0) return this.getSource().resolve(this.packId); - Path path = switch (paths[0]) { - case PACK_META -> this.getSource(); - case "pack.png" -> this.getSource().resolve(this.packId).resolve("pack.png"); - default -> { - if (this.type.getDirectory().equals(paths[0])) { - yield this.getSource().resolve(this.packId); - } else { - yield this.getSource().resolve(this.packId).resolve("SNOWBALL"); - } - } - }; - for (int i = 1; i < paths.length; i++) path = path.resolve(paths[i]); - return path; - } - public record PackTypeConfig(PackSource source, String prefix, int version) {} + public record PackTypeConfig(PackSource source, PackSelectionConfig selection, String prefix, int version) {} } diff --git a/src/main/java/org/moddingx/libx/impl/inventory/AdvancedItemHandlerHelper.java b/src/main/java/org/moddingx/libx/impl/inventory/AdvancedItemHandlerHelper.java new file mode 100644 index 00000000..4caeba57 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/inventory/AdvancedItemHandlerHelper.java @@ -0,0 +1,55 @@ +package org.moddingx.libx.impl.inventory; + +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.items.IItemHandler; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiPredicate; + +public class AdvancedItemHandlerHelper { + + public static boolean hasSpaceFor(IItemHandler itemHandler, List stacks, int startInclusive, int endExclusive, BiPredicate itemValidForSlot) { + if (stacks.isEmpty()) { + return true; + } else if (stacks.size() == 1) { + ItemStack remainder = stacks.get(0).copy(); + for (int slot = startInclusive; slot < endExclusive; slot++) { + remainder = itemHandler.insertItem(slot, remainder, true); + if (remainder.isEmpty()) return true; + } + return remainder.isEmpty(); + } else { + Map copies = new HashMap<>(); + for (ItemStack stack : stacks) { + if (!stack.isEmpty()) { + int amountLeft = stack.getCount(); + for (int slot = startInclusive; slot < endExclusive; slot++) { + if (itemValidForSlot.test(slot, stack)) { + ItemStack content = copies.getOrDefault(slot, itemHandler.getStackInSlot(slot)); + if (content.isEmpty()) { + amountLeft = 0; + ItemStack modifiableStack = stack.copy(); + modifiableStack.setCount(amountLeft); + copies.put(slot, modifiableStack); + break; + } else if (ItemStack.isSameItemSameComponents(stack, content)) { + int reduce = Math.max(0, Math.min(content.getMaxStackSize() - content.getCount(), amountLeft)); + amountLeft -= reduce; + ItemStack modifiableStack = copies.getOrDefault(slot, itemHandler.getStackInSlot(slot).copy()); + modifiableStack.grow(reduce); + copies.put(slot, modifiableStack); + if (amountLeft <= 0) break; + } + } + } + if (amountLeft > 0) { + return false; + } + } + } + return true; + } + } +} diff --git a/src/main/java/org/moddingx/libx/impl/libxcore/CoreInteract.java b/src/main/java/org/moddingx/libx/impl/libxcore/CoreInteract.java index 04c1bc1b..73ae2b04 100644 --- a/src/main/java/org/moddingx/libx/impl/libxcore/CoreInteract.java +++ b/src/main/java/org/moddingx/libx/impl/libxcore/CoreInteract.java @@ -7,7 +7,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.common.MinecraftForge; +import net.neoforged.neoforge.common.NeoForge; import org.moddingx.libx.event.InteractBlockEmptyHandEvent; import javax.annotation.Nullable; @@ -23,7 +23,7 @@ public class CoreInteract { public static InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack stack, InteractionHand hand, BlockHitResult hit) { if (stack.isEmpty()) { InteractBlockEmptyHandEvent event = new InteractBlockEmptyHandEvent(player, level, hand, hit); - if (MinecraftForge.EVENT_BUS.post(event)) { + if (NeoForge.EVENT_BUS.post(event).isCanceled()) { return event.getCancellationResult() == null ? InteractionResult.PASS : event.getCancellationResult(); } } diff --git a/src/main/java/org/moddingx/libx/impl/loot/AllLootEntry.java b/src/main/java/org/moddingx/libx/impl/loot/AllLootEntry.java index 768b5413..c590b74a 100644 --- a/src/main/java/org/moddingx/libx/impl/loot/AllLootEntry.java +++ b/src/main/java/org/moddingx/libx/impl/loot/AllLootEntry.java @@ -1,5 +1,6 @@ package org.moddingx.libx.impl.loot; +import com.mojang.serialization.MapCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; @@ -16,9 +17,10 @@ public class AllLootEntry extends CompositeEntryBase { public static final ResourceLocation ID = LibX.getInstance().resource("all"); - public static final LootPoolEntryType TYPE = new LootPoolEntryType(CompositeEntryBase.createSerializer(AllLootEntry::new)); + public static final MapCodec CODEC = createCodec(AllLootEntry::new); + public static final LootPoolEntryType TYPE = new LootPoolEntryType(CODEC); - public AllLootEntry(LootPoolEntryContainer[] children, LootItemCondition[] conditions) { + public AllLootEntry(List children, List conditions) { super(children, conditions); } @@ -30,14 +32,14 @@ public LootPoolEntryType getType() { @Nonnull @Override - protected ComposableEntryContainer compose(ComposableEntryContainer[] entries) { - return switch (entries.length) { + protected ComposableEntryContainer compose(@Nonnull List children) { + return switch (children.size()) { case 0 -> ALWAYS_TRUE; - case 1 -> entries[0]; + case 1 -> children.getFirst(); default -> (ctx, consumer) -> { List list = new ArrayList<>(); boolean success = false; - for (ComposableEntryContainer entry : entries) { + for (ComposableEntryContainer entry : children) { if (entry.expand(ctx, list::add)) { success = true; } diff --git a/src/main/java/org/moddingx/libx/impl/loot/CopyBlockEntityDataFunction.java b/src/main/java/org/moddingx/libx/impl/loot/CopyBlockEntityDataFunction.java new file mode 100644 index 00000000..78fd27ea --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/loot/CopyBlockEntityDataFunction.java @@ -0,0 +1,101 @@ +package org.moddingx.libx.impl.loot; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction; +import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import org.moddingx.libx.LibX; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Set; + +public class CopyBlockEntityDataFunction extends LootItemConditionalFunction { + + public static final ResourceLocation ID = LibX.getInstance().resource("copy_block_entity_data"); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> commonFields(instance).and(instance.group( + BuiltInRegistries.BLOCK.holderByNameCodec().fieldOf("block").forGetter(function -> function.block), + Codec.STRING.listOf().fieldOf("tags").forGetter(function -> function.tags.stream().sorted().toList()) + )).apply(instance, CopyBlockEntityDataFunction::new)); + public static final LootItemFunctionType TYPE = new LootItemFunctionType<>(CODEC); + + private final Holder block; + private final Set tags; + + private CopyBlockEntityDataFunction(List conditions, Holder block, List tags) { + this(conditions, block, Set.copyOf(tags)); + } + + public CopyBlockEntityDataFunction(List conditions, Holder block, Set tags) { + super(conditions); + this.block = block; + this.tags = Set.copyOf(tags); + } + + @Nonnull + @Override + public LootItemFunctionType getType() { + return TYPE; + } + + @Nonnull + @Override + protected ItemStack run(@Nonnull ItemStack stack, @Nonnull LootContext context) { + BlockEntity blockEntity = context.getParamOrNull(LootContextParams.BLOCK_ENTITY); + if (blockEntity != null) { + stack.update(DataComponents.BLOCK_ENTITY_DATA, CustomData.EMPTY, data -> { + CompoundTag blockEntityData = blockEntity.saveCustomOnly(context.getLevel().registryAccess()); + for (String tagName : this.tags) { + Tag tag; + if (blockEntityData.contains(tagName) && (tag = blockEntityData.get(tagName)) != null) { + data = data.update(nbt -> nbt.put(tagName, tag.copy())); + } + } + return data; + }); + } + return stack; + } + + public static CopyBlockEntityDataFunction.Builder copyBlockEntityData(Block block, Set tags) { + return new CopyBlockEntityDataFunction.Builder(block, tags); + } + + public static class Builder extends LootItemConditionalFunction.Builder { + + private final Holder block; + private final Set tags; + + @SuppressWarnings("deprecation") + private Builder(Block block, Set tags) { + this.block = block.builtInRegistryHolder(); + this.tags = Set.copyOf(tags); + } + + @Nonnull + @Override + protected Builder getThis() { + return this; + } + + @Nonnull + @Override + public CopyBlockEntityDataFunction build() { + return new CopyBlockEntityDataFunction(this.getConditions(), this.block, this.tags); + } + } +} diff --git a/src/main/java/org/moddingx/libx/impl/loot/modifier/AdditionLootModifier.java b/src/main/java/org/moddingx/libx/impl/loot/modifier/AdditionLootModifier.java index 5cb7d98e..e86fcdc7 100644 --- a/src/main/java/org/moddingx/libx/impl/loot/modifier/AdditionLootModifier.java +++ b/src/main/java/org/moddingx/libx/impl/loot/modifier/AdditionLootModifier.java @@ -1,28 +1,30 @@ package org.moddingx.libx.impl.loot.modifier; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; import javax.annotation.Nonnull; import java.util.Optional; public class AdditionLootModifier extends LootModifier { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ResourceLocation.CODEC.fieldOf("loot_table").forGetter(lm -> lm.table), + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + ResourceLocation.CODEC.fieldOf("loot_table").forGetter(lm -> lm.table.location()), ResourceLocation.CODEC.optionalFieldOf("random_sequence").forGetter(lm -> lm.randomSequence), LOOT_CONDITIONS_CODEC.fieldOf("conditions").forGetter(lm -> lm.conditions) ).apply(instance, AdditionLootModifier::new)); - private final ResourceLocation table; + private final ResourceKey table; private final Optional randomSequence; public AdditionLootModifier(ResourceLocation table, LootItemCondition... conditions) { @@ -35,22 +37,25 @@ public AdditionLootModifier(ResourceLocation table, ResourceLocation randomSeque private AdditionLootModifier(ResourceLocation table, Optional randomSequence, LootItemCondition... conditions) { super(conditions); - this.table = table; + this.table = ResourceKey.create(Registries.LOOT_TABLE, table); this.randomSequence = randomSequence; } @Nonnull @Override - protected ObjectArrayList doApply(ObjectArrayList loot, LootContext context) { - LootTable table = context.getResolver().getLootTable(this.table); - LootContext copy = new LootContext.Builder(context).withQueriedLootTableId(this.table).create(this.randomSequence.orElse(null)); - ObjectArrayList stacks = table.getRandomItems(copy); - loot.addAll(stacks); + protected ObjectArrayList doApply(@Nonnull ObjectArrayList loot, @Nonnull LootContext context) { + Holder.Reference table = context.getResolver().get(Registries.LOOT_TABLE, this.table).orElse(null); + if (table != null) { + LootContext copy = new LootContext.Builder(context).withQueriedLootTableId(this.table.location()).create(this.randomSequence); + ObjectArrayList stacks = table.value().getRandomItems(copy); + loot.addAll(stacks); + } return loot; } + @Nonnull @Override - public Codec codec() { + public MapCodec codec() { return CODEC; } } diff --git a/src/main/java/org/moddingx/libx/impl/loot/modifier/RemovalLootModifier.java b/src/main/java/org/moddingx/libx/impl/loot/modifier/RemovalLootModifier.java index 641f4246..536766f1 100644 --- a/src/main/java/org/moddingx/libx/impl/loot/modifier/RemovalLootModifier.java +++ b/src/main/java/org/moddingx/libx/impl/loot/modifier/RemovalLootModifier.java @@ -1,23 +1,22 @@ package org.moddingx.libx.impl.loot.modifier; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.common.loot.LootModifier; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.loot.LootModifier; import javax.annotation.Nonnull; import java.util.List; public class RemovalLootModifier extends LootModifier { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ForgeRegistries.ITEMS.getCodec().listOf().fieldOf("items").forGetter(lm -> lm.items), + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + BuiltInRegistries.ITEM.byNameCodec().listOf().fieldOf("items").forGetter(lm -> lm.items), LOOT_CONDITIONS_CODEC.fieldOf("conditions").forGetter(lm -> lm.conditions) ).apply(instance, RemovalLootModifier::new)); @@ -30,13 +29,14 @@ public RemovalLootModifier(List items, LootItemCondition... conditions) { @Nonnull @Override - protected ObjectArrayList doApply(ObjectArrayList loot, LootContext context) { + protected ObjectArrayList doApply(@Nonnull ObjectArrayList loot, @Nonnull LootContext context) { loot.removeIf(stack -> this.items.contains(stack.getItem())); return loot; } + @Nonnull @Override - public Codec codec() { + public MapCodec codec() { return CODEC; } } diff --git a/src/main/java/org/moddingx/libx/impl/menu/GenericContainerSlotValidationWrapper.java b/src/main/java/org/moddingx/libx/impl/menu/GenericContainerSlotValidationWrapper.java deleted file mode 100644 index b17cab93..00000000 --- a/src/main/java/org/moddingx/libx/impl/menu/GenericContainerSlotValidationWrapper.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.moddingx.libx.impl.menu; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.function.BiPredicate; - -// Used to provide a validity check for items when using a fake handler -// on the client. -public class GenericContainerSlotValidationWrapper implements IItemHandlerModifiable { - - private final IItemHandlerModifiable handler; - @Nullable - private final BiPredicate validator; - @Nullable // Null on server side as we have access to the method directly. - private final int[] slotLimits; - - public GenericContainerSlotValidationWrapper(IItemHandlerModifiable handler, @Nullable BiPredicate validator, @Nullable int[] slotLimits) { - this.handler = handler; - this.validator = validator; - this.slotLimits = slotLimits; - } - - @Override - public void setStackInSlot(int slot, @Nonnull ItemStack stack) { - this.handler.setStackInSlot(slot, stack); - } - - @Override - public int getSlots() { - return this.handler.getSlots(); - } - - @Nonnull - @Override - public ItemStack getStackInSlot(int slot) { - return this.handler.getStackInSlot(slot); - } - - @Nonnull - @Override - public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { - return this.handler.insertItem(slot, stack, simulate); - } - - @Nonnull - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - return this.handler.extractItem(slot, amount, simulate); - } - - @Override - public int getSlotLimit(int slot) { - if (this.slotLimits != null && slot >= 0 && slot < this.slotLimits.length) { - return this.slotLimits[slot]; - } else { - return this.handler.getSlotLimit(slot); - } - } - - @Override - public boolean isItemValid(int slot, @Nonnull ItemStack stack) { - return this.validator == null || this.validator.test(slot, stack); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/menu/screen/GenericScreen.java b/src/main/java/org/moddingx/libx/impl/menu/screen/GenericScreen.java deleted file mode 100644 index 8c224c67..00000000 --- a/src/main/java/org/moddingx/libx/impl/menu/screen/GenericScreen.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.moddingx.libx.impl.menu.screen; - -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.player.Inventory; -import org.apache.commons.lang3.tuple.Pair; -import org.moddingx.libx.menu.GenericMenu; -import org.moddingx.libx.render.RenderHelper; - -import javax.annotation.Nonnull; - -// Screen for the GenericContainerMenu. Do not use manually. -public class GenericScreen extends AbstractContainerScreen { - - private final GenericMenu menu; - - public GenericScreen(GenericMenu menu, Inventory playerContainer, Component title) { - super(menu, playerContainer, title); - this.menu = menu; - this.imageWidth = menu.width; - this.imageHeight = menu.height; - this.inventoryLabelX = menu.invX; - this.inventoryLabelY = menu.invY - 11; - } - - @Override - public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { - this.renderBackground(graphics); - super.render(graphics, mouseX, mouseY, partialTicks); - this.renderTooltip(graphics, mouseX, mouseY); - } - - @Override - protected void renderBg(@Nonnull GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) { - if (this.minecraft != null) { - int i = (this.width - this.imageWidth) / 2; - int j = (this.height - this.imageHeight) / 2; - RenderHelper.renderGuiBackground(graphics, i, j, this.imageWidth, this.imageHeight); - for (Pair slot : this.menu.slotList) { - graphics.blit(RenderHelper.TEXTURE_CHEST_GUI, i + slot.getLeft() - 1, j + slot.getRight() - 1, 25, 35, 18, 18); - } - graphics.blit(RenderHelper.TEXTURE_CHEST_GUI, i + this.menu.invX - 1, j + this.menu.invY - 1, 7, 139, 162, 76); - } - } -} diff --git a/src/main/java/org/moddingx/libx/impl/network/BeRequestHandler.java b/src/main/java/org/moddingx/libx/impl/network/BeRequestHandler.java new file mode 100644 index 00000000..391c9f92 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/network/BeRequestHandler.java @@ -0,0 +1,43 @@ +package org.moddingx.libx.impl.network; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.HandlerThread; +import org.moddingx.libx.LibX; +import org.moddingx.libx.network.PacketHandler; + +import javax.annotation.Nonnull; + +public class BeRequestHandler extends PacketHandler { + + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(LibX.getInstance().resource("be_request")); + + protected BeRequestHandler() { + super(TYPE, PacketFlow.SERVERBOUND, BlockPos.STREAM_CODEC.map(Message::new, Message::pos), HandlerThread.MAIN); + } + + @Override + public void handle(Message msg, IPayloadContext ctx) { + if (ctx.player() instanceof ServerPlayer sender) { + ServerLevel level = sender.serverLevel(); + //noinspection deprecation + if (level.hasChunkAt(msg.pos()) && NetworkImpl.getImpl().canSend(sender, BeUpdateHandler.TYPE)) { + BeUpdateHandler.Message reply = NetworkImpl.getImpl().getBeUpdateMessage(sender.level(), msg.pos()); + if (reply != null) ctx.reply(reply); + } + } + } + + public record Message(BlockPos pos) implements CustomPacketPayload { + + @Nonnull + @Override + public Type type() { + return BeRequestHandler.TYPE; + } + } +} diff --git a/src/main/java/org/moddingx/libx/impl/network/BeRequestMessage.java b/src/main/java/org/moddingx/libx/impl/network/BeRequestMessage.java deleted file mode 100644 index dd9940e3..00000000 --- a/src/main/java/org/moddingx/libx/impl/network/BeRequestMessage.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.moddingx.libx.impl.network; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent; -import org.moddingx.libx.network.PacketHandler; -import org.moddingx.libx.network.PacketSerializer; - -import java.util.function.Supplier; - -public record BeRequestMessage(BlockPos pos) { - - public static class Serializer implements PacketSerializer { - - @Override - public Class messageClass() { - return BeRequestMessage.class; - } - - @Override - public void encode(BeRequestMessage msg, FriendlyByteBuf buffer) { - buffer.writeBlockPos(msg.pos); - } - - @Override - public BeRequestMessage decode(FriendlyByteBuf buffer) { - return new BeRequestMessage(buffer.readBlockPos()); - } - } - - public static class Handler implements PacketHandler { - - @Override - public Target target() { - return Target.MAIN_THREAD; - } - - @Override - public boolean handle(BeRequestMessage msg, Supplier ctx) { - ServerPlayer sender = ctx.get().getSender(); - if (sender != null) { - ServerLevel level = sender.serverLevel(); - //noinspection deprecation - if (level.hasChunkAt(msg.pos())) { - NetworkImpl.getImpl().updateBE(ctx.get(), level, msg.pos()); - } - } - return true; - } - } -} diff --git a/src/main/java/org/moddingx/libx/impl/network/BeUpdateHandler.java b/src/main/java/org/moddingx/libx/impl/network/BeUpdateHandler.java new file mode 100644 index 00000000..edf09c5e --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/network/BeUpdateHandler.java @@ -0,0 +1,56 @@ +package org.moddingx.libx.impl.network; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.HandlerThread; +import org.moddingx.libx.LibX; +import org.moddingx.libx.codec.MoreStreamCodecs; +import org.moddingx.libx.network.PacketHandler; + +import javax.annotation.Nonnull; + +public class BeUpdateHandler extends PacketHandler { + + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(LibX.getInstance().resource("be_update")); + + protected BeUpdateHandler() { + super(TYPE, PacketFlow.CLIENTBOUND, StreamCodec.composite( + BlockPos.STREAM_CODEC, Message::pos, + ResourceLocation.STREAM_CODEC, Message::id, + MoreStreamCodecs.COMPOUND_TAG, Message::nbt, + Message::new + ), HandlerThread.MAIN); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void handle(Message msg, IPayloadContext ctx) { + Level level = Minecraft.getInstance().level; + if (level != null) { + BlockEntity be = level.getBlockEntity(msg.pos()); + if (be != null && msg.id().equals(BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(be.getType()))) { + be.handleUpdateTag(msg.nbt(), level.registryAccess()); + } + } + } + + public record Message(BlockPos pos, ResourceLocation id, CompoundTag nbt) implements CustomPacketPayload { + + @Nonnull + @Override + public Type type() { + return BeUpdateHandler.TYPE; + } + } +} diff --git a/src/main/java/org/moddingx/libx/impl/network/BeUpdateMessage.java b/src/main/java/org/moddingx/libx/impl/network/BeUpdateMessage.java deleted file mode 100644 index 17d1df69..00000000 --- a/src/main/java/org/moddingx/libx/impl/network/BeUpdateMessage.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.moddingx.libx.impl.network; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent; -import net.minecraftforge.registries.ForgeRegistries; -import org.moddingx.libx.network.PacketHandler; -import org.moddingx.libx.network.PacketSerializer; - -import java.util.function.Supplier; - -public record BeUpdateMessage(BlockPos pos, ResourceLocation id, CompoundTag nbt) { - - public static class Serializer implements PacketSerializer { - - @Override - public Class messageClass() { - return BeUpdateMessage.class; - } - - @Override - public void encode(BeUpdateMessage msg, FriendlyByteBuf buffer) { - buffer.writeBlockPos(msg.pos); - buffer.writeResourceLocation(msg.id); - buffer.writeNbt(msg.nbt); - } - - @Override - public BeUpdateMessage decode(FriendlyByteBuf buffer) { - BlockPos pos = buffer.readBlockPos(); - ResourceLocation id = buffer.readResourceLocation(); - CompoundTag nbt = buffer.readNbt(); - return new BeUpdateMessage(pos, id, nbt); - } - } - - public static class Handler implements PacketHandler { - - @Override - public Target target() { - return Target.MAIN_THREAD; - } - - @Override - public boolean handle(BeUpdateMessage msg, Supplier ctx) { - Level level = Minecraft.getInstance().level; - if (level != null) { - BlockEntity be = level.getBlockEntity(msg.pos()); - if (be != null && msg.id().equals(ForgeRegistries.BLOCK_ENTITY_TYPES.getKey(be.getType()))) { - be.handleUpdateTag(msg.nbt()); - } - } - return true; - } - } -} diff --git a/src/main/java/org/moddingx/libx/impl/network/ConfigShadowHandler.java b/src/main/java/org/moddingx/libx/impl/network/ConfigShadowHandler.java new file mode 100644 index 00000000..41deeb88 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/network/ConfigShadowHandler.java @@ -0,0 +1,77 @@ +package org.moddingx.libx.impl.network; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.HandlerThread; +import org.moddingx.libx.LibX; +import org.moddingx.libx.impl.config.ConfigImpl; +import org.moddingx.libx.impl.config.ConfigState; +import org.moddingx.libx.network.PacketHandler; +import org.moddingx.libx.util.Misc; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ConfigShadowHandler extends PacketHandler { + + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(LibX.getInstance().resource("config_shadow")); + + protected ConfigShadowHandler() { + super(TYPE, PacketFlow.CLIENTBOUND, StreamCodec.of(ConfigShadowHandler::encode, ConfigShadowHandler::decode), HandlerThread.MAIN); + } + + private static void encode(FriendlyByteBuf buffer, Message msg) { + if (msg.config() == null || msg.state() == null || Misc.MISSINGNO.equals(msg.config().id)) { + buffer.writeResourceLocation(Misc.MISSINGNO); + } else { + buffer.writeResourceLocation(msg.config().id); + FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.buffer()); + msg.state().write(b); + buffer.writeVarInt(b.writerIndex()); + buffer.writeBytes(b); + } + } + + private static Message decode(FriendlyByteBuf buffer) { + ResourceLocation configId = buffer.readResourceLocation(); + if (Misc.MISSINGNO.equals(configId)) { + return new Message(null, null); + } + ConfigImpl config = ConfigImpl.getConfigNullable(configId); + int size = buffer.readVarInt(); + if (config == null) { + LibX.logger.warn("Received shadow message for unknown config: '" + configId + "'. Ignoring"); + // Skip the bytes we don't know about. + buffer.skipBytes(size); + return new Message(null, null); + } else if (config.clientConfig) { + LibX.logger.warn("Received shadow message for not-synced config: '" + configId + "'. Ignoring"); + // Skip the bytes we don't know about. + buffer.skipBytes(size); + return new Message(null, null); + } else { + return new Message(config, config.readState(buffer)); + } + } + + @Override + public void handle(Message msg, IPayloadContext ctx) { + if (msg.config() != null && msg.state() != null) { + msg.config().shadowBy(msg.state()); + } + } + + public record Message(@Nullable ConfigImpl config, @Nullable ConfigState state) implements CustomPacketPayload { + + @Nonnull + @Override + public Type type() { + return ConfigShadowHandler.TYPE; + } + } +} diff --git a/src/main/java/org/moddingx/libx/impl/network/ConfigShadowMessage.java b/src/main/java/org/moddingx/libx/impl/network/ConfigShadowMessage.java deleted file mode 100644 index 78fbb182..00000000 --- a/src/main/java/org/moddingx/libx/impl/network/ConfigShadowMessage.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.moddingx.libx.impl.network; - -import io.netty.buffer.Unpooled; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.network.NetworkEvent; -import org.moddingx.libx.LibX; -import org.moddingx.libx.impl.config.ConfigImpl; -import org.moddingx.libx.impl.config.ConfigState; -import org.moddingx.libx.network.PacketHandler; -import org.moddingx.libx.network.PacketSerializer; -import org.moddingx.libx.util.Misc; - -import javax.annotation.Nullable; -import java.util.function.Supplier; - -public record ConfigShadowMessage(@Nullable ConfigImpl config, @Nullable ConfigState state) { - - public static class Serializer implements PacketSerializer { - - @Override - public Class messageClass() { - return ConfigShadowMessage.class; - } - - @Override - public void encode(ConfigShadowMessage msg, FriendlyByteBuf buffer) { - if (msg.config() == null || msg.state() == null) { - buffer.writeResourceLocation(Misc.MISSINGNO); - } else { - buffer.writeResourceLocation(msg.config().id); - FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.buffer()); - msg.state().write(b); - buffer.writeVarInt(b.writerIndex()); - buffer.writeBytes(b); - } - } - - @Override - public ConfigShadowMessage decode(FriendlyByteBuf buffer) { - ResourceLocation configId = buffer.readResourceLocation(); - if (Misc.MISSINGNO.equals(configId)) { - return new ConfigShadowMessage(null, null); - } - ConfigImpl config = ConfigImpl.getConfigNullable(configId); - int size = buffer.readVarInt(); - if (config == null) { - LibX.logger.warn("Received shadow message for unknown config: '" + configId + "'. Ignoring"); - // Skip the bytes we don't know about. - buffer.skipBytes(size); - return new ConfigShadowMessage(null, null); - } else if (config.clientConfig) { - LibX.logger.warn("Received shadow message for not-synced config: '" + configId + "'. Ignoring"); - // Skip the bytes we don't know about. - buffer.skipBytes(size); - return new ConfigShadowMessage(null, null); - } else { - return new ConfigShadowMessage(config, config.readState(buffer)); - } - } - } - - public static class Handler implements PacketHandler { - - @Override - public Target target() { - return Target.MAIN_THREAD; - } - - @Override - public boolean handle(ConfigShadowMessage msg, Supplier ctx) { - if (msg.config() != null && msg.state() != null) { - msg.config().shadowBy(msg.state()); - } - return true; - } - } -} diff --git a/src/main/java/org/moddingx/libx/impl/network/NetworkImpl.java b/src/main/java/org/moddingx/libx/impl/network/NetworkImpl.java index 56c8327a..478d3ba3 100644 --- a/src/main/java/org/moddingx/libx/impl/network/NetworkImpl.java +++ b/src/main/java/org/moddingx/libx/impl/network/NetworkImpl.java @@ -1,16 +1,18 @@ package org.moddingx.libx.impl.network; -import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.NetworkEvent; -import net.minecraftforge.network.PacketDistributor; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.network.PacketDistributor; +import org.moddingx.libx.impl.config.ConfigImpl; +import org.moddingx.libx.impl.config.ConfigState; import org.moddingx.libx.mod.ModX; import org.moddingx.libx.network.NetworkX; @@ -25,6 +27,10 @@ public NetworkImpl(ModX mod) { super(mod); if (impl != null) throw new IllegalStateException("NetworkImpl created twice."); impl = this; + + this.registerOptional(new ConfigShadowHandler()); + this.registerOptional(new BeRequestHandler()); + this.registerOptional(new BeUpdateHandler()); } @Nonnull @@ -34,61 +40,57 @@ public static NetworkImpl getImpl() { } @Override - protected Protocol getProtocol() { - // Not required on the client, so LibX can be used by client only mods - return new Protocol("10", ProtocolSide.VANILLA, ProtocolSide.REQUIRED); - } - - // Gets whether a packet can be currently sent. - // Will return false on clients connected to a non-LibX server - public boolean canSend() { - return DistExecutor.unsafeRunForDist( - () -> () -> Minecraft.getInstance().getConnection() != null && this.channel.isRemotePresent(Minecraft.getInstance().getConnection().getConnection()), - () -> () -> true - ); + protected String getVersion() { + return "11"; } - @Override - protected void registerPackets() { - this.registerGame(NetworkDirection.PLAY_TO_CLIENT, new BeUpdateMessage.Serializer(), () -> BeUpdateMessage.Handler::new); - this.registerGame(NetworkDirection.PLAY_TO_CLIENT, new ConfigShadowMessage.Serializer(), () -> ConfigShadowMessage.Handler::new); - - this.registerGame(NetworkDirection.PLAY_TO_SERVER, new BeRequestMessage.Serializer(), () -> BeRequestMessage.Handler::new); + public void requestBE(Level level, BlockPos pos) { + if (level.isClientSide && this.canSend(BeRequestHandler.TYPE)) { + PacketDistributor.sendToServer(new BeRequestHandler.Message(pos)); + } } - public void updateBE(Level level, BlockPos pos) { - BeUpdateMessage msg = this.getBeUpdateMessage(level, pos); + public void updateBE(ServerLevel level, BlockPos pos) { + BeUpdateHandler.Message msg = this.getBeUpdateMessage(level, pos); if (msg != null) { - this.channel.send(PacketDistributor.TRACKING_CHUNK.with(() -> level.getChunkAt(pos)), msg); + // We don't use PacketDistributor.sendToPlayersTrackingChunk here because our payload is optional + for (ServerPlayer player : level.getChunkSource().chunkMap.getPlayers(new ChunkPos(pos), false)) { + if (this.canSend(player, BeUpdateHandler.TYPE)) { + PacketDistributor.sendToPlayer(player, msg); + } + } } } - void updateBE(NetworkEvent.Context context, Level level, BlockPos pos) { - BeUpdateMessage msg = this.getBeUpdateMessage(level, pos); - if (msg != null) { - this.channel.reply(msg, context); + public void syncConfig(MinecraftServer server, @Nullable ServerPlayer receiver, ConfigImpl config, ConfigState state) { + ConfigShadowHandler.Message msg = new ConfigShadowHandler.Message(config, state); + if (receiver != null) { + if (this.canSend(receiver, ConfigShadowHandler.TYPE)) { + PacketDistributor.sendToPlayer(receiver, msg); + } + } else { + // We don't use PacketDistributor.sendToAllPlayers here because our payload is optional + for (ServerPlayer player : server.getPlayerList().getPlayers()) { + if (this.canSend(player, BeUpdateHandler.TYPE)) { + player.connection.send(msg); + } + } } } @Nullable - private BeUpdateMessage getBeUpdateMessage(Level level, BlockPos pos) { - if (!level.isClientSide && this.canSend()) { + BeUpdateHandler.Message getBeUpdateMessage(Level level, BlockPos pos) { + if (!level.isClientSide) { BlockEntity be = level.getBlockEntity(pos); if (be == null) return null; - CompoundTag nbt = be.getUpdateTag(); + CompoundTag nbt = be.getUpdateTag(level.registryAccess()); //noinspection ConstantConditions if (nbt == null) return null; - ResourceLocation id = ForgeRegistries.BLOCK_ENTITY_TYPES.getKey(be.getType()); + ResourceLocation id = BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(be.getType()); if (id == null) return null; - return new BeUpdateMessage(pos, id, nbt); + return new BeUpdateHandler.Message(pos, id, nbt); } else { return null; } } - - public void requestBE(Level level, BlockPos pos) { - if (level.isClientSide && this.canSend()) { - this.channel.sendToServer(new BeRequestMessage(pos)); - } - } } diff --git a/src/main/java/org/moddingx/libx/impl/reflect/ReflectionHacks.java b/src/main/java/org/moddingx/libx/impl/reflect/ReflectionHacks.java index 984160f9..3a74fb70 100644 --- a/src/main/java/org/moddingx/libx/impl/reflect/ReflectionHacks.java +++ b/src/main/java/org/moddingx/libx/impl/reflect/ReflectionHacks.java @@ -3,9 +3,7 @@ import org.moddingx.libx.util.lazy.LazyValue; import sun.misc.Unsafe; -import javax.annotation.Nullable; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; public class ReflectionHacks { @@ -27,55 +25,4 @@ public static T newInstance(Class cls) throws InstantiationException { //noinspection unchecked return (T) unsafe.get().allocateInstance(cls); } - - public static void setFinalField(Field field, Object instance, @Nullable Object value) { - Object base; - long offset; - if (Modifier.isStatic(field.getModifiers())) { - base = unsafe.get().staticFieldBase(field); - offset = unsafe.get().staticFieldOffset(field); - } else { - if (instance == null) { - throw new NullPointerException("No instance for non-static field: " + field); - } else if (!field.getDeclaringClass().isAssignableFrom(instance.getClass())) { - throw new IllegalArgumentException("Instance has wrong type for field: " + instance + " " + field); - } else { - base = instance; - offset = unsafe.get().objectFieldOffset(field); - } - } - if (field.getType() == void.class) { - throw new IllegalStateException("Field with void type"); - } else if (field.isEnumConstant()) { - throw new IllegalArgumentException("Can't change enum constant"); - } else if (field.getType() == boolean.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putBooleanVolatile(base, offset, (Boolean) value); - } else if (field.getType() == byte.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putByteVolatile(base, offset, (Byte) value); - } else if (field.getType() == char.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putCharVolatile(base, offset, (Character) value); - } else if (field.getType() == short.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putShortVolatile(base, offset, (Short) value); - } else if (field.getType() == int.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putIntVolatile(base, offset, (Integer) value); - } else if (field.getType() == long.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putLongVolatile(base, offset, (Long) value); - } else if (field.getType() == float.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putFloatVolatile(base, offset, (Float) value); - } else if (field.getType() == double.class) { - if (value == null) throw new NullPointerException("Null primitive for field: " + field); - unsafe.get().putDoubleVolatile(base, offset, (Double) value); - } else if (value != null && !field.getType().isAssignableFrom(value.getClass())) { - throw new ClassCastException("Expected value of type " + field.getType() + " for field " + field + ", got " + value.getClass()); - } else { - unsafe.get().putObjectVolatile(base, offset, value); - } - } } diff --git a/src/main/java/org/moddingx/libx/impl/registration/BuiltinRegistryHelper.java b/src/main/java/org/moddingx/libx/impl/registration/BuiltinRegistryHelper.java new file mode 100644 index 00000000..c611f9f3 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/registration/BuiltinRegistryHelper.java @@ -0,0 +1,30 @@ +package org.moddingx.libx.impl.registration; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; + +import javax.annotation.Nonnull; +import java.util.Optional; +import java.util.stream.Stream; + +public class BuiltinRegistryHelper { + + // Only use this, if you know what you are doing. The game expects datapack registries to be present here, which they aren't. + public static final HolderLookup.Provider BUILTIN_REGISTRY_LOOKUP = new HolderLookup.Provider() { + + @Nonnull + @Override + public Stream>> listRegistries() { + return BuiltInRegistries.REGISTRY.registryKeySet().stream().map(key -> key); + } + + @Nonnull + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public Optional> lookup(@Nonnull ResourceKey> registryKey) { + return BuiltInRegistries.REGISTRY.getOptional((ResourceKey) registryKey); + } + }; +} diff --git a/src/main/java/org/moddingx/libx/impl/registration/RegistrationDispatcher.java b/src/main/java/org/moddingx/libx/impl/registration/RegistrationDispatcher.java index 675cb487..f05570e9 100644 --- a/src/main/java/org/moddingx/libx/impl/registration/RegistrationDispatcher.java +++ b/src/main/java/org/moddingx/libx/impl/registration/RegistrationDispatcher.java @@ -3,20 +3,19 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.RegisterEvent; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.registries.RegisterEvent; import org.apache.commons.lang3.tuple.Pair; -import org.moddingx.libx.impl.registration.tracking.TrackingInstance; +import org.moddingx.libx.impl.registration.handler.CapabilityRegistrationHandler; +import org.moddingx.libx.impl.registration.handler.ClientExtensionRegistrationHandler; import org.moddingx.libx.mod.ModXRegistration; import org.moddingx.libx.registration.*; -import org.moddingx.libx.registration.tracking.RegistryTracker; import javax.annotation.Nullable; -import java.lang.reflect.Field; import java.util.*; import java.util.function.Consumer; @@ -26,7 +25,6 @@ public class RegistrationDispatcher { private final ModXRegistration mod; - private final boolean trackingEnabled; private final List conditions; private final List transformers; @@ -36,15 +34,19 @@ public class RegistrationDispatcher { private final Map>, RegistryData> allEntries; private final List registerables; + private final CapabilityRegistrationHandler capabilityHandler; + @Nullable private final ClientExtensionRegistrationHandler clientExtHandler; + public RegistrationDispatcher(ModXRegistration mod, RegistrationBuilder.Result result) { this.mod = mod; - this.trackingEnabled = result.tracking(); this.conditions = result.conditions(); this.transformers = result.transformers(); this.hasRegistrationRun = false; this.registrationHandlers = new ArrayList<>(); this.allEntries = new HashMap<>(); this.registerables = new LinkedList<>(); + this.capabilityHandler = new CapabilityRegistrationHandler(this::runRegistration); + this.clientExtHandler = FMLLoader.getDist() == Dist.CLIENT ? new ClientExtensionRegistrationHandler(this::runRegistration) : null; } private void runRegistration() { @@ -60,6 +62,17 @@ private void runRegistration() { this.registrationHandlers.forEach(Runnable::run); } + public void setupEventListeners(IEventBus modBus) { + modBus.addListener(this::registerBy); + modBus.addListener(this::registerCommon); + modBus.addListener(this::registerClient); + modBus.addListener(this.capabilityHandler::registerCapabilities); + if (this.clientExtHandler != null) { + modBus.addListener(this.clientExtHandler::registerClientExtensions); + modBus.addListener(this.clientExtHandler::registerMenuScreens); + } + } + public void addRegistrationHandler(Runnable handler) { synchronized (this.LOCK) { if (this.hasRegistrationRun) { @@ -86,18 +99,16 @@ public void register(@Nullable ResourceKey> registry, this.addEntry(resourceKey, value); } + this.capabilityHandler.handle(rl, value); + if (this.clientExtHandler != null) { + this.clientExtHandler.handle(rl, value); + } + if (value instanceof Registerable registerable) { this.registerables.add(new NamedRegisterable(ctx, registerable)); registerable.registerAdditional(ctx, collector); - } - - if (registry != null) { - if (value instanceof Registerable registerable && this.trackingEnabled) { - try { - registerable.initTracking(ctx, new TrackingInstance(rl, value)); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Failed to initialise registry tracking for " + id + " in " + registry + ": " + value, e); - } + if (FMLLoader.getDist() == Dist.CLIENT) { + RegisterableClientAdapter.registerClientAdditional(registerable, ctx, collector); } } } @@ -110,7 +121,7 @@ private void addEntry(ResourceKey resourceKey, Object element) { } } - public void registerBy(RegisterEvent event) { + private void registerBy(RegisterEvent event) { this.runRegistration(); RegistryData data = this.allEntries.get(event.getRegistryKey()); @@ -123,29 +134,27 @@ public void registerBy(RegisterEvent event) { }); } } - - public void registerCommon(FMLCommonSetupEvent event) { + + private void registerCommon(FMLCommonSetupEvent event) { + this.runRegistration(); this.registerables.forEach(reg -> reg.registerCommon(event::enqueueWork)); } - - public void registerClient(FMLClientSetupEvent event) { + + private void registerClient(FMLClientSetupEvent event) { + this.runRegistration(); this.registerables.forEach(reg -> reg.registerClient(event::enqueueWork)); } - public void notifyRegisterField(IForgeRegistry registry, String id, Field field) { - if (this.trackingEnabled) { - RegistryTracker.track(registry, field, this.mod.resource(id)); - } - } - private record NamedRegisterable(RegistrationContext ctx, Registerable value) { public void registerCommon(Consumer enqueue) { - this.value().registerCommon(new SetupContext(this.ctx(), enqueue)); + this.value().setupCommon(new SetupContext(this.ctx(), enqueue)); } public void registerClient(Consumer enqueue) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.value().registerClient(new SetupContext(this.ctx(), enqueue))); + if (FMLLoader.getDist() == Dist.CLIENT) { + RegisterableClientAdapter.registerClient(this.value(), new SetupContext(this.ctx(), enqueue)); + } } } @@ -167,4 +176,22 @@ public List, Object>> values() { return Collections.unmodifiableList(this.values); } } + + // Safely reference the client only methods from registerable + private static class RegisterableClientAdapter { + + static { + if (FMLLoader.getDist().isDedicatedServer()) { + throw new IllegalStateException("RegisterableClientAdapter should never be loaded on the dedicated server. This is a bug in LibX."); + } + } + + public static void registerClient(Registerable registerable, SetupContext ctx) { + registerable.setupClient(ctx); + } + + public static void registerClientAdditional(Registerable registerable, RegistrationContext ctx, Registerable.EntryCollector builder) { + registerable.registerClientAdditional(ctx, builder); + } + } } diff --git a/src/main/java/org/moddingx/libx/impl/registration/handler/CapabilityRegistrationHandler.java b/src/main/java/org/moddingx/libx/impl/registration/handler/CapabilityRegistrationHandler.java new file mode 100644 index 00000000..60c2a52f --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/registration/handler/CapabilityRegistrationHandler.java @@ -0,0 +1,65 @@ +package org.moddingx.libx.impl.registration.handler; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import org.moddingx.libx.registration.util.CapabilityInfo; + +import java.util.HashMap; +import java.util.Map; + +public class CapabilityRegistrationHandler extends SpecialRegistrationHandler { + + private final Map> items; + private final Map> blocks; + private final Map> blockEntities; + private final Map> entities; + + public CapabilityRegistrationHandler(Runnable runRegistration) { + super(runRegistration); + this.items = new HashMap<>(); + this.blocks = new HashMap<>(); + this.blockEntities = new HashMap<>(); + this.entities = new HashMap<>(); + } + + @Override + public void handle(ResourceLocation id, Object object) { + if (object instanceof CapabilityInfo.Item itemInfo) { + this.addToMap("CapabilityInfo.Item", this.items, id, itemInfo); + } + if (object instanceof CapabilityInfo.Block blockInfo) { + this.addToMap("CapabilityInfo.Block", this.blocks, id, blockInfo); + } + if (object instanceof CapabilityInfo.BlockEntity blockEntityInfo) { + this.addToMap("CapabilityInfo.BlockEntity", this.blockEntities, id, blockEntityInfo); + } + if (object instanceof CapabilityInfo.Entity entityInfo) { + this.addToMap("CapabilityInfo.Entity", this.entities, id, entityInfo); + } + } + + public void registerCapabilities(RegisterCapabilitiesEvent event) { + for (CapabilityInfo.Item info : this.items.values()) registerItemTo(event, info); + for (CapabilityInfo.Block info : this.blocks.values()) registerBlockTo(event, info); + for (CapabilityInfo.BlockEntity info : this.blockEntities.values()) registerBlockEntityTo(event, info); + for (CapabilityInfo.Entity info : this.entities.values()) registerEntityTo(event, info); + } + + private static void registerItemTo(RegisterCapabilitiesEvent event, CapabilityInfo.Item info) { + event.registerItem(info.capability(), info.provider(), info.item()); + } + + private static void registerBlockTo(RegisterCapabilitiesEvent event, CapabilityInfo.Block info) { + event.registerBlock(info.capability(), info.provider(), info.block()); + } + + private static void registerBlockEntityTo(RegisterCapabilitiesEvent event, CapabilityInfo.BlockEntity info) { + event.registerBlockEntity(info.capability(), info.blockEntityType(), info.provider()); + } + + private static void registerEntityTo(RegisterCapabilitiesEvent event, CapabilityInfo.Entity info) { + event.registerEntity(info.capability(), info.entityType(), info.provider()); + } +} diff --git a/src/main/java/org/moddingx/libx/impl/registration/handler/ClientExtensionRegistrationHandler.java b/src/main/java/org/moddingx/libx/impl/registration/handler/ClientExtensionRegistrationHandler.java new file mode 100644 index 00000000..8be0d749 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/registration/handler/ClientExtensionRegistrationHandler.java @@ -0,0 +1,98 @@ +package org.moddingx.libx.impl.registration.handler; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent; +import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import org.moddingx.libx.registration.util.ClientExtensionInfo; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +public class ClientExtensionRegistrationHandler extends SpecialRegistrationHandler { + + private final Map items; + private final Map blocks; + private final Map fluids; + private final Map mobEffects; + private final Map> menuScreens; + + public ClientExtensionRegistrationHandler(Runnable runRegistration) { + super(runRegistration); + this.items = new HashMap<>(); + this.blocks = new HashMap<>(); + this.fluids = new HashMap<>(); + this.mobEffects = new HashMap<>(); + this.menuScreens = new HashMap<>(); + } + + @Override + public void handle(ResourceLocation id, Object object) { + if (object instanceof ClientExtensionInfo.Item itemInfo) { + this.addToMap("ClientExtensionInfo.Item", this.items, id, itemInfo); + } + if (object instanceof ClientExtensionInfo.Block blockInfo) { + this.addToMap("ClientExtensionInfo.Block", this.blocks, id, blockInfo); + } + if (object instanceof ClientExtensionInfo.Fluid fluidInfo) { + this.addToMap("ClientExtensionInfo.Fluid", this.fluids, id, fluidInfo); + } + if (object instanceof ClientExtensionInfo.MobEffect mobEffectInfo) { + this.addToMap("ClientExtensionInfo.MobEffect", this.mobEffects, id, mobEffectInfo); + } + if (object instanceof ClientExtensionInfo.MenuScreen menuScreenInfo) { + this.addToMap("ClientExtensionInfo.MenuScreen", this.menuScreens, id, menuScreenInfo); + } + } + + public void registerClientExtensions(RegisterClientExtensionsEvent event) { + this.runRegistration(); + for (Map.Entry entry : this.items.entrySet()) { + Item item = BuiltInRegistries.ITEM.getOptional(entry.getKey()).orElse(null); + if (item == null) throw new IllegalStateException("ClientExtensionInfo.Item registered for unknown item: " + entry.getKey()); + event.registerItem(entry.getValue().extensions().get(), item); + } + for (Map.Entry entry : this.blocks.entrySet()) { + Block block = BuiltInRegistries.BLOCK.getOptional(entry.getKey()).orElse(null); + if (block == null) throw new IllegalStateException("ClientExtensionInfo.Block registered for unknown block: " + entry.getKey()); + event.registerBlock(entry.getValue().extensions().get(), block); + } + for (Map.Entry entry : this.fluids.entrySet()) { + FluidType fluidType = NeoForgeRegistries.FLUID_TYPES.getOptional(entry.getKey()).orElse(null); + if (fluidType == null) throw new IllegalStateException("ClientExtensionInfo.Fluid registered for unknown fluid type: " + entry.getKey()); + event.registerFluidType(entry.getValue().extensions().get(), fluidType); + } + for (Map.Entry entry : this.mobEffects.entrySet()) { + MobEffect effect = BuiltInRegistries.MOB_EFFECT.getOptional(entry.getKey()).orElse(null); + if (effect == null) throw new IllegalStateException("ClientExtensionInfo.MobEffect registered for unknown mob effect: " + entry.getKey()); + event.registerMobEffect(entry.getValue().extensions().get(), effect); + } + } + + public void registerMenuScreens(RegisterMenuScreensEvent event) { + this.runRegistration(); + for (Map.Entry> entry : this.menuScreens.entrySet()) { + MenuType menuType = BuiltInRegistries.MENU.getOptional(entry.getKey()).orElse(null); + if (menuType == null) throw new IllegalStateException("ClientExtensionInfo.MenuScreen registered for unknown menu type: " + entry.getKey()); + if (menuType != entry.getValue().menuType()) { + @Nullable ResourceLocation expectedId = BuiltInRegistries.MENU.getKey(entry.getValue().menuType()); + throw new IllegalStateException("ClientExtensionInfo.MenuScreen registered with wrong id, expected " + expectedId + ", got " + entry.getKey()); + } + registerMenuScreenTo(event, entry.getValue()); + } + } + + private static > void registerMenuScreenTo(RegisterMenuScreensEvent event, ClientExtensionInfo.MenuScreen menuScreenInfo) { + event.register(menuScreenInfo.menuType(), menuScreenInfo.screenConstructor()); + } +} diff --git a/src/main/java/org/moddingx/libx/impl/registration/handler/SpecialRegistrationHandler.java b/src/main/java/org/moddingx/libx/impl/registration/handler/SpecialRegistrationHandler.java new file mode 100644 index 00000000..3ba767e8 --- /dev/null +++ b/src/main/java/org/moddingx/libx/impl/registration/handler/SpecialRegistrationHandler.java @@ -0,0 +1,27 @@ +package org.moddingx.libx.impl.registration.handler; + +import net.minecraft.resources.ResourceLocation; + +import java.util.Map; + +public abstract class SpecialRegistrationHandler { + + private final Runnable runRegistration; + + protected SpecialRegistrationHandler(Runnable runRegistration) { + this.runRegistration = runRegistration; + } + + protected final void runRegistration() { + this.runRegistration.run(); + } + + public abstract void handle(ResourceLocation id, Object object); + + protected void addToMap(String clsName, Map map, ResourceLocation id, T value) { + if (map.containsKey(id)) { + throw new IllegalStateException("Two instances of " + clsName + " registered with the same id: " + id); + } + map.put(id, value); + } +} diff --git a/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingData.java b/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingData.java deleted file mode 100644 index 9bb6f2b7..00000000 --- a/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingData.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.moddingx.libx.impl.registration.tracking; - -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.registries.IForgeRegistry; -import org.moddingx.libx.LibX; -import org.moddingx.libx.impl.ModInternal; -import org.moddingx.libx.impl.reflect.ReflectionHacks; -import org.moddingx.libx.mod.ModXRegistration; -import org.moddingx.libx.registration.Registerable; -import org.moddingx.libx.registration.RegistrationContext; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public final class TrackingData { - - public final ResourceLocation registryId; - public final IForgeRegistry registry; - - private final List staticFields; - private final List instanceFields; - private final List> actions; - private final Set trackedFields; - - public TrackingData(IForgeRegistry registry) { - this.registryId = registry.getRegistryName(); - this.registry = registry; - this.staticFields = new ArrayList<>(); - this.instanceFields = new ArrayList<>(); - this.actions = new ArrayList<>(); - this.trackedFields = new HashSet<>(); - } - - public synchronized void addStatic(ResourceLocation id, Field field) { - if (!Modifier.isStatic(field.getModifiers())) { - throw new IllegalStateException("Can't track registry element field: Must be static: " + field); - } else { - TrackedFieldKey key = TrackedFieldKey.create(field, null); - if (!this.trackedFields.contains(key)) { - this.staticFields.add(new TrackedStaticField(id, field)); - this.trackedFields.add(key); - } - } - } - - public synchronized void addInstance(ResourceLocation id, Field field, Object instance) { - if (Modifier.isStatic(field.getModifiers())) { - throw new IllegalStateException("Can't track registry instance field: Must not be static: " + field); - } else if (!field.getDeclaringClass().isAssignableFrom(instance.getClass())) { - throw new IllegalStateException("Can't track registry instance field: Instance object is of type " + instance.getClass() + ", expected " + field.getDeclaringClass() + "."); - } else { - TrackedFieldKey key = TrackedFieldKey.create(field, instance); - if (!this.trackedFields.contains(key)) { - this.instanceFields.add(new TrackedInstanceField(id, field, new WeakReference<>(instance))); - this.trackedFields.add(key); - } - } - } - - public synchronized void addAction(ResourceLocation id, Object instance, Consumer action) { - this.actions.add(new TrackedInstanceAction<>(id, new WeakReference<>(instance), action)); - } - - public synchronized void apply(Predicate changed, @Nullable Predicate instanceChanged, Consumer enqueue, Consumer valueUpdate) { - if (changed.test(this.registryId)) { - if (instanceChanged == null) { - for (TrackedStaticField field : this.staticFields) { - this.updateFrom(field.id(), field.field(), null, enqueue, valueUpdate); - } - } - - { - Iterator itr = this.instanceFields.iterator(); - while (itr.hasNext()) { - TrackedInstanceField field = itr.next(); - Object instance = field.instance().get(); - if (instance == null) { - itr.remove(); // Object has been cleared by garbage collector, don't track field any longer. - } else if (instanceChanged == null || instanceChanged.test(instance)) { - this.updateFrom(field.id(), field.field(), instance, enqueue, valueUpdate); - } - } - } - - { - Iterator> itr = this.actions.iterator(); - while (itr.hasNext()) { - TrackedInstanceAction action = itr.next(); - Object instance = action.instance().get(); - if (instance == null) { - itr.remove(); // Object has been cleared by garbage collector, don't track action any longer. - } else { - T value = this.registry.getValue(action.id()); - if (value == null) { - throw new IllegalStateException("Tracked registry object not present for action: " + this.registryId + " / " + action.id() + "."); - } else if (instanceChanged == null || instanceChanged.test(instance)) { - action.action().accept(value); - } - } - } - } - } - } - - @Override - public int hashCode() { - return this.registryId.hashCode(); - } - - private void updateFrom(ResourceLocation id, Field field, Object instance, Consumer enqueue, Consumer valueUpdate) { - try { - field.setAccessible(true); - //noinspection unchecked - T oldValue = (T) field.get(instance); - T value = this.registry.getValue(id); - if (value == null) { - throw new IllegalStateException("Tracked registry object not present: " + this.registryId + " / " + id + ", was " + oldValue + " before."); - } else if (!field.getType().isAssignableFrom(value.getClass())) { - throw new IllegalStateException("Tracked registry object has invalid type: " + this.registryId + " / " + id + ", was " + oldValue + " before. Probably a failed registry replacement. Expected: " + field.getType()); - } else if (value != oldValue) { - if (Modifier.isFinal(field.getModifiers())) { - try { - ReflectionHacks.setFinalField(field, instance, value); - } catch (Exception e) { - throw new ReflectiveOperationException("Failed to set final tracked registry field " + field, e); - } - } else { - field.setAccessible(true); - field.set(instance, value); - } - // A field was updated. It's instance fields need updating now as well. - // First add it to the tracker as well. - // Can't be done immediately or it would deadlock - // Submit it to be done before the next round - enqueue.accept(() -> { - Optional modInternal = ModInternal.get(id.getNamespace()); - if (modInternal.isPresent() && modInternal.get().instance() instanceof ModXRegistration mod) { - RegistrationContext ctx = new RegistrationContext(mod, id, ResourceKey.create(this.registry.getRegistryKey(), id)); - try { - if (value instanceof Registerable registerable) { - registerable.initTracking(ctx, new TrackingInstance(id, value)); - } - } catch (ReflectiveOperationException e) { - LibX.logger.error("Failed to update instance tracking for " + value + " (" + id + "/" + this.registry.getRegistryName() + ")", e); - } - } - }); - valueUpdate.accept(value); - } - } catch (ReflectiveOperationException e) { - LibX.logger.error("Failed to update registry object: " + this.registryId + " / " + id, e); - } - } - - private record TrackedStaticField(ResourceLocation id, Field field) {} - private record TrackedInstanceField(ResourceLocation id, Field field, WeakReference instance) {} - private record TrackedInstanceAction(ResourceLocation id, WeakReference instance, Consumer action) {} - - // Provide key with weak reference that allows hashing on fields and their instance - private record TrackedFieldKey(Field field, @Nullable WeakReference instance, int instanceHash) { - - public static TrackedFieldKey create(Field field, @Nullable Object instance) { - return new TrackedFieldKey(field, instance == null ? null : new WeakReference<>(instance), System.identityHashCode(instance)); - } - - @Override - public int hashCode() { - return this.instanceHash ^ this.field.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TrackedFieldKey key)) return false; - if (!Objects.equals(this.field(), key.field())) return false; - if (this.instance() == null && key.instance() == null) return true; - if (this.instance() == null || key.instance() == null) return false; - Object instance = this.instance().get(); - return instance != null && key.instance().refersTo(instance); - } - } -} diff --git a/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingInstance.java b/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingInstance.java deleted file mode 100644 index c7c9d820..00000000 --- a/src/main/java/org/moddingx/libx/impl/registration/tracking/TrackingInstance.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.moddingx.libx.impl.registration.tracking; - -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.registries.IForgeRegistry; -import org.moddingx.libx.registration.Registerable; -import org.moddingx.libx.registration.tracking.RegistryTracker; - -import java.lang.reflect.Field; -import java.util.function.Consumer; - -public class TrackingInstance implements Registerable.TrackingCollector { - - private final ResourceLocation baseId; - private final Object instance; - - public TrackingInstance(ResourceLocation baseId, Object instance) { - this.baseId = baseId; - this.instance = instance; - } - - @Override - public void track(IForgeRegistry registry, Field field) { - RegistryTracker.track(registry, field, this.instance, this.baseId); - } - - @Override - public void trackNamed(IForgeRegistry registry, String name, Field field) { - RegistryTracker.track(registry, field, this.instance, new ResourceLocation(this.baseId.getNamespace(), this.baseId.getPath() + "_" + name)); - } - - @Override - public void run(IForgeRegistry registry, Consumer action) { - RegistryTracker.run(registry, action, this.instance, this.baseId); - } - - @Override - public void runNamed(IForgeRegistry registry, String name, Consumer action) { - RegistryTracker.run(registry, action, this.instance, new ResourceLocation(this.baseId.getNamespace(), this.baseId.getPath() + "_" + name)); - } -} diff --git a/src/main/java/org/moddingx/libx/impl/render/BlockOverlayQuadCache.java b/src/main/java/org/moddingx/libx/impl/render/BlockOverlayQuadCache.java index 6d8ef79d..8766f15d 100644 --- a/src/main/java/org/moddingx/libx/impl/render/BlockOverlayQuadCache.java +++ b/src/main/java/org/moddingx/libx/impl/render/BlockOverlayQuadCache.java @@ -5,7 +5,7 @@ import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.SimplePreparableReloadListener; import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; +import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/org/moddingx/libx/impl/render/JobRenderer.java b/src/main/java/org/moddingx/libx/impl/render/JobRenderer.java index f819fd18..24dc962a 100644 --- a/src/main/java/org/moddingx/libx/impl/render/JobRenderer.java +++ b/src/main/java/org/moddingx/libx/impl/render/JobRenderer.java @@ -13,6 +13,7 @@ import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.world.phys.Vec2; import org.joml.Matrix4f; +import org.joml.Matrix4fStack; import org.joml.Vector3f; import org.joml.Vector4f; import org.lwjgl.opengl.GL11; @@ -55,10 +56,10 @@ public static NativeImage renderJob(RenderJob job) { RenderSystem.viewport(0, 0, width, height); - PoseStack modelViewStack = RenderSystem.getModelViewStack(); - modelViewStack.pushPose(); - modelViewStack.setIdentity(); - modelViewStack.mulPoseMatrix(job.setupModelViewMatrix()); + Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); + modelViewStack.pushMatrix(); + modelViewStack.identity(); + modelViewStack.mul(job.setupModelViewMatrix()); RenderSystem.applyModelViewMatrix(); Matrix4f projectionMatrix = job.setupProjectionMatrix(); @@ -69,14 +70,14 @@ public static NativeImage renderJob(RenderJob job) { RenderHelper.resetColor(); @Nullable - Matrix4f transformationMatrix = overlay ? new Matrix4f(modelViewStack.last().pose()) : null; + Matrix4f transformationMatrix = overlay ? new Matrix4f(modelViewStack) : null; PoseStack poseStack = new PoseStack(); job.setupTransformation(poseStack); if (overlay) { transformationMatrix.mul(poseStack.last().pose()); } - RenderBuffers buffers = new RenderBuffers(); + RenderBuffers buffers = new RenderBuffers(Runtime.getRuntime().availableProcessors()); job.render(poseStack, buffers.bufferSource()); buffers.bufferSource().endBatch(); @@ -87,8 +88,8 @@ public static NativeImage renderJob(RenderJob job) { resetDepthState(); RenderSystem.viewport(0, 0, width, height); - modelViewStack.setIdentity(); - modelViewStack.mulPoseMatrix(new Matrix4f().translate(0, 0, 1000 - GuiGraphics.MIN_GUI_Z)); + modelViewStack.identity(); + modelViewStack.mul(new Matrix4f().translate(0, 0, 1000 - GuiGraphics.MIN_GUI_Z)); RenderSystem.applyModelViewMatrix(); RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, width, height, 0, 1000, 1000 + GuiGraphics.MAX_GUI_Z - GuiGraphics.MIN_GUI_Z), VertexSorting.ORTHOGRAPHIC_Z); @@ -102,7 +103,7 @@ public static NativeImage renderJob(RenderJob job) { } resetDepthState(); - modelViewStack.popPose(); + modelViewStack.popMatrix(); RenderSystem.applyModelViewMatrix(); NativeImage img = takeNonOpaqueScreenshot(target); diff --git a/src/main/java/org/moddingx/libx/impl/sandbox/EmptySurfaceRule.java b/src/main/java/org/moddingx/libx/impl/sandbox/EmptySurfaceRule.java index 91b62180..55122128 100644 --- a/src/main/java/org/moddingx/libx/impl/sandbox/EmptySurfaceRule.java +++ b/src/main/java/org/moddingx/libx/impl/sandbox/EmptySurfaceRule.java @@ -1,6 +1,6 @@ package org.moddingx.libx.impl.sandbox; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import net.minecraft.util.KeyDispatchDataCodec; import net.minecraft.world.level.levelgen.SurfaceRules; @@ -9,7 +9,7 @@ public class EmptySurfaceRule implements SurfaceRules.RuleSource { public static final EmptySurfaceRule INSTANCE = new EmptySurfaceRule(); - public static final Codec CODEC = Codec.unit(INSTANCE); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); private EmptySurfaceRule() { @@ -27,4 +27,3 @@ public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) { return (x, y, z) -> null; } } - diff --git a/src/main/java/org/moddingx/libx/impl/sandbox/FakeHolder.java b/src/main/java/org/moddingx/libx/impl/sandbox/FakeHolder.java index b9dd4820..12ca88cb 100644 --- a/src/main/java/org/moddingx/libx/impl/sandbox/FakeHolder.java +++ b/src/main/java/org/moddingx/libx/impl/sandbox/FakeHolder.java @@ -25,7 +25,7 @@ public FakeHolder(Holder initial) { public void set(Holder value) { try { - value.get(); + value.value(); } catch (IllegalStateException e) { throw new IllegalArgumentException("Unbound holder: " + value, e); } @@ -63,6 +63,12 @@ public boolean is(@Nonnull TagKey key) { return false; } + @Override + @Deprecated + public boolean is(@Nonnull Holder holder) { + return false; + } + @Nonnull @Override public Stream> tags() { diff --git a/src/main/java/org/moddingx/libx/impl/sandbox/layer/NoiseLayerSelector.java b/src/main/java/org/moddingx/libx/impl/sandbox/layer/NoiseLayerSelector.java index e18efd0d..0b74e0d9 100644 --- a/src/main/java/org/moddingx/libx/impl/sandbox/layer/NoiseLayerSelector.java +++ b/src/main/java/org/moddingx/libx/impl/sandbox/layer/NoiseLayerSelector.java @@ -63,7 +63,7 @@ public DensityFunction apply(@Nonnull DensityFunction density) { @Override public DensityFunction.NoiseHolder visitNoise(@Nonnull DensityFunction.NoiseHolder noise) { long xor = noise.noiseData().unwrapKey().map(key -> (((long) key.location().getNamespace().hashCode()) << 32) | key.location().getPath().hashCode()).orElse(42L); - return new DensityFunction.NoiseHolder(noise.noiseData(), NormalNoise.create(RandomSource.create(seed ^ xor), noise.noiseData().get())); + return new DensityFunction.NoiseHolder(noise.noiseData(), NormalNoise.create(RandomSource.create(seed ^ xor), noise.noiseData().value())); } }); } diff --git a/src/main/java/org/moddingx/libx/impl/screen/text/SimpleLayout.java b/src/main/java/org/moddingx/libx/impl/screen/text/SimpleLayout.java index c9be0b3b..14a2a492 100644 --- a/src/main/java/org/moddingx/libx/impl/screen/text/SimpleLayout.java +++ b/src/main/java/org/moddingx/libx/impl/screen/text/SimpleLayout.java @@ -3,8 +3,8 @@ import com.google.common.collect.ImmutableList; import net.minecraft.client.gui.Font; import net.minecraft.network.chat.Component; -import org.moddingx.libx.screen.text.entry.AlignedComponent; import org.moddingx.libx.screen.text.ComponentLayout; +import org.moddingx.libx.screen.text.entry.AlignedComponent; import org.moddingx.libx.screen.text.entry.TextScreenEntry; import javax.annotation.Nullable; diff --git a/src/main/java/org/moddingx/libx/inventory/BaseItemStackHandler.java b/src/main/java/org/moddingx/libx/inventory/BaseItemStackHandler.java index c7031b40..02afa29a 100644 --- a/src/main/java/org/moddingx/libx/inventory/BaseItemStackHandler.java +++ b/src/main/java/org/moddingx/libx/inventory/BaseItemStackHandler.java @@ -6,18 +6,11 @@ import net.minecraft.core.NonNullList; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; -import org.moddingx.libx.capability.ItemCapabilities; +import net.neoforged.neoforge.items.ItemStackHandler; +import org.moddingx.libx.impl.inventory.AdvancedItemHandlerHelper; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.function.BiPredicate; +import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.IntStream; @@ -92,6 +85,11 @@ protected void onLoad() { } } + @Override + public boolean hasSpaceFor(List stacks, int startInclusive, int endExclusive) { + return AdvancedItemHandlerHelper.hasSpaceFor(this, stacks, startInclusive, endExclusive, (slot, stack) -> !this.outputSlots.contains(slot) && this.isItemValid(slot, stack)); + } + /** * Gets a vanilla container that wraps around this item handler. */ @@ -109,32 +107,6 @@ public IAdvancedItemHandlerModifiable getUnrestricted() { return this.unrestricted; } - /** - * Creates a new {@link LazyOptional} for this inventory. - */ - public LazyOptional createCapability() { - return ItemCapabilities.create(this); - } - - /** - * Creates a new {@link LazyOptional} for this inventory but without slot validation. - * - * @see #getUnrestricted() - */ - public LazyOptional createUnrestrictedCapability() { - return ItemCapabilities.create(this::getUnrestricted); - } - - /** - * Creates a new {@link LazyOptional} for this inventory. - * - * @param extract A predicate on whether an item can be extracted through this {@link LazyOptional}. This gets passed the slot to extract from. - * @param insert A predicate on whether an item can be inserted through this {@link LazyOptional}. This gets passed the slot to insert to and the stack that should be inserted. - */ - public LazyOptional createCapability(@Nullable Predicate extract, @Nullable BiPredicate insert) { - return ItemCapabilities.create(this, extract, insert); - } - /** * Creates a new {@link Builder} for an item handler with the given size. */ @@ -168,20 +140,20 @@ public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate ItemStack current = BaseItemStackHandler.this.stacks.get(slot); int amount = BaseItemStackHandler.this.getStackLimit(slot, stack); if (!current.isEmpty()) { - if (!ItemHandlerHelper.canItemStacksStack(stack, current)) return stack; + if (!ItemStack.isSameItemSameComponents(stack, current)) return stack; amount -= current.getCount(); } if (amount <= 0) return stack; if (!simulate) { if (current.isEmpty()) { - BaseItemStackHandler.this.stacks.set(slot, ItemHandlerHelper.copyStackWithSize(stack, Math.min(stack.getCount(), amount))); + BaseItemStackHandler.this.stacks.set(slot, stack.copyWithCount(Math.min(stack.getCount(), amount))); } else { current.grow(Math.min(stack.getCount(), amount)); } BaseItemStackHandler.this.onContentsChanged(slot); } - return ItemHandlerHelper.copyStackWithSize(stack, Math.max(0, stack.getCount() - amount)); + return stack.copyWithCount(Math.max(0, stack.getCount() - amount)); } @Nonnull @@ -193,10 +165,10 @@ public ItemStack extractItem(int slot, int amount, boolean simulate) { if (current.isEmpty()) return ItemStack.EMPTY; int count = Math.min(current.getCount(), Math.min(amount, current.getMaxStackSize())); if (!simulate) { - BaseItemStackHandler.this.stacks.set(slot, ItemHandlerHelper.copyStackWithSize(current, Math.max(0, current.getCount() - count))); + BaseItemStackHandler.this.stacks.set(slot, current.copyWithCount(Math.max(0, current.getCount() - count))); BaseItemStackHandler.this.onContentsChanged(slot); } - return ItemHandlerHelper.copyStackWithSize(current, count); + return current.copyWithCount(count); } @Override diff --git a/src/main/java/org/moddingx/libx/inventory/FilterItemHandler.java b/src/main/java/org/moddingx/libx/inventory/FilterItemHandler.java new file mode 100644 index 00000000..7d246449 --- /dev/null +++ b/src/main/java/org/moddingx/libx/inventory/FilterItemHandler.java @@ -0,0 +1,67 @@ +package org.moddingx.libx.inventory; + +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +/** + * A simple wrapper around an {@link IItemHandler} that limits the possibility to insert or extract items. This is + * especially useful for {@link Capabilities.ItemHandler item handler capabilities}. + */ +public class FilterItemHandler implements IAdvancedItemHandler { + + private final IItemHandler handler; + private final Predicate extract; + private final BiPredicate insert; + + /** + * Creates a new {@link FilterItemHandler}. + * + * @param handler The {@link IItemHandler} this {@link FilterItemHandler} wraps around. + * @param extract A predicate that tests whether extraction should be allowed from the provided slot. + * @param insert A predicate that tests whether insertion of the provided item should be allowed into the provided slot. + */ + public FilterItemHandler(IItemHandler handler, @Nullable Predicate extract, @Nullable BiPredicate insert) { + this.handler = handler; + this.extract = extract == null ? slot -> true : extract; + this.insert = insert == null ? (slot, stack) -> true : insert; + } + + @Override + public int getSlots() { + return this.handler.getSlots(); + } + + @Nonnull + @Override + public ItemStack getStackInSlot(int slot) { + return this.handler.getStackInSlot(slot); + } + + @Nonnull + @Override + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + return this.insert.test(slot, stack) ? this.handler.insertItem(slot, stack, simulate) : stack; + } + + @Nonnull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return this.extract.test(slot) ? this.handler.extractItem(slot, amount, simulate) : ItemStack.EMPTY; + } + + @Override + public int getSlotLimit(int slot) { + return this.handler.getSlotLimit(slot); + } + + @Override + public boolean isItemValid(int slot, @Nonnull ItemStack stack) { + return this.insert.test(slot, stack) && this.handler.isItemValid(slot, stack); + } +} diff --git a/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandler.java b/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandler.java index 53d74134..78a0b100 100644 --- a/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandler.java +++ b/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandler.java @@ -1,13 +1,12 @@ package org.moddingx.libx.inventory; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.IItemHandlerModifiable; +import org.moddingx.libx.impl.inventory.AdvancedItemHandlerHelper; import javax.annotation.Nonnull; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Predicate; /** @@ -49,46 +48,7 @@ default boolean hasSpaceFor(List stacks) { * @param endExclusive The first slot to after the range of slots to test. */ default boolean hasSpaceFor(List stacks, int startInclusive, int endExclusive) { - if (stacks.isEmpty()) { - return true; - } else if (stacks.size() == 1) { - ItemStack remainder = stacks.get(0).copy(); - for (int slot = startInclusive; slot < endExclusive; slot++) { - remainder = this.insertItem(slot, remainder, true); - if (remainder.isEmpty()) return true; - } - return remainder.isEmpty(); - } else { - Map copies = new HashMap<>(); - for (ItemStack stack : stacks) { - if (!stack.isEmpty()) { - int amountLeft = stack.getCount(); - for (int slot = startInclusive; slot < endExclusive; slot++) { - if (this.isItemValid(slot, stack)) { - ItemStack content = copies.getOrDefault(slot, this.getStackInSlot(slot)); - if (content.isEmpty()) { - amountLeft = 0; - ItemStack modifiableStack = stack.copy(); - modifiableStack.setCount(amountLeft); - copies.put(slot, modifiableStack); - break; - } else if (ItemStack.isSameItemSameTags(stack, content)) { - int reduce = Math.max(0, Math.min(content.getMaxStackSize() - content.getCount(), amountLeft)); - amountLeft -= reduce; - ItemStack modifiableStack = copies.getOrDefault(slot, this.getStackInSlot(slot).copy()); - modifiableStack.grow(reduce); - copies.put(slot, modifiableStack); - if (amountLeft <= 0) break; - } - } - } - if (amountLeft > 0) { - return false; - } - } - } - return true; - } + return AdvancedItemHandlerHelper.hasSpaceFor(this, stacks, startInclusive, endExclusive, this::isItemValid); } /** @@ -114,7 +74,7 @@ default ItemStack extractItem(Predicate predicate, int amount, boolea } } } else { - if (ItemStack.isSameItemSameTags(extracted, content)) { + if (ItemStack.isSameItemSameComponents(extracted, content)) { extracted.grow(content.getCount()); if (!simulate) { this.extractItem(slot, amountToExtract, false); diff --git a/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandlerModifiable.java b/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandlerModifiable.java index 33cad228..5de8d96a 100644 --- a/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandlerModifiable.java +++ b/src/main/java/org/moddingx/libx/inventory/IAdvancedItemHandlerModifiable.java @@ -1,7 +1,7 @@ package org.moddingx.libx.inventory; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.IItemHandlerModifiable; import javax.annotation.Nonnull; import java.util.function.Predicate; diff --git a/src/main/java/org/moddingx/libx/inventory/StackItemHandler.java b/src/main/java/org/moddingx/libx/inventory/StackItemHandler.java new file mode 100644 index 00000000..10dea994 --- /dev/null +++ b/src/main/java/org/moddingx/libx/inventory/StackItemHandler.java @@ -0,0 +1,145 @@ +package org.moddingx.libx.inventory; + +import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.common.MutableDataComponentHolder; +import net.neoforged.neoforge.items.IItemHandlerModifiable; +import org.moddingx.libx.codec.MoreStreamCodecs; + +import javax.annotation.Nonnull; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * An {@link IItemHandlerModifiable} with a {@link MutableDataComponentHolder} as backend. + */ +public class StackItemHandler implements IAdvancedItemHandlerModifiable { + + public static final DataComponentType> INVENTORY_DATA = new DataComponentType.Builder>() + .persistent(NonNullList.codecOf(ItemStack.OPTIONAL_CODEC)) + .networkSynchronized(MoreStreamCodecs.listOf(ItemStack.OPTIONAL_STREAM_CODEC).map(NonNullList::copyOf, Function.identity())) + .build(); + + private final int size; + protected final MutableDataComponentHolder dataComponentHolder; + + public StackItemHandler(int size, MutableDataComponentHolder dataComponentHolder) { + this.size = size; + this.dataComponentHolder = dataComponentHolder; + } + + @Override + public int getSlots() { + return this.size; + } + + @Nonnull + @Override + public ItemStack getStackInSlot(int slot) { + this.validateSlotIndex(slot); + NonNullList stacks = this.getContents(); + if (slot < stacks.size()) return stacks.get(slot); + else return ItemStack.EMPTY; + } + + @Override + public void setStackInSlot(int slot, @Nonnull ItemStack stack) { + this.validateSlotIndex(slot); + NonNullList newStacks = this.copyContentsPossiblyEnlarged(this.getContents()); + newStacks.set(slot, stack.copy()); + this.dataComponentHolder.set(INVENTORY_DATA, newStacks); + } + + @Override + public void clear() { + this.clear(stack -> true); + } + + @Override + public int clear(Predicate predicate) { + NonNullList newStacks = this.copyContentsPossiblyEnlarged(this.getContents()); + int cleared = 0; + for (int i = 0; i < this.size; i ++) { + ItemStack stack = newStacks.get(i); + if (predicate.test(stack)) { + cleared += stack.getCount(); + newStacks.set(i, ItemStack.EMPTY); + } + } + this.dataComponentHolder.set(INVENTORY_DATA, newStacks); + return cleared; + } + + @Nonnull + @Override + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + this.validateSlotIndex(slot); + if (stack.isEmpty()) return ItemStack.EMPTY; + if (!this.isItemValid(slot, stack)) return stack; + + NonNullList oldStacks = this.getContents(); + ItemStack existing = slot < oldStacks.size() ? oldStacks.get(slot) : ItemStack.EMPTY; + int limit = Math.min(this.getSlotLimit(slot), stack.getMaxStackSize()); + + if (!existing.isEmpty()) { + if (!ItemStack.isSameItemSameComponents(stack, existing)) return stack; + limit -= existing.getCount(); + } + + int insertAmount = Math.min(stack.getCount(), limit); + if (insertAmount <= 0) return stack; + + ItemStack newStack = stack.copyWithCount(existing.getCount() + insertAmount); + ItemStack remainder = stack.copyWithCount(stack.getCount() - insertAmount); + + if (!simulate) this.setStackInSlot(slot, newStack); + return remainder; + } + + @Nonnull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + this.validateSlotIndex(slot); + + NonNullList oldStacks = this.getContents(); + ItemStack existing = slot < oldStacks.size() ? oldStacks.get(slot) : ItemStack.EMPTY; + if (existing.isEmpty()) return ItemStack.EMPTY; + int extractAmount = Math.min(existing.getCount(), amount); + + ItemStack extractStack = existing.copyWithCount(extractAmount); + ItemStack remainder = existing.copyWithCount(existing.getCount() - extractAmount); + + if (!simulate) this.setStackInSlot(slot, remainder); + return extractStack; + } + + @Override + public int getSlotLimit(int slot) { + return Item.DEFAULT_MAX_STACK_SIZE; + } + + @Override + public boolean isItemValid(int slot, @Nonnull ItemStack stack) { + return true; + } + + private NonNullList getContents() { + return this.dataComponentHolder.getOrDefault(INVENTORY_DATA, NonNullList.create()); + } + + private void validateSlotIndex(int slot) { + if (slot < 0 || slot >= this.size) { + throw new IllegalArgumentException("Slot " + slot + " not in valid range - [0," + this.size + ")"); + } + } + + private NonNullList copyContentsPossiblyEnlarged(NonNullList oldStacks) { + NonNullList newStacks = NonNullList.withSize(Math.max(this.size, oldStacks.size()), ItemStack.EMPTY); + for (int i = 0; i < oldStacks.size(); i++) { + newStacks.set(i, oldStacks.get(i).copy()); + } + return newStacks; + } +} diff --git a/src/main/java/org/moddingx/libx/inventory/VanillaWrapper.java b/src/main/java/org/moddingx/libx/inventory/VanillaWrapper.java index 2fed7016..216c23db 100644 --- a/src/main/java/org/moddingx/libx/inventory/VanillaWrapper.java +++ b/src/main/java/org/moddingx/libx/inventory/VanillaWrapper.java @@ -3,7 +3,7 @@ import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.IItemHandlerModifiable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/org/moddingx/libx/inventory/package-info.java b/src/main/java/org/moddingx/libx/inventory/package-info.java index b80d51fd..c8711bac 100644 --- a/src/main/java/org/moddingx/libx/inventory/package-info.java +++ b/src/main/java/org/moddingx/libx/inventory/package-info.java @@ -1,4 +1,4 @@ /** - * Contains classes to deal with {@link net.minecraftforge.items.IItemHandler item handlers} and vanilla {@link net.minecraft.world.Container containers}. + * Contains classes to deal with {@link net.neoforged.neoforge.items.IItemHandler item handlers} and vanilla {@link net.minecraft.world.Container containers}. */ -package org.moddingx.libx.inventory; \ No newline at end of file +package org.moddingx.libx.inventory; diff --git a/src/main/java/org/moddingx/libx/menu/BlockEntityMenu.java b/src/main/java/org/moddingx/libx/menu/BlockEntityMenu.java index 8e5c18fe..05270788 100644 --- a/src/main/java/org/moddingx/libx/menu/BlockEntityMenu.java +++ b/src/main/java/org/moddingx/libx/menu/BlockEntityMenu.java @@ -16,8 +16,8 @@ public class BlockEntityMenu extends BlockMenu { protected final T blockEntity; - public BlockEntityMenu(@Nullable MenuType> type, int windowId, Level level, BlockPos pos, Inventory playerContainer, Player player, int firstOutputSlot, int firstInventorySlot) { - super(type, windowId, level, pos, playerContainer, player, firstOutputSlot, firstInventorySlot); + public BlockEntityMenu(@Nullable MenuType> type, int windowId, Level level, BlockPos pos, Player player, Inventory inventory, int firstOutputSlot, int firstInventorySlot) { + super(type, windowId, level, pos, player, inventory, firstOutputSlot, firstInventorySlot); //noinspection unchecked this.blockEntity = (T) level.getBlockEntity(pos); } diff --git a/src/main/java/org/moddingx/libx/menu/BlockMenu.java b/src/main/java/org/moddingx/libx/menu/BlockMenu.java index 126fd274..8fa03c48 100644 --- a/src/main/java/org/moddingx/libx/menu/BlockMenu.java +++ b/src/main/java/org/moddingx/libx/menu/BlockMenu.java @@ -1,25 +1,14 @@ package org.moddingx.libx.menu; -import io.netty.buffer.Unpooled; import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.level.Level; -import net.minecraftforge.common.extensions.IForgeMenuType; -import net.minecraftforge.network.NetworkHooks; -import org.moddingx.libx.fi.Function5; -import org.moddingx.libx.fi.Function6; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.concurrent.atomic.AtomicReference; /** * A {@link DefaultMenu} for menus related to a block in the world. @@ -28,8 +17,8 @@ public class BlockMenu extends DefaultMenu { protected final BlockPos pos; - public BlockMenu(@Nullable MenuType type, int windowId, Level level, BlockPos pos, Inventory playerContainer, Player player, int firstOutputSlot, int firstInventorySlot) { - super(type, windowId, level, playerContainer, player, firstOutputSlot, firstInventorySlot); + public BlockMenu(@Nullable MenuType type, int windowId, Level level, BlockPos pos, Player player, Inventory inventory, int firstOutputSlot, int firstInventorySlot) { + super(type, windowId, level, player, inventory, firstOutputSlot, firstInventorySlot); this.pos = pos; } @@ -41,47 +30,4 @@ public boolean stillValid(@Nonnull Player player) { public BlockPos getPos() { return this.pos; } - - /** - * Creates a menu type for a {@link BlockMenu}. - * - * @param constructor A method reference to the menus' constructor. - */ - public static MenuType createMenuType(Function5 constructor) { - return IForgeMenuType.create((windowId, inv, data) -> constructor.apply(windowId, inv.player.level(), data.readBlockPos(), inv, inv.player)); - } - - /** - * Creates a menu type for a {@link BlockMenu}. - * - * @param constructor A method reference to the menus' constructor. - */ - public static MenuType createMenuType(Function6, Integer, Level, BlockPos, Inventory, Player, T> constructor) { - AtomicReference> typeRef = new AtomicReference<>(null); - MenuType type = IForgeMenuType.create((windowId, inv, data) -> constructor.apply(typeRef.get(), windowId, inv.player.level(), data.readBlockPos(), inv, inv.player)); - typeRef.set(type); - return type; - } - - /** - * Opens a {@link BlockMenu} for a player. - */ - public static void openMenu(ServerPlayer player, MenuType menu, Component title, BlockPos pos) { - MenuProvider containerProvider = new MenuProvider() { - - @Nonnull - @Override - public Component getDisplayName() { - return title; - } - - @Override - public AbstractContainerMenu createMenu(int containerId, @Nonnull Inventory inventory, @Nonnull Player player) { - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); - buffer.writeBlockPos(pos); - return menu.create(containerId, inventory, buffer); - } - }; - NetworkHooks.openScreen(player, containerProvider, pos); - } } diff --git a/src/main/java/org/moddingx/libx/menu/DefaultMenu.java b/src/main/java/org/moddingx/libx/menu/DefaultMenu.java index 14166a70..7cbfeb7f 100644 --- a/src/main/java/org/moddingx/libx/menu/DefaultMenu.java +++ b/src/main/java/org/moddingx/libx/menu/DefaultMenu.java @@ -37,7 +37,7 @@ public abstract class DefaultMenu extends MenuBase { public final int firstOutputSlot; public final int firstInventorySlot; - protected DefaultMenu(@Nullable MenuType type, int windowId, Level level, Inventory inventory, Player player, int firstOutputSlot, int firstInventorySlot) { + protected DefaultMenu(@Nullable MenuType type, int windowId, Level level, Player player, Inventory inventory, int firstOutputSlot, int firstInventorySlot) { super(type, windowId, inventory); this.player = player; this.level = level; diff --git a/src/main/java/org/moddingx/libx/menu/EntityMenu.java b/src/main/java/org/moddingx/libx/menu/EntityMenu.java index c5bbe786..9352b2e8 100644 --- a/src/main/java/org/moddingx/libx/menu/EntityMenu.java +++ b/src/main/java/org/moddingx/libx/menu/EntityMenu.java @@ -1,25 +1,14 @@ package org.moddingx.libx.menu; -import com.mojang.datafixers.util.Function5; -import io.netty.buffer.Unpooled; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.level.Level; -import net.minecraftforge.common.extensions.IForgeMenuType; -import net.minecraftforge.network.NetworkHooks; -import org.moddingx.libx.fi.Function6; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.concurrent.atomic.AtomicReference; /** * A {@link DefaultMenu} for entities. @@ -28,8 +17,8 @@ public abstract class EntityMenu extends DefaultMenu { public final T entity; - public EntityMenu(@Nullable MenuType type, int windowId, Level level, int entityId, Inventory playerContainer, Player player, int firstOutputSlot, int firstInventorySlot) { - super(type, windowId, level, playerContainer, player, firstOutputSlot, firstInventorySlot); + public EntityMenu(@Nullable MenuType type, int windowId, Level level, int entityId, Player player, Inventory inventory, int firstOutputSlot, int firstInventorySlot) { + super(type, windowId, level, player, inventory, firstOutputSlot, firstInventorySlot); //noinspection unchecked this.entity = (T) level.getEntity(entityId); } @@ -42,47 +31,4 @@ public boolean stillValid(@Nonnull Player player) { public T getEntity() { return this.entity; } - - /** - * Creates a container type for an {@link EntityMenu}. - * - * @param constructor A method reference to the menus' constructor. - */ - public static MenuType createMenuType(Function5 constructor) { - return IForgeMenuType.create((windowId1, inv, data) -> constructor.apply(windowId1, inv.player.level(), data.readInt(), inv, inv.player)); - } - - /** - * Creates a menu type for an {@link EntityMenu}. - * - * @param constructor A method reference to the menus' constructor. - */ - public static MenuType createMenuType(Function6, Integer, Level, Integer, Inventory, Player, T> constructor) { - AtomicReference> typeRef = new AtomicReference<>(null); - MenuType type = IForgeMenuType.create((windowId, inv, data) -> constructor.apply(typeRef.get(), windowId, inv.player.level(), data.readInt(), inv, inv.player)); - typeRef.set(type); - return type; - } - - /** - * Opens an {@link EntityMenu} for a player. - */ - public static void openMenu(ServerPlayer player, MenuType> menu, Component title, Entity entity) { - MenuProvider containerProvider = new MenuProvider() { - - @Nonnull - @Override - public Component getDisplayName() { - return title; - } - - @Override - public AbstractContainerMenu createMenu(int containerId, @Nonnull Inventory inventory, @Nonnull Player player) { - FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); - buffer.writeInt(entity.getId()); - return menu.create(containerId, inventory, buffer); - } - }; - NetworkHooks.openScreen(player, containerProvider, buffer -> buffer.writeInt(entity.getId())); - } } diff --git a/src/main/java/org/moddingx/libx/menu/GenericMenu.java b/src/main/java/org/moddingx/libx/menu/GenericMenu.java deleted file mode 100644 index b31cf55a..00000000 --- a/src/main/java/org/moddingx/libx/menu/GenericMenu.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.moddingx.libx.menu; - -import com.google.common.collect.ImmutableList; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.extensions.IForgeMenuType; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; -import net.minecraftforge.network.NetworkHooks; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.moddingx.libx.LibX; -import org.moddingx.libx.impl.menu.GenericContainerSlotValidationWrapper; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiPredicate; - -/** - * A common {@link AbstractContainerMenu menu} with a variable amount of slots. You should not use this with - * more than 154 slots. - * - * To show a menu to a {@link Player player}, call - * {@link #open(ServerPlayer, IItemHandlerModifiable, Component, ResourceLocation) open} on the logical server. - * - * As there's no way to synchronise the item validator method from the {@link IItemHandlerModifiable modifiable item handler}, - * you should register the validator during setup. The slot validation method in your item handler will be ignored by this. - */ -public class GenericMenu extends MenuBase { - - private static final ResourceLocation EMPTY_VALIDATOR = LibX.getInstance().resource("nothing"); - private static final Map> validators = new HashMap<>(Map.of( - EMPTY_VALIDATOR, (slot, stack) -> true - )); - - public static final MenuType TYPE = IForgeMenuType.create((id, playerInv, buffer) -> { - int size = buffer.readVarInt(); - ResourceLocation validatorId = buffer.readResourceLocation(); - BiPredicate validator; - if (validators.containsKey(validatorId)) { - validator = validators.get(validatorId); - } else { - LibX.logger.warn("Received invalid validator for generic container. Validator: " + validatorId); - validator = validators.get(EMPTY_VALIDATOR); - } - int[] slotLimits = new int[size]; - for (int i = 0; i < size; i++) { - slotLimits[i] = buffer.readVarInt(); - } - IItemHandlerModifiable handler = new GenericContainerSlotValidationWrapper(new ItemStackHandler(size), validator, slotLimits); - return new GenericMenu(id, handler, playerInv); - }); - - public final int width; - public final int height; - public final int invX; - public final int invY; - public final List> slotList; - - private GenericMenu(int id, IItemHandlerModifiable handler, Inventory playerContainer) { - super(TYPE, id, playerContainer); - Triple, Pair, List>> layout = layoutSlots(handler.getSlots()); - this.width = layout.getLeft().getLeft(); - this.height = layout.getLeft().getRight(); - this.invX = layout.getMiddle().getLeft(); - this.invY = layout.getMiddle().getRight(); - this.slotList = layout.getRight(); - for (int i = 0; i < this.slotList.size(); i++) { - this.addSlot(new SlotItemHandler(handler, i, this.slotList.get(i).getLeft(), this.slotList.get(i).getRight())); - } - this.layoutPlayerInventorySlots(layout.getMiddle().getLeft(), layout.getMiddle().getRight()); - } - - @Override - public boolean stillValid(@Nonnull Player player) { - return true; - } - - @Nonnull - @Override - public ItemStack quickMoveStack(@Nonnull Player player, int index) { - ItemStack itemstack = ItemStack.EMPTY; - Slot slot = this.slots.get(index); - if (slot.hasItem()) { - ItemStack stack = slot.getItem(); - itemstack = stack.copy(); - - final int inventorySize = this.slotList.size(); - final int playerInventoryEnd = inventorySize + 27; - final int playerHotBarEnd = playerInventoryEnd + 9; - - if (index >= inventorySize) { - if (!this.moveItemStackTo(stack, 0, inventorySize, false)) { - return ItemStack.EMPTY; - } else if (index < playerInventoryEnd) { - if (!this.moveItemStackTo(stack, playerInventoryEnd, playerHotBarEnd, false)) { - return ItemStack.EMPTY; - } - } else if (index < playerHotBarEnd && !this.moveItemStackTo(stack, inventorySize, playerInventoryEnd, false)) { - return ItemStack.EMPTY; - } - } else if (!this.moveItemStackTo(stack, inventorySize, playerHotBarEnd, false)) { - return ItemStack.EMPTY; - } - if (stack.isEmpty()) { - slot.set(ItemStack.EMPTY); - } else { - slot.setChanged(); - } - if (stack.getCount() == itemstack.getCount()) { - return ItemStack.EMPTY; - } - slot.onTake(player, stack); - } - return itemstack; - } - - /** - * Opens a menu for a {@link Player player}. - * - * @param player The player that should see the menu. - * @param inventory The inventory of the menu. The slot amount of this determines how big the container is. - * This should not have more than 154 slots. - * @param name The name of the menu. - * @param validatorId The id of the slot validator registered with {@link #registerSlotValidator(ResourceLocation, BiPredicate) registerSlotValidator}. - * {@code null} disables slot validation. This will override the item handlers slot validation, so null - * means no slot validation even if the item handler has that feature. - */ - public static void open(ServerPlayer player, IItemHandlerModifiable inventory, Component name, @Nullable ResourceLocation validatorId) { - MenuProvider provider = new MenuProvider() { - - @Nonnull - @Override - public Component getDisplayName() { - return name; - } - - @Override - public AbstractContainerMenu createMenu(int containerId, @Nonnull Inventory inv, @Nonnull Player player) { - BiPredicate validator; - if (validators.containsKey(validatorId == null ? EMPTY_VALIDATOR : validatorId)) { - validator = validators.get(validatorId); - } else { - LibX.logger.warn("Generic container created with invalid validator. Validator ID: " + validatorId); - validator = validators.get(EMPTY_VALIDATOR); - } - return new GenericMenu(containerId, new GenericContainerSlotValidationWrapper(inventory, validator, null), inv); - } - }; - NetworkHooks.openScreen(player, provider, buffer -> { - buffer.writeVarInt(inventory.getSlots()); - buffer.writeResourceLocation(validatorId == null ? EMPTY_VALIDATOR : validatorId); - for (int i = 0; i < inventory.getSlots(); i++) { - buffer.writeVarInt(inventory.getSlotLimit(i)); - } - }); - } - - /** - * Registers a slot validator. This is required as the item handler can not be synced to the client, - * so the slot validation method of the item handler can not be used. This should be called during setup. - */ - public static void registerSlotValidator(ResourceLocation validatorId, BiPredicate validator) { - synchronized (validators) { - if (validators.containsKey(validatorId)) { - throw new IllegalStateException("Slot validator for generic container registered: " + validatorId); - } - validators.put(validatorId, validator); - } - } - - private static Triple, Pair, List>> layoutSlots(int size) { - // We try some special cases here for the best possible results. - // If nothing works we just put them in a rectangle - if (size < 9) { - return layoutRectangle(size, 1, size); - } else if (size % 9 == 0 && size <= 9 * 8) { - return layoutRectangle(9, size / 9, size); - } else if (size % 11 == 0 && size <= 11 * 8) { - return layoutRectangle(11, size / 11, size); - } else if (size % 12 == 0 && size <= 12 * 8) { - return layoutRectangle(12, size / 12, size); - } else if (size % 8 == 0 && size <= 8 * 8) { - return layoutRectangle(8, size / 8, size); - } else if (size % 13 == 0 && size <= 13 * 8) { - return layoutRectangle(13, size / 13, size); - } else if (size % 14 == 0 && size <= 14 * 8) { - return layoutRectangle(14, size / 14, size); - } else if (size <= 9 * 8) { - return layoutRectangle(9, size % 9 == 0 ? size / 9 : (size / 9) + 1, size); - } else if (size <= 11 * 8) { - return layoutRectangle(11, size % 11 == 0 ? size / 11 : (size / 11) + 1, size); - } else if (size <= 12 * 8) { - return layoutRectangle(12, size % 12 == 0 ? size / 12 : (size / 12) + 1, size); - } else if (size <= 13 * 8) { - return layoutRectangle(13, size % 13 == 0 ? size / 13 : (size / 13) + 1, size); - } else { - return layoutRectangle(14, size % 14 == 0 ? size / 14 : (size / 14) + 1, size); - } - } - - private static Triple, Pair, List>> layoutRectangle(int width, int height, int maxSize) { - int invX; - int paddingX; - if (width < 9) { - invX = 0; - paddingX = (9 - width) * 9; - } else { - invX = (width - 9) * 9; - paddingX = 0; - } - ImmutableList.Builder> builder = ImmutableList.builder(); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (((y * width) + x) < maxSize) - builder.add(Pair.of(7 + paddingX + (18 * x) + 1, 17 + (18 * y) + 1)); - } - } - return Triple.of( - Pair.of( - Math.max((2 * (7 + invX)) + (9 * 18), (2 * (7 + paddingX)) + (width * 18)), - 17 + (18 * height) + 14 + 83 - ), - Pair.of(7 + invX + 1, 17 + (height * 18) + 14 + 1), - builder.build() - ); - } -} diff --git a/src/main/java/org/moddingx/libx/menu/MenuBase.java b/src/main/java/org/moddingx/libx/menu/MenuBase.java index ecdf418b..7b048351 100644 --- a/src/main/java/org/moddingx/libx/menu/MenuBase.java +++ b/src/main/java/org/moddingx/libx/menu/MenuBase.java @@ -6,9 +6,9 @@ import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.SlotItemHandler; -import net.minecraftforge.items.wrapper.InvWrapper; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.SlotItemHandler; +import net.neoforged.neoforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -136,7 +136,7 @@ protected boolean moveItemStackTo(@Nonnull ItemStack stack, int startIndex, int Slot slot = this.slots.get(idx); ItemStack content = slot.getItem(); - if (!content.isEmpty() && ItemStack.isSameItemSameTags(stack, content) && slot.mayPlace(stack)) { + if (!content.isEmpty() && ItemStack.isSameItemSameComponents(stack, content) && slot.mayPlace(stack)) { int totalCount = content.getCount() + stack.getCount(); int maxSize = Math.min(slot.getMaxStackSize(), stack.getMaxStackSize()); if (totalCount <= maxSize) { diff --git a/src/main/java/org/moddingx/libx/menu/package-info.java b/src/main/java/org/moddingx/libx/menu/package-info.java index 8d655ed3..024f4606 100644 --- a/src/main/java/org/moddingx/libx/menu/package-info.java +++ b/src/main/java/org/moddingx/libx/menu/package-info.java @@ -1,4 +1,4 @@ /** * Contains several base classes for {@link net.minecraft.world.inventory.AbstractContainerMenu menus}. */ -package org.moddingx.libx.menu; \ No newline at end of file +package org.moddingx.libx.menu; diff --git a/src/main/java/org/moddingx/libx/menu/slot/BaseSlot.java b/src/main/java/org/moddingx/libx/menu/slot/BaseSlot.java index 3a975f74..e7b3ae91 100644 --- a/src/main/java/org/moddingx/libx/menu/slot/BaseSlot.java +++ b/src/main/java/org/moddingx/libx/menu/slot/BaseSlot.java @@ -1,8 +1,8 @@ package org.moddingx.libx.menu.slot; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.SlotItemHandler; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.SlotItemHandler; import org.moddingx.libx.inventory.BaseItemStackHandler; import javax.annotation.Nonnull; diff --git a/src/main/java/org/moddingx/libx/menu/slot/OutputSlot.java b/src/main/java/org/moddingx/libx/menu/slot/OutputSlot.java index f461f469..eddf3372 100644 --- a/src/main/java/org/moddingx/libx/menu/slot/OutputSlot.java +++ b/src/main/java/org/moddingx/libx/menu/slot/OutputSlot.java @@ -1,8 +1,8 @@ package org.moddingx.libx.menu.slot; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.SlotItemHandler; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.SlotItemHandler; import javax.annotation.Nonnull; diff --git a/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuFactory.java b/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuFactory.java new file mode 100644 index 00000000..a347cb6f --- /dev/null +++ b/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuFactory.java @@ -0,0 +1,21 @@ +package org.moddingx.libx.menu.type; + +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; + +/** + * A factory for {@link AbstractContainerMenu menus} that can take some kind of extra payload. + * + * @param The type of {@link AbstractContainerMenu menu} created by this factory. + * @param The type of the extra payload used to create menus. This can be {@link Void}. + */ +public interface AdvancedMenuFactory { + + /** + * Creates a new menu. This is called on both the logical server and the logical client. + */ + T createMenu(MenuType menuType, int windowId, Level level, S payload, Player player, Inventory inventory); +} diff --git a/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuType.java b/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuType.java new file mode 100644 index 00000000..37b5b101 --- /dev/null +++ b/src/main/java/org/moddingx/libx/menu/type/AdvancedMenuType.java @@ -0,0 +1,134 @@ +package org.moddingx.libx.menu.type; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.neoforged.neoforge.network.IContainerFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +/** + * A menu type for {@link AdvancedMenuFactory advanced men factories}. + */ +public class AdvancedMenuType extends MenuType { + + private final AdvancedMenuFactory factory; + @Nullable private final StreamCodec codec; + + private AdvancedMenuType(AtomicReference> menuTypeRef, AdvancedMenuFactory factory, @Nullable StreamCodec codec, FeatureFlagSet featureFlags) { + super(new Factory<>(menuTypeRef, factory, codec), featureFlags); + this.factory = factory; + this.codec = codec; + menuTypeRef.set(this); + } + + /** + * Opens a menu of this type to the provided player. + */ + public void open(ServerPlayer player, Component title, S payload) { + Provider provider = new Provider<>(this, title, this.factory, payload); + if (this.codec != null) { + player.openMenu(provider, buf -> this.codec.encode(buf, payload)); + } else { + player.openMenu(provider); + } + } + + /** + * Creates a new {@link AdvancedMenuType} using the provided {@link AdvancedMenuFactory factory}. + */ + public static AdvancedMenuType create(AdvancedMenuFactory factory) { + return create(factory, FeatureFlags.VANILLA_SET); + } + + /** + * Creates a new {@link AdvancedMenuType} using the provided {@link AdvancedMenuFactory factory}. + */ + public static AdvancedMenuType create(AdvancedMenuFactory factory, FeatureFlagSet featureFlags) { + AtomicReference> menuTypeRef = new AtomicReference<>(); + Objects.requireNonNull(factory); + return new AdvancedMenuType<>(menuTypeRef, factory, null, featureFlags); + } + + /** + * Creates a new {@link AdvancedMenuType} using the provided {@link AdvancedMenuFactory factory} and {@link StreamCodec}. + */ + public static AdvancedMenuType create(AdvancedMenuFactory factory, StreamCodec codec) { + return create(factory, codec, FeatureFlags.VANILLA_SET); + } + + /** + * Creates a new {@link AdvancedMenuType} using the provided {@link AdvancedMenuFactory factory} and {@link StreamCodec}. + */ + public static AdvancedMenuType create(AdvancedMenuFactory factory, StreamCodec codec, FeatureFlagSet featureFlags) { + AtomicReference> menuTypeRef = new AtomicReference<>(); + Objects.requireNonNull(factory); + Objects.requireNonNull(codec); + return new AdvancedMenuType<>(menuTypeRef, factory, codec, featureFlags); + } + + private static class Factory implements IContainerFactory { + + private final AtomicReference> menuType; + private final AdvancedMenuFactory factory; + @Nullable private final StreamCodec codec; + + private Factory(AtomicReference> menuType, AdvancedMenuFactory factory, @Nullable StreamCodec codec) { + this.menuType = menuType; + this.factory = factory; + this.codec = codec; + } + + @Nonnull + @Override + public T create(int windowId, @Nonnull Inventory inventory, @Nullable RegistryFriendlyByteBuf data) { + MenuType menuType = Objects.requireNonNull(this.menuType.get()); + if (this.codec != null && data == null) { + @Nullable ResourceLocation id = BuiltInRegistries.MENU.getKey(menuType); + throw new IllegalStateException("Can't open menus of type " + id + " without extra payload."); + } + S payload = this.codec == null ? null : this.codec.decode(data); + return this.factory.createMenu(menuType, windowId, inventory.player.level(), payload, inventory.player, inventory); + } + } + + private static class Provider implements MenuProvider { + + private final MenuType menuType; + private final Component title; + private final AdvancedMenuFactory factory; + private final S payload; + + private Provider(MenuType menuType, Component title, AdvancedMenuFactory factory, S payload) { + this.menuType = menuType; + this.title = title; + this.factory = factory; + this.payload = payload; + } + + @Nonnull + @Override + public Component getDisplayName() { + return this.title; + } + + @Nullable + @Override + public AbstractContainerMenu createMenu(int windowId, @Nonnull Inventory inventory, @Nonnull Player player) { + return this.factory.createMenu(this.menuType, windowId, player.level(), this.payload, player, inventory); + } + } +} diff --git a/src/main/java/org/moddingx/libx/mod/ModX.java b/src/main/java/org/moddingx/libx/mod/ModX.java index 99a97b56..8d0e13ae 100644 --- a/src/main/java/org/moddingx/libx/mod/ModX.java +++ b/src/main/java/org/moddingx/libx/mod/ModX.java @@ -1,11 +1,9 @@ package org.moddingx.libx.mod; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import org.moddingx.libx.impl.ModInternal; import org.moddingx.libx.impl.config.ModMappers; @@ -32,14 +30,14 @@ protected ModX() { if (mod == null) throw new IllegalStateException("Mod class has no @Mod annotation."); this.modid = mod.value(); - ModInternal.init(this, FMLJavaModLoadingContext.get()); + ModInternal modInternal = ModInternal.init(this); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientSetup); + modInternal.modEventBus().addListener(this::setup); + modInternal.modEventBus().addListener(this::clientSetup); // Initialise config system for this mod container // Required, so the extension point can be added when required - ModMappers.get(this.modid).initAdapter(ModLoadingContext.get()); + ModMappers.get(this.modid).initAdapter(modInternal.modContainer()); // As the generated code registers registration handlers this will produce a null pointer exception // as the list of handlers will be null. So for instances of ModXRegistration we don't call it here @@ -64,6 +62,6 @@ protected ModX() { * path is the given string. */ public final ResourceLocation resource(String path) { - return new ResourceLocation(this.modid, path); + return ResourceLocation.fromNamespaceAndPath(this.modid, path); } } diff --git a/src/main/java/org/moddingx/libx/mod/ModXRegistration.java b/src/main/java/org/moddingx/libx/mod/ModXRegistration.java index 44fd0054..586787e2 100644 --- a/src/main/java/org/moddingx/libx/mod/ModXRegistration.java +++ b/src/main/java/org/moddingx/libx/mod/ModXRegistration.java @@ -6,7 +6,6 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.moddingx.libx.base.tile.BlockBE; import org.moddingx.libx.impl.ModInternal; import org.moddingx.libx.impl.registration.RegistrationDispatcher; @@ -27,7 +26,7 @@ * registration method with a method reference to it. (Example: {@code addRegistrationHandler(ModItems::init)}. * The handlers will get called in the order you added them. * - * This system has several advantages over the one recommended by forge: + * This system has several advantages over the one recommended by neoforge: * *
      *
    • An object can have dependencies that are automatically registered with it. This is done with @@ -53,14 +52,12 @@ protected ModXRegistration() { RegistrationBuilder builder = new RegistrationBuilder(); this.initRegistration(builder); this.dispatcher = new RegistrationDispatcher(this, builder.build()); - ModInternal.get(this).initRegistration(this.dispatcher); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this.dispatcher::registerBy); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this.dispatcher::registerCommon); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this.dispatcher::registerClient); + ModInternal modInternal = ModInternal.get(this); + this.dispatcher.setupEventListeners(modInternal.modEventBus()); // Call the generated code here as well - ModInternal.get(this).callGeneratedCode(); + modInternal.callGeneratedCode(); } /** diff --git a/src/main/java/org/moddingx/libx/network/EnumDataSerializer.java b/src/main/java/org/moddingx/libx/network/EnumDataSerializer.java index 6533644d..e3404d03 100644 --- a/src/main/java/org/moddingx/libx/network/EnumDataSerializer.java +++ b/src/main/java/org/moddingx/libx/network/EnumDataSerializer.java @@ -1,7 +1,9 @@ package org.moddingx.libx.network; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.syncher.EntityDataSerializer; +import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs; import javax.annotation.Nonnull; @@ -9,22 +11,17 @@ * {@link EntityDataSerializer Data serializers} for enums. It needs to be registered in order to be used. */ public class EnumDataSerializer> implements EntityDataSerializer { - - private final Class enumClass; - public EnumDataSerializer(Class enumClass) { - this.enumClass = enumClass; - } + private final StreamCodec codec; - @Override - public void write(@Nonnull FriendlyByteBuf buffer, @Nonnull T value) { - buffer.writeEnum(value); + public EnumDataSerializer(Class enumClass) { + this.codec = NeoForgeStreamCodecs.enumCodec(enumClass); } @Nonnull @Override - public T read(@Nonnull FriendlyByteBuf buffer) { - return buffer.readEnum(this.enumClass); + public StreamCodec codec() { + return this.codec; } @Nonnull diff --git a/src/main/java/org/moddingx/libx/network/LoginPacketSerializer.java b/src/main/java/org/moddingx/libx/network/LoginPacketSerializer.java deleted file mode 100644 index 5e31ed9f..00000000 --- a/src/main/java/org/moddingx/libx/network/LoginPacketSerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.moddingx.libx.network; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.function.IntSupplier; - -/** - * An interface that extends the logic in {@link PacketSerializer} to support login packets. - */ -public interface LoginPacketSerializer extends PacketSerializer { - - /** - * Gets the login packet index from the packet. - */ - int getLoginIndex(T msg); - - /** - * Sets the login packet index to the packet. - */ - void setLoginIndex(T msg, int idx); - - /** - * Builds a list of login packets that are sent on login. The default implementation calls a {@code public} no-arg - * constructor on the message class and returns a {@link List} with exactly one packet. - */ - default List> buildLoginPackets(boolean isLocal) { - try { - return List.of(new LoginPacket<>(this.messageClass().getName(), this.messageClass().getConstructor().newInstance())); - } catch (NoSuchMethodException e) { - throw new IllegalStateException("No public no-arg constructor defined in " + this.messageClass() + ". Override LoginPacketSerializer#buildLoginPackets to create custom login packets.", e); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException("Failed to invoke public no-arg constructor defined in " + this.messageClass() + ".", e); - } - } - - /** - * Gets whether this login packet needs a response. The default implementation returns {@code true}. - */ - default boolean needsResponse() { - return true; - } - - /** - * A login packet. - * - * @param context Some unique key for the login packet. Used for logging. - * @param message The packet to send. - */ - record LoginPacket(String context, T message) {} -} diff --git a/src/main/java/org/moddingx/libx/network/NetworkX.java b/src/main/java/org/moddingx/libx/network/NetworkX.java index a0ded4d2..f09014f1 100644 --- a/src/main/java/org/moddingx/libx/network/NetworkX.java +++ b/src/main/java/org/moddingx/libx/network/NetworkX.java @@ -1,186 +1,141 @@ package org.moddingx.libx.network; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.NetworkEvent; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.simple.SimpleChannel; -import org.apache.commons.lang3.tuple.Pair; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.handling.IPayloadHandler; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import org.moddingx.libx.impl.ModInternal; import org.moddingx.libx.mod.ModX; -import java.lang.reflect.Modifier; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.IntSupplier; -import java.util.function.Supplier; /** - * A class implementing network logic. You should subclass it and create an instance in your - * mods' constructor. {@link NetworkX#registerPackets()} will then automatically be called - * during setup. You can register custom packets there. The order in which they are - * registered is important. + * A class implementing network logic. You can use the {@link #register(PacketHandler) register} methods + * in you constructor to register network packets. */ public abstract class NetworkX { - private static final Object LOCK = new Object(); + private final Object lock; + private final ModX mod; + private final String version; + @Nullable private HashSet usedIds; + private final List> packetTypes; - public final SimpleChannel channel; - private final Protocol protocol; - private int discriminator = 0; - protected NetworkX(ModX mod) { - this.protocol = this.getProtocol(); - this.channel = NetworkRegistry.newSimpleChannel( - mod.resource("netchannel"), - this.protocol::version, - remote -> this.protocol.client().predicate.test(this.protocol.version(), remote), - remote -> this.protocol.server().predicate.test(this.protocol.version(), remote) - ); - ModInternal.get(mod).addSetupTask(this::registerPackets, false); + this.lock = new Object(); + this.mod = mod; + this.version = this.getVersion(); + this.usedIds = new HashSet<>(); + this.packetTypes = new ArrayList<>(); + + ModInternal.get(this.mod).modEventBus().addListener(this::runRegistration); } /** - * Gets the {@link Protocol protocol} for this network. + * Gets the network version for this network. */ - protected abstract Protocol getProtocol(); + protected abstract String getVersion(); /** - * You can register your own packets here. The order is important. + * Registers a new packet handler to the system. This should be called in the constructor. */ - protected abstract void registerPackets(); + protected final void register(PacketHandler handler) { + this.doRegister(handler, false); + } - protected final void registerGame(NetworkDirection direction, PacketSerializer serializer, Supplier>> handler) { - validateMessage(direction, serializer, false); - BiConsumer> action = resolveHandler(direction, serializer, handler); - synchronized (LOCK) { - this.channel.registerMessage(this.discriminator++, serializer.messageClass(), serializer::encode, serializer::decode, action, Optional.of(direction)); - this.channel.messageBuilder(serializer.messageClass(), this.discriminator++, direction) - .encoder(serializer::encode) - .decoder(serializer::decode) - .consumerNetworkThread(action) - .noResponse() - .add(); - } + /** + * Registers a new optional packet handler to the system. An optional packet handler is not required to be present + * on the remote side for the connection negotiation to be successful. This should be called in the constructor. + */ + protected final void registerOptional(PacketHandler handler) { + this.doRegister(handler, true); } - protected final void registerLogin(NetworkDirection direction, LoginPacketSerializer serializer, Supplier>> handler) { - validateMessage(direction, serializer, true); - BiConsumer> action = resolveHandler(direction, serializer, handler); - synchronized (LOCK) { - SimpleChannel.MessageBuilder builder = this.channel.messageBuilder(serializer.messageClass(), this.discriminator++, direction) - .encoder(serializer::encode) - .decoder(serializer::decode) - .consumerNetworkThread(action) - .markAsLoginPacket() - .loginIndex(serializer::getLoginIndex, serializer::setLoginIndex) - .buildLoginPacketList((isLocal) -> { - List> packets = serializer.buildLoginPackets(isLocal); - return packets.stream().map(p -> Pair.of(p.context(), p.message())).toList(); - }); - if (!serializer.needsResponse()) { - builder.noResponse(); + private void doRegister(PacketHandler handler, boolean optional) { + synchronized (this.lock) { + CustomPacketPayload.Type type = handler.type(); + if (!Objects.equals(this.mod.modid, type.id().getNamespace())) { + throw new IllegalArgumentException("Invalid packet namespace " + type.id().getNamespace() + ", expected " + this.mod.modid); + } else if (this.usedIds == null) { + throw new IllegalStateException("Network packet handler registered too late."); + } else if (this.usedIds.add(type.id().getPath())) { + this.packetTypes.add(new PacketType<>(type, handler, optional)); + } else { + throw new IllegalStateException("Duplicate packet id: " + type.id()); } - builder.add(); } } - private static void validateMessage(NetworkDirection direction, PacketSerializer serializer, boolean login) { - Objects.requireNonNull(direction, "No network direction"); - - if (login) { - if (direction == NetworkDirection.PLAY_TO_CLIENT || direction == NetworkDirection.PLAY_TO_SERVER) { - throw new IllegalArgumentException("Use registerGame to register game packets."); + private void runRegistration(RegisterPayloadHandlersEvent event) { + synchronized (this.lock) { + for (PacketType packetType : this.packetTypes) { + this.registerHandler(event, packetType); } - } else { - if (direction == NetworkDirection.LOGIN_TO_CLIENT || direction == NetworkDirection.LOGIN_TO_SERVER) { - throw new IllegalArgumentException("Use registerLogin to register login packets."); - } - } - - if (!Modifier.isFinal(serializer.messageClass().getModifiers())) { - throw new IllegalArgumentException("Non-final message class"); + this.usedIds = null; } } - - @SuppressWarnings("EqualsBetweenInconvertibleTypes") - private static BiConsumer> resolveHandler(NetworkDirection direction, PacketSerializer serializer, Supplier>> supplier) { - PacketHandler handler; - if (direction.getReceptionSide() == LogicalSide.CLIENT) { - handler = DistExecutor.unsafeRunForDist(supplier, () -> () -> null); - } else { - handler = supplier.get().get(); - } - if (handler == null) { - return (msg, ctx) -> {}; - } else if (handler.getClass() == serializer.getClass()) { - throw new IllegalStateException("The packet handler must be a different class than the packet serializer."); - } else { - return switch (handler.target()) { - case MAIN_THREAD -> (msg, ctx) -> { - ctx.get().enqueueWork(() -> handler.handle(msg, ctx)); - ctx.get().setPacketHandled(true); - }; - case NETWORK_THREAD -> (msg, ctx) -> { - boolean handled = handler.handle(msg, ctx); - ctx.get().setPacketHandled(handled); - }; + + private void registerHandler(RegisterPayloadHandlersEvent event, PacketType packetType) { + synchronized (this.lock) { + PayloadRegistrar registrar = event.registrar(this.version).executesOn(packetType.handler().target()); + if (packetType.optional()) registrar = registrar.optional(); + Void ignored = switch (packetType.handler().direction()) { + case CLIENTBOUND -> { + registrar.playToClient(packetType.type(), packetType.handler().codec(), new WrappedHandler<>(packetType.handler())); + yield null; + } + case SERVERBOUND -> { + registrar.playToServer(packetType.type(), packetType.handler().codec(), new WrappedHandler<>(packetType.handler())); + yield null; + } }; } } - + /** - * A protocol defines when a connection is accepted or rejected. - * - * @param version The protocol version. This must be equal on client and server - * @param client The behaviour for the client - * @param server The behaviour for the dedicated server + * Checks whether a packet of a given type can currently be sent. On the physical client this checks that the + * current connection supports the given packet type. On a dedicated server, this always returns {@code true}. */ - public record Protocol(String version, ProtocolSide client, ProtocolSide server) { - - /** - * Creates a new protocol with the given version, that is required on both sides. - */ - public static Protocol of(String version) { - return new Protocol(version, ProtocolSide.REQUIRED, ProtocolSide.REQUIRED); - } + public boolean canSend(CustomPacketPayload.Type type) { + return switch (FMLLoader.getDist()) { + case CLIENT -> ClientCanSendCheck.canSendOnClient(type); + case DEDICATED_SERVER -> true; + }; } - + /** - * Defines when a connection should be accepted. + * Checks whether a packet of a given type can currently be sent to the given player. This check that the given + * players connection supports the given packet type. */ - public enum ProtocolSide { - - /** - * The connection is only accepted if the protocol is present on the local and remote side - */ - REQUIRED(String::equals), - - /** - * The connection is accepted if the remote side is running on forge. However, it is not required - * that the protocol is present on the other side. - */ - OPTIONAL(REQUIRED.predicate.or((version, remote) -> NetworkRegistry.ABSENT.version().equals(remote))), + public boolean canSend(ServerPlayer player, CustomPacketPayload.Type type) { + return player.connection.hasChannel(type); + } - /** - * The connection is accepted if the remote side is running on forge or vanilla. However, it is not - * required that the protocol is present on the other side. - */ - VANILLA(OPTIONAL.predicate.or((version, remote) -> NetworkRegistry.ACCEPTVANILLA.equals(remote))), + private record PacketType(CustomPacketPayload.Type type, PacketHandler handler, boolean optional) {} + + private record WrappedHandler(PacketHandler handler) implements IPayloadHandler { - /** - * The connection is always rejected. - */ - REJECTED((version, remote) -> false); + @Override + public void handle(@Nonnull T payload, @Nonnull IPayloadContext context) { + this.handler().handle(payload, context); + } + } + + private static class ClientCanSendCheck { - private final BiPredicate predicate; - - ProtocolSide(BiPredicate predicate) { - this.predicate = predicate; + public static boolean canSendOnClient(CustomPacketPayload.Type type) { + ClientPacketListener connection = Minecraft.getInstance().getConnection(); + return connection != null && connection.hasChannel(type); } } } diff --git a/src/main/java/org/moddingx/libx/network/PacketHandler.java b/src/main/java/org/moddingx/libx/network/PacketHandler.java index e71518c7..3b9cd08c 100644 --- a/src/main/java/org/moddingx/libx/network/PacketHandler.java +++ b/src/main/java/org/moddingx/libx/network/PacketHandler.java @@ -1,41 +1,51 @@ package org.moddingx.libx.network; -import net.minecraftforge.network.NetworkEvent; - -import java.util.function.Supplier; - -/** - * An interface implementing the logic on how to handle a type of packet. - * - * Note that {@link PacketSerializer} and {@link PacketHandler} may not be implemented on the same class. - */ -public interface PacketHandler { - - /** - * The target thread, this handler should run on. - */ - Target target(); - - /** - * Handles the given message. - * - * @return Whether the message was handled. This is ignored on the {@link Target#MAIN_THREAD main thread} target. - */ - boolean handle(T msg, Supplier ctx); - - /** - * A thread target for a {@link PacketHandler}. - */ - enum Target { +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.HandlerThread; + +public abstract class PacketHandler { + + private final CustomPacketPayload.Type type; + private final PacketFlow direction; + private final StreamCodec codec; + private final HandlerThread thread; + + protected PacketHandler(PacketFlow direction, StreamCodec codec, CustomPacketPayload.Type type) { + this(type, direction, codec, HandlerThread.NETWORK); + } + + protected PacketHandler(CustomPacketPayload.Type type, PacketFlow direction, StreamCodec codec, HandlerThread thread) { + this.type = type; + this.direction = direction; + this.codec = codec; + this.thread = thread; + } - /** - * The main thread, where the game logic happens. - */ - MAIN_THREAD, + public CustomPacketPayload.Type type() { + return this.type; + } - /** - * An async network thread. This target may also run on the game thread, but it doesn't need to. - */ - NETWORK_THREAD + public final PacketFlow direction() { + return this.direction; + } + + public final StreamCodec codec() { + return this.codec; + } + + public final HandlerThread target() { + return this.thread; + } + + public void handle(T msg, IPayloadContext ctx) { + // This method does nothing. + // It is not abstract to allow implementing handler methods with @OnlyIn in a safe way. + // Due to dynamic binding, if the overriding method is removed by the side stripper this + // method will be invoked instead and nothing happens. This is also the primary reason, + // PacketHandler is an abstract class instead of an interface. } } diff --git a/src/main/java/org/moddingx/libx/network/PacketSerializer.java b/src/main/java/org/moddingx/libx/network/PacketSerializer.java deleted file mode 100644 index 1d09dfe5..00000000 --- a/src/main/java/org/moddingx/libx/network/PacketSerializer.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.moddingx.libx.network; - -import net.minecraft.network.FriendlyByteBuf; - -/** - * An interface implementing the logic on how to serialise and deserialize a message. - */ -public interface PacketSerializer { - - /** - * The class of the message serialised by this serializer. - */ - Class messageClass(); - - /** - * Encodes the message to a {@link FriendlyByteBuf}. - */ - void encode(T msg, FriendlyByteBuf buffer); - - /** - * Decodes a message from a {@link FriendlyByteBuf}. - */ - T decode(FriendlyByteBuf buffer); -} diff --git a/src/main/java/org/moddingx/libx/network/RemoteModList.java b/src/main/java/org/moddingx/libx/network/RemoteModList.java deleted file mode 100644 index 0db9f022..00000000 --- a/src/main/java/org/moddingx/libx/network/RemoteModList.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.moddingx.libx.network; - -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.common.ForgeI18n; -import net.minecraftforge.network.ConnectionData; -import net.minecraftforge.network.NetworkHooks; - -/** - * Allows to query information about mods, players have installed on the server side. - */ -public class RemoteModList { - - /** - * Gets whether a player has installed a certain mod. - */ - public static boolean hasMod(ServerPlayer player, String modid) { - ConnectionData data = NetworkHooks.getConnectionData(player.connection.connection); - return data != null && data.getModList().contains(modid); - } - - /** - * Creates a {@link MutableComponent} from a translation key. - * If the given player has the given mod installed, it will result in a - * {@link Component#translatable(String) translatable component}. If the player does not have the mod installed, - * the key is translated on the server and the result is a {@link Component#literal(String) literal component} with - * the translated text in english. - */ - public static MutableComponent translate(ServerPlayer player, String modid, String translationKey, Object... args) { - if (hasMod(player, modid)) { - return Component.translatable(translationKey, args); - } else { - return Component.literal(String.format(ForgeI18n.getPattern(translationKey), args)); - } - } -} diff --git a/src/main/java/org/moddingx/libx/registration/Registerable.java b/src/main/java/org/moddingx/libx/registration/Registerable.java index 611481bb..e7aed260 100644 --- a/src/main/java/org/moddingx/libx/registration/Registerable.java +++ b/src/main/java/org/moddingx/libx/registration/Registerable.java @@ -2,16 +2,12 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.IForgeRegistry; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.moddingx.libx.annotation.meta.SuperChainRequired; import org.moddingx.libx.mod.ModXRegistration; -import org.moddingx.libx.registration.tracking.RegistryTracker; import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.util.function.Consumer; /** * Everything that is registered to {@link ModXRegistration} that implements this can specify dependencies @@ -22,7 +18,7 @@ public interface Registerable { /** * Do stuff needed in the common setup phase. This is called during parallel mod loading. */ - default void registerCommon(SetupContext ctx) { + default void setupCommon(SetupContext ctx) { } @@ -30,7 +26,7 @@ default void registerCommon(SetupContext ctx) { * Do stuff needed in the client setup phase. This is called during parallel mod loading. */ @OnlyIn(Dist.CLIENT) - default void registerClient(SetupContext ctx) { + default void setupClient(SetupContext ctx) { } @@ -42,13 +38,13 @@ default void registerClient(SetupContext ctx) { default void registerAdditional(RegistrationContext ctx, EntryCollector builder) { } - + /** - * Adds fields with additional registry values to the {@link RegistryTracker}. This called, unless - * {@link RegistrationBuilder#disableRegistryTracking()} ()} is set. + * Similar to {@link #registerAdditional(RegistrationContext, EntryCollector)} but only invoked on the client. */ @SuperChainRequired - default void initTracking(RegistrationContext ctx, TrackingCollector builder) throws ReflectiveOperationException { + @OnlyIn(Dist.CLIENT) + default void registerClientAdditional(RegistrationContext ctx, EntryCollector builder) { } @@ -69,34 +65,4 @@ interface EntryCollector { */ void registerNamed(@Nullable ResourceKey> registry, String name, T value); } - - /** - * Some helpful methods to track elements with names depending on this elements registry name. - */ - interface TrackingCollector { - - /** - * Tracks a field with a value with the same registry name as the current object, registered in the given - * registry that is stored in the given field. The field must not be static and must be a field of the - * class that implements {@link Registerable} - */ - void track(IForgeRegistry registry, Field field); - - /** - * Tracks a field with a value with the same registry name as the current object with a given suffix, - * registered in the given registry that is stored in the given field. The field must not be static - * and must be a field of the class that implements {@link Registerable} - */ - void trackNamed(IForgeRegistry registry, String name, Field field); - - /** - * Adds a registry tracking action with the same registry name as the current object. - */ - void run(IForgeRegistry registry, Consumer action); - - /** - * Adds a registry tracking action with the same registry name as the current object with a given suffix. - */ - void runNamed(IForgeRegistry registry, String name, Consumer action); - } } diff --git a/src/main/java/org/moddingx/libx/registration/RegistrationBuilder.java b/src/main/java/org/moddingx/libx/registration/RegistrationBuilder.java index dcfe863e..06937a77 100644 --- a/src/main/java/org/moddingx/libx/registration/RegistrationBuilder.java +++ b/src/main/java/org/moddingx/libx/registration/RegistrationBuilder.java @@ -8,25 +8,14 @@ */ public class RegistrationBuilder { - private boolean tracking; private final List conditions; private final List transformers; public RegistrationBuilder() { - this.tracking = true; this.conditions = new ArrayList<>(); this.transformers = new ArrayList<>(); } - /** - * Disables automatic registry tracking. That means when registering objects, - * {@link Registerable#initTracking(RegistrationContext, Registerable.TrackingCollector)} - * won't be called and ModInit won't add fields to the tracker. - */ - public void disableRegistryTracking() { - this.tracking = false; - } - /** * Adds a new {@link RegistryCondition} that must match each object that is passed to the system in order * to be registered. @@ -44,8 +33,8 @@ public void transformer(RegistryTransformer transformer) { } public Result build() { - return new Result(this.tracking, List.copyOf(this.conditions), List.copyOf(this.transformers)); + return new Result(List.copyOf(this.conditions), List.copyOf(this.transformers)); } - public record Result(boolean tracking, List conditions, List transformers) {} + public record Result(List conditions, List transformers) {} } diff --git a/src/main/java/org/moddingx/libx/registration/tracking/RegistryTracker.java b/src/main/java/org/moddingx/libx/registration/tracking/RegistryTracker.java deleted file mode 100644 index 8895193d..00000000 --- a/src/main/java/org/moddingx/libx/registration/tracking/RegistryTracker.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.moddingx.libx.registration.tracking; - -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.ObjectHolderRegistry; -import org.moddingx.libx.impl.registration.tracking.TrackingData; -import org.moddingx.libx.registration.Registerable; -import org.moddingx.libx.registration.RegistrationContext; - -import java.lang.reflect.Field; -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * Provides a way to track the values of fields with a registry object. That means if the registry object is - * replaced, the field is updated. - */ -public class RegistryTracker { - - private static final Object LOCK = new Object(); - - private static boolean registeredToObjectHolders = false; - private static final Map> trackedRegistries = new HashMap<>(); - - /** - * Add a static field to the list of tracked fields. It will then be updated whenever the registry value changes. - * This will not ensure the field holds the value matching the registry at the time, the method is called. - * - * @param registry The registry used to track the field. - * @param field The field to track. - * @param id The {@link ResourceLocation} used for registered the object - */ - public static void track(IForgeRegistry registry, Field field, ResourceLocation id) { - synchronized (LOCK) { - trackingData(registry).addStatic(id, field); - } - } - - /** - * Add an instance field to the list of tracked fields. It will then be updated whenever the registry value changes. - * This will not ensure the field holds the value matching the registry at the time, the method is called. If the - * object instance is garbage collected, the tracking will be removed. - * - * If a field is tracked in {@link Registerable#initTracking(RegistrationContext, Registerable.TrackingCollector)} - * and the tracking of the {@link Registerable} is initialised because the parent object changed due to registry - * tracking, it will be ensured, that the field is updated as soon as possible to reflect the current registry - * change. This does not hold true if the tracking is initialised during first registering. - * - * @param registry The registry used to track the field. - * @param field The field to track. - * @param instance The object instance on which the field is updated. - * @param id The {@link ResourceLocation} used for registered the object - */ - public static void track(IForgeRegistry registry, Field field, Object instance, ResourceLocation id) { - synchronized (LOCK) { - trackingData(registry).addInstance(id, field, instance); - } - } - - /** - * Add an action that is invoked whenever the object with the given id changes in the registry. The action is tied - * to an instance object and won't be called any longer if the instance object is garbage collected. - * hold true if the tracking is initialised during first registering. - * - * @param registry The registry used to track the field. - * @param action The action to run when the object updates in the registry. - * @param instance The object instance to which the action is tied. - * @param id The {@link ResourceLocation} used for registered the object - */ - public static void run(IForgeRegistry registry, Consumer action, Object instance, ResourceLocation id) { - synchronized (LOCK) { - trackingData(registry).addAction(id, instance, action); - } - } - - private static TrackingData trackingData(IForgeRegistry registry) { - synchronized (LOCK) { - if (!registeredToObjectHolders) { - ObjectHolderRegistry.addHandler(new UpdateConsumer()); - registeredToObjectHolders = true; - } - //noinspection unchecked - return (TrackingData) trackedRegistries.computeIfAbsent(registry.getRegistryName(), k -> new TrackingData<>(registry)); - } - } - - private static class UpdateConsumer implements Consumer> { - - private final List enqueuedTasks = new ArrayList<>(); - private final Set objectsToUpdate = new HashSet<>(); - - @Override - public void accept(Predicate changed) { - Predicate registryChanged = changed; - Predicate instanceChanged = null; - this.enqueuedTasks.clear(); - this.objectsToUpdate.clear(); - do { - // enqueued tasks must run without lock as it allows objects to register new registry tracking fields - this.enqueuedTasks.forEach(Runnable::run); - this.enqueuedTasks.clear(); - this.objectsToUpdate.clear(); - synchronized (LOCK) { - for (Map.Entry> entry : trackedRegistries.entrySet()) { - entry.getValue().apply(registryChanged, instanceChanged, this.enqueuedTasks::add, this.objectsToUpdate::add); - } - Set objectsNextRound = Set.copyOf(this.objectsToUpdate); - instanceChanged = objectsNextRound::contains; - registryChanged = rl -> true; // In second round, everything that is now outdated needs updating, no matter of the registry - } - } while (!this.enqueuedTasks.isEmpty() || !this.objectsToUpdate.isEmpty()); - } - } -} diff --git a/src/main/java/org/moddingx/libx/registration/util/CapabilityInfo.java b/src/main/java/org/moddingx/libx/registration/util/CapabilityInfo.java new file mode 100644 index 00000000..38d373cf --- /dev/null +++ b/src/main/java/org/moddingx/libx/registration/util/CapabilityInfo.java @@ -0,0 +1,71 @@ +package org.moddingx.libx.registration.util; + +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.neoforged.neoforge.capabilities.*; +import org.moddingx.libx.registration.Registerable; +import org.moddingx.libx.registration.RegistrationContext; + +/** + * Auxiliary classes to to register capability providers easily. + */ +public abstract class CapabilityInfo { + + private CapabilityInfo() { + + } + + /** + * Wraps a {@link ICapabilityProvider capability provider} for an {@link ItemCapability item capability}. Using + * the LibX registration system, an instance of this class can be registered to apply a capability to an + * {@link net.minecraft.world.item.Item}. + * + * @see Registerable#registerAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Item( + ItemLike item, + ItemCapability capability, + ICapabilityProvider provider + ) {} + + /** + * Wraps a {@link IBlockCapabilityProvider capability provider} for a {@link BlockCapability block capability}. + * Using the LibX registration system, an instance of this class can be registered to apply a capability to a + * {@link net.minecraft.world.level.block.Block block}. + * + * @see Registerable#registerAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Block( + net.minecraft.world.level.block.Block block, + BlockCapability capability, + IBlockCapabilityProvider provider + ) {} + + /** + * Wraps a {@link ICapabilityProvider capability provider} for a {@link BlockCapability block capability}. Using + * the LibX registration system, an instance of this class can be registered to apply a capability to a + * {@link BlockEntityType block entity}. + * + * @see Registerable#registerAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record BlockEntity( + BlockEntityType blockEntityType, + BlockCapability capability, + ICapabilityProvider provider + ) {} + + /** + * Wraps a {@link ICapabilityProvider capability provider} for an {@link EntityCapability entity capability}. Using + * the LibX registration system, an instance of this class can be registered to apply a capability to an + * {@link EntityType entity type}. + * + * @see Registerable#registerAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Entity( + EntityType entityType, + EntityCapability capability, + ICapabilityProvider provider + ) {} +} diff --git a/src/main/java/org/moddingx/libx/registration/util/ClientExtensionInfo.java b/src/main/java/org/moddingx/libx/registration/util/ClientExtensionInfo.java new file mode 100644 index 00000000..3e176cb3 --- /dev/null +++ b/src/main/java/org/moddingx/libx/registration/util/ClientExtensionInfo.java @@ -0,0 +1,78 @@ +package org.moddingx.libx.registration.util; + +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.neoforged.neoforge.client.extensions.common.IClientBlockExtensions; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions; +import net.neoforged.neoforge.client.extensions.common.IClientMobEffectExtensions; +import org.moddingx.libx.registration.Registerable; +import org.moddingx.libx.registration.RegistrationContext; + +import java.util.function.Supplier; + +/** + * Auxiliary classes to to register client extensions easily. + */ +public abstract class ClientExtensionInfo { + + private ClientExtensionInfo() { + + } + + /** + * Wraps some {@link IClientItemExtensions client item extensions}. Using the LibX registration system, an + * instance of this class can be registered on the client using the same id as the associated + * {@link net.minecraft.world.item.Item} to set up the {@link IClientItemExtensions client item extensions}. + * + * @see Registerable#registerClientAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Item(Supplier extensions) { + public Item(IClientItemExtensions extensions) { this(() -> extensions); } + } + + /** + * Wraps some {@link IClientBlockExtensions client block extensions}. Using the LibX registration system, an + * instance of this class can be registered on the client using the same id as the associated + * {@link net.minecraft.world.level.block.Block} to set up the {@link IClientBlockExtensions client block extensions}. + * + * @see Registerable#registerClientAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Block(Supplier extensions) { + public Block(IClientBlockExtensions extensions) { this(() -> extensions); } + } + + /** + * Wraps some {@link IClientFluidTypeExtensions client fluid type extensions}. Using the LibX registration system, an + * instance of this class can be registered on the client using the same id as the associated + * {@link net.neoforged.neoforge.fluids.FluidType} to set up the {@link IClientFluidTypeExtensions client fluid type extensions}. + * + * @see Registerable#registerClientAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record Fluid(Supplier extensions) { + public Fluid(IClientFluidTypeExtensions extensions) { this(() -> extensions); } + } + + /** + * Wraps some {@link IClientMobEffectExtensions client mob effect extensions}. Using the LibX registration system, an + * instance of this class can be registered on the client using the same id as the associated + * {@link net.minecraft.world.effect.MobEffect} to set up the {@link IClientMobEffectExtensions client mob effect extensions}. + * + * @see Registerable#registerClientAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record MobEffect(Supplier extensions) { + public MobEffect(IClientMobEffectExtensions extensions) { this(() -> extensions); } + } + + /** + * Wraps a {@link MenuScreens.ScreenConstructor screen constructor}. Using the LibX registration system, an + * instance of this class can be registered on the client using the same id as the associated + * {@link MenuType} to set up the {@link MenuScreens.ScreenConstructor screen constructor} for that menu. + * + * @see Registerable#registerClientAdditional(RegistrationContext, Registerable.EntryCollector) + */ + public record MenuScreen>(MenuType menuType, MenuScreens.ScreenConstructor screenConstructor) {} +} diff --git a/src/main/java/org/moddingx/libx/registration/util/EnumObjects.java b/src/main/java/org/moddingx/libx/registration/util/EnumObjects.java index 0fcd493a..38de6318 100644 --- a/src/main/java/org/moddingx/libx/registration/util/EnumObjects.java +++ b/src/main/java/org/moddingx/libx/registration/util/EnumObjects.java @@ -3,8 +3,7 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.util.RandomSource; -import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.RegistryManager; +import org.moddingx.libx.annotation.registration.PlainRegisterable; import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.RegistrationContext; @@ -23,7 +22,8 @@ * @param The type of the enum to use. * @param The type of the thing to register. */ -public class EnumObjects, T> implements Registerable { +@PlainRegisterable +public final class EnumObjects, T> implements Registerable { private final ResourceKey> registryKey; private final T defaultValue; @@ -77,18 +77,4 @@ public void registerAdditional(RegistrationContext ctx, EntryCollector builder) builder.registerNamed(this.registryKey, entry.getKey().name().toLowerCase(Locale.ROOT), entry.getValue()); } } - - @Override - @OverridingMethodsMustInvokeSuper - public void initTracking(RegistrationContext ctx, Registerable.TrackingCollector builder) throws ReflectiveOperationException { - ResourceKey> registryKey = ctx.registry().orElse(null); - //noinspection UnstableApiUsage - IForgeRegistry registry = registryKey == null ? null : RegistryManager.ACTIVE.getRegistry(registryKey.location()); - if (registry != null) { - for (E key : this.keys) { - //noinspection unchecked - builder.runNamed(registry, key.name().toLowerCase(Locale.ROOT), value -> this.map.put(key, (T) value)); - } - } - } } diff --git a/src/main/java/org/moddingx/libx/render/ClientTickHandler.java b/src/main/java/org/moddingx/libx/render/ClientTickHandler.java index e2fd6d9e..a8eb8243 100644 --- a/src/main/java/org/moddingx/libx/render/ClientTickHandler.java +++ b/src/main/java/org/moddingx/libx/render/ClientTickHandler.java @@ -1,6 +1,6 @@ package org.moddingx.libx.render; -import net.minecraftforge.event.TickEvent; +import net.neoforged.neoforge.client.event.ClientTickEvent; /** * On the client, this counts the ticks in game. Useful for rendering code. @@ -13,9 +13,7 @@ public static int ticksInGame() { return ticksInGame; } - public static void tick(TickEvent.ClientTickEvent event) { - if (event.phase == TickEvent.Phase.START) { - ticksInGame += 1; - } + public static void tick(ClientTickEvent.Pre event) { + ticksInGame += 1; } } diff --git a/src/main/java/org/moddingx/libx/render/FilterGuiGraphics.java b/src/main/java/org/moddingx/libx/render/FilterGuiGraphics.java index c23af003..54252968 100644 --- a/src/main/java/org/moddingx/libx/render/FilterGuiGraphics.java +++ b/src/main/java/org/moddingx/libx/render/FilterGuiGraphics.java @@ -1,6 +1,7 @@ package org.moddingx.libx.render; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.datafixers.util.Either; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -233,51 +234,6 @@ public void blit(@Nonnull ResourceLocation atlasLocation, int x, int y, float uO this.parent.blit(atlasLocation, x, y, uOffset, vOffset, width, height, textureWidth, textureHeight); } - @Override - public void innerBlit(@Nonnull ResourceLocation atlasLocation, int x1, int x2, int y1, int y2, int blitOffset, float minU, float maxU, float minV, float maxV) { - this.parent.innerBlit(atlasLocation, x1, x2, y1, y2, blitOffset, minU, maxU, minV, maxV); - } - - @Override - public void blitNineSliced(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sliceSize, int sourceWidth, int sourceHeight, int sourceX, int sourceY) { - this.parent.blitNineSliced(atlasLocation, targetX, targetY, targetWidth, targetHeight, sliceSize, sourceWidth, sourceHeight, sourceX, sourceY); - } - - @Override - public void blitNineSliced(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sliceWidth, int sliceHeight, int sourceWidth, int sourceHeight, int sourceX, int sourceY) { - this.parent.blitNineSliced(atlasLocation, targetX, targetY, targetWidth, targetHeight, sliceWidth, sliceHeight, sourceWidth, sourceHeight, sourceX, sourceY); - } - - @Override - public void blitNineSliced(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int cornerWidth, int cornerHeight, int edgeWidth, int edgeHeight, int sourceWidth, int sourceHeight, int sourceX, int sourceY) { - this.parent.blitNineSliced(atlasLocation, targetX, targetY, targetWidth, targetHeight, cornerWidth, cornerHeight, edgeWidth, edgeHeight, sourceWidth, sourceHeight, sourceX, sourceY); - } - - @Override - public void blitNineSlicedSized(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sliceSize, int uWidth, int vHeight, int uOffset, int vOffset, int textureWidth, int textureHeight) { - this.parent.blitNineSlicedSized(atlasLocation, targetX, targetY, targetWidth, targetHeight, sliceSize, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight); - } - - @Override - public void blitNineSlicedSized(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sliceWidth, int sliceHeight, int uWidth, int vHeight, int uOffset, int vOffset, int textureWidth, int textureHeight) { - this.parent.blitNineSlicedSized(atlasLocation, targetX, targetY, targetWidth, targetHeight, sliceWidth, sliceHeight, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight); - } - - @Override - public void blitNineSlicedSized(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int cornerWidth, int cornerHeight, int edgeWidth, int edgeHeight, int uWidth, int vHeight, int uOffset, int vOffset, int textureWidth, int textureHeight) { - this.parent.blitNineSlicedSized(atlasLocation, targetX, targetY, targetWidth, targetHeight, cornerWidth, cornerHeight, edgeWidth, edgeHeight, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight); - } - - @Override - public void blitRepeating(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight) { - this.parent.blitRepeating(atlasLocation, targetX, targetY, targetWidth, targetHeight, sourceX, sourceY, sourceWidth, sourceHeight); - } - - @Override - public void blitRepeating(@Nonnull ResourceLocation atlasLocation, int targetX, int targetY, int targetWidth, int targetHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight, int textureWidth, int textureHeight) { - this.parent.blitRepeating(atlasLocation, targetX, targetY, targetWidth, targetHeight, sourceX, sourceY, sourceWidth, sourceHeight, textureWidth, textureHeight); - } - @Override public void renderItem(@Nonnull ItemStack stack, int x, int y) { this.parent.renderItem(stack, x, y); @@ -382,4 +338,59 @@ public void blitInscribed(@Nonnull ResourceLocation texture, int x, int y, int b public void blitInscribed(@Nonnull ResourceLocation texture, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight, boolean centerX, boolean centerY) { this.parent.blitInscribed(texture, x, y, boundsWidth, boundsHeight, rectWidth, rectHeight, centerX, centerY); } + + @Override + public boolean containsPointInScissor(int x, int y) { + return this.parent.containsPointInScissor(x, y); + } + + @Override + public void fillRenderType(@Nonnull RenderType renderType, int x1, int y1, int x2, int y2, int z) { + this.parent.fillRenderType(renderType, x1, y1, x2, y2, z); + } + + @Override + public int drawStringWithBackdrop(@Nonnull Font font, @Nonnull Component text, int x, int y, int xOffset, int color) { + return this.parent.drawStringWithBackdrop(font, text, x, y, xOffset, color); + } + + @Override + public void blitSprite(@Nonnull ResourceLocation sprite, int x, int y, int width, int height) { + this.parent.blitSprite(sprite, x, y, width, height); + } + + @Override + public void blitSprite(@Nonnull ResourceLocation sprite, int x, int y, int blitOffset, int width, int height) { + this.parent.blitSprite(sprite, x, y, blitOffset, width, height); + } + + @Override + public void blitSprite(@Nonnull ResourceLocation sprite, int textureWidth, int textureHeight, int uPosition, int vPosition, int x, int y, int uWidth, int vHeight) { + this.parent.blitSprite(sprite, textureWidth, textureHeight, uPosition, vPosition, x, y, uWidth, vHeight); + } + + @Override + public void blitSprite(@Nonnull ResourceLocation sprite, int textureWidth, int textureHeight, int uPosition, int vPosition, int x, int y, int blitOffset, int uWidth, int vHeight) { + this.parent.blitSprite(sprite, textureWidth, textureHeight, uPosition, vPosition, x, y, blitOffset, uWidth, vHeight); + } + + @Override + public void renderFakeItem(@Nonnull ItemStack stack, int x, int y, int seed) { + this.parent.renderFakeItem(stack, x, y, seed); + } + + @Override + public void renderComponentTooltipFromElements(@Nonnull Font font, @Nonnull List> elements, int mouseX, int mouseY, @Nonnull ItemStack stack) { + this.parent.renderComponentTooltipFromElements(font, elements, mouseX, mouseY, stack); + } + + @Override + public int drawScrollingString(@Nonnull Font font, @Nonnull Component text, int minX, int maxX, int y, int color) { + return this.parent.drawScrollingString(font, text, minX, maxX, y, color); + } + + @Override + public void innerBlit(@Nonnull ResourceLocation atlasLocation, int x1, int x2, int y1, int y2, int blitOffset, float minU, float maxU, float minV, float maxV) { + this.parent.innerBlit(atlasLocation, x1, x2, y1, y2, blitOffset, minU, maxU, minV, maxV); + } } diff --git a/src/main/java/org/moddingx/libx/render/ItemStackRenderer.java b/src/main/java/org/moddingx/libx/render/ItemStackRenderer.java index 5ea223bf..b40af259 100644 --- a/src/main/java/org/moddingx/libx/render/ItemStackRenderer.java +++ b/src/main/java/org/moddingx/libx/render/ItemStackRenderer.java @@ -8,42 +8,37 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.extensions.common.IClientItemExtensions; -import net.minecraftforge.fml.loading.FMLLoader; +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions; import org.apache.commons.lang3.tuple.Pair; -import org.moddingx.libx.base.BlockBase; import org.moddingx.libx.datagen.provider.model.ItemModelProviderBase; -import org.moddingx.libx.impl.RendererOnDataGenException; import org.moddingx.libx.registration.Registerable; import org.moddingx.libx.registration.SetupContext; import org.moddingx.libx.util.lazy.LazyValue; import javax.annotation.Nonnull; import java.util.*; -import java.util.function.Consumer; /** * This class is meant to apply a {@link BlockEntityRenderer} to items. Using it is really straightforward: * *
        - *
      • Add custom {@link IClientItemExtensions client extensions} to your item through - * {@link Item#initializeClient(Consumer)} or {@link BlockBase#initializeItemClient(Consumer)}
      • - *
      • In {@link Registerable#registerClient(SetupContext)} call + *
      • Add custom {@link IClientItemExtensions client extensions} to your item.
      • + *
      • In {@link Registerable#setupClient(SetupContext)} call * {@link ItemStackRenderer#addRenderBlock(BlockEntityType, boolean)}
      • *
      * - * The required models will generate automatically if you're using {@link ItemModelProviderBase}. + * You item also needs a special item model. {@link ItemModelProviderBase} provides a method to generate that for you. */ public class ItemStackRenderer extends BlockEntityWithoutLevelRenderer { @@ -66,7 +61,7 @@ public ItemStackRenderer(BlockEntityRenderDispatcher dispatcher, EntityModelSet */ public static void addRenderBlock(BlockEntityType beType, boolean readBlockEntityTag) { types.add(beType); - for (Block block : beType.validBlocks) { + for (Block block : beType.getValidBlocks()) { blocks.put(block, Pair.of(new LazyValue<>(() -> beType.create(BlockPos.ZERO, block.defaultBlockState())), readBlockEntityTag)); } } @@ -83,33 +78,30 @@ public void renderByItem(ItemStack stack, @Nonnull ItemDisplayContext ctx, @Nonn BlockEntityRenderer renderer = this.blockEntityRenderDispatcher.getRenderer(blockEntity); if (renderer != null) { + setLevelAndState(blockEntity, state); if (pair.getRight()) { - if (!defaultTags.containsKey(teType)) { + if (Minecraft.getInstance().level != null) { + if (!defaultTags.containsKey(teType)) { + defaultTags.put(teType, blockEntity.saveCustomOnly(Minecraft.getInstance().level.registryAccess())); + } else { + blockEntity.loadCustomOnly(defaultTags.get(teType), Minecraft.getInstance().level.registryAccess()); + } setLevelAndState(blockEntity, state); - defaultTags.put(teType, blockEntity.saveWithFullMetadata()); - } - - CompoundTag nbt = stack.getTag(); - setLevelAndState(blockEntity, state); - blockEntity.load(defaultTags.get(teType)); - if (nbt != null && nbt.contains("BlockEntityTag", Tag.TAG_COMPOUND)) { - CompoundTag blockTag = nbt.getCompound("BlockEntityTag"); - blockEntity.load(blockTag); + + CustomData customData = stack.get(DataComponents.BLOCK_ENTITY_DATA); + if (customData != null) { + customData.loadInto(blockEntity, Minecraft.getInstance().level.registryAccess()); + } } } - if (Minecraft.getInstance().level != null) { - blockEntity.setLevel(Minecraft.getInstance().level); - } - blockEntity.blockState = state; - poseStack.pushPose(); if (state.getRenderShape() != RenderShape.ENTITYBLOCK_ANIMATED) { //noinspection deprecation Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block.defaultBlockState(), poseStack, buffer, light, overlay); } - renderer.render(blockEntity, Minecraft.getInstance().getFrameTime(), poseStack, buffer, light, overlay); + renderer.render(blockEntity, Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(false), poseStack, buffer, light, overlay); poseStack.popPose(); } @@ -128,11 +120,7 @@ private static void setLevelAndState(BlockEntity blockEntity, BlockState state) * Gets the instance of the ItemStackRenderer. */ public static ItemStackRenderer get() { - if (FMLLoader.getLaunchHandler().isData()) { - throw new RendererOnDataGenException(); - } else { - return INSTANCE.get(); - } + return INSTANCE.get(); } /** @@ -141,6 +129,7 @@ public static ItemStackRenderer get() { public static IClientItemExtensions createProperties() { return new IClientItemExtensions() { + @Nonnull @Override public BlockEntityWithoutLevelRenderer getCustomRenderer() { return ItemStackRenderer.get(); diff --git a/src/main/java/org/moddingx/libx/render/RenderHelper.java b/src/main/java/org/moddingx/libx/render/RenderHelper.java index d35ef60b..495c568b 100644 --- a/src/main/java/org/moddingx/libx/render/RenderHelper.java +++ b/src/main/java/org/moddingx/libx/render/RenderHelper.java @@ -19,7 +19,7 @@ public class RenderHelper { * {@link RenderSystem#setShaderColor(float, float, float, float)}. */ public static final ResourceLocation TEXTURE_WHITE = LibX.getInstance().resource("textures/white.png"); - public static final ResourceLocation TEXTURE_CHEST_GUI = new ResourceLocation("minecraft", "textures/gui/container/generic_54.png"); + public static final ResourceLocation TEXTURE_CHEST_GUI = ResourceLocation.withDefaultNamespace("textures/gui/container/generic_54.png"); /** * Same as {@link #repeatBlit(GuiGraphics, int, int, int, int, int, int, TextureAtlasSprite)}. texWidth and texHeight are set from the sprite. @@ -92,10 +92,10 @@ public static void renderIconColored(PoseStack poseStack, VertexConsumer buffer, int green = color >> 8 & 255; int blue = color & 255; Matrix4f pose = poseStack.last().pose(); - buffer.vertex(pose, x, y + height, 0.0F).color(red, green, blue, (int) (alpha * 255.0F)).uv(sprite.getU0(), sprite.getV1()).overlayCoords(overlay).uv2(light).normal(0.0F, 0.0F, 1.0F).endVertex(); - buffer.vertex(pose, x + width, y + height, 0.0F).color(red, green, blue, (int) (alpha * 255.0F)).uv(sprite.getU1(), sprite.getV1()).overlayCoords(overlay).uv2(light).normal(0.0F, 0.0F, 1.0F).endVertex(); - buffer.vertex(pose, x + width, y, 0.0F).color(red, green, blue, (int) (alpha * 255.0F)).uv(sprite.getU1(), sprite.getV0()).overlayCoords(overlay).uv2(light).normal(0.0F, 0.0F, 1.0F).endVertex(); - buffer.vertex(pose, x, y, 0.0F).color(red, green, blue, (int) (alpha * 255.0F)).uv(sprite.getU0(), sprite.getV0()).overlayCoords(overlay).uv2(light).normal(0.0F, 0.0F, 1.0F).endVertex(); + buffer.addVertex(pose, x, y + height, 0.0F).setColor(red, green, blue, (int) (alpha * 255.0F)).setUv(sprite.getU0(), sprite.getV1()).setOverlay(overlay).setLight(light).setNormal(0.0F, 0.0F, 1.0F); + buffer.addVertex(pose, x + width, y + height, 0.0F).setColor(red, green, blue, (int) (alpha * 255.0F)).setUv(sprite.getU1(), sprite.getV1()).setOverlay(overlay).setLight(light).setNormal(0.0F, 0.0F, 1.0F); + buffer.addVertex(pose, x + width, y, 0.0F).setColor(red, green, blue, (int) (alpha * 255.0F)).setUv(sprite.getU1(), sprite.getV0()).setOverlay(overlay).setLight(light).setNormal(0.0F, 0.0F, 1.0F); + buffer.addVertex(pose, x, y, 0.0F).setColor(red, green, blue, (int) (alpha * 255.0F)).setUv(sprite.getU0(), sprite.getV0()).setOverlay(overlay).setLight(light).setNormal(0.0F, 0.0F, 1.0F); } /** diff --git a/src/main/java/org/moddingx/libx/render/RenderHelperBlock.java b/src/main/java/org/moddingx/libx/render/RenderHelperBlock.java index cbf95dff..6e7be5d3 100644 --- a/src/main/java/org/moddingx/libx/render/RenderHelperBlock.java +++ b/src/main/java/org/moddingx/libx/render/RenderHelperBlock.java @@ -1,9 +1,6 @@ package org.moddingx.libx.render; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.*; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -19,7 +16,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.data.ModelData; +import net.neoforged.neoforge.client.model.data.ModelData; import org.moddingx.libx.impl.render.BlockOverlayQuadCache; import java.util.List; @@ -115,7 +112,7 @@ public static void endOverlayBatch() { private static void renderBlockOverlayQuad(@SuppressWarnings("SameParameterValue") VertexFormat format, PoseStack.Pose pose, VertexConsumer vertex, List list, int light, int overlay, TextureAtlasSprite sprite, Predicate dirs) { for (BakedQuad quad : list) { if (dirs.test(quad.getDirection())) { - vertex.putBulkData(pose, modifyBlockQuad(format, quad, sprite), 1, 1, 1, light, overlay); + vertex.putBulkData(pose, modifyBlockQuad(format, quad, sprite), 1, 1, 1, 1, light, overlay); } } } @@ -126,13 +123,14 @@ private static BakedQuad modifyBlockQuad(VertexFormat format, BakedQuad quad, Te int[] data = quad.getVertices(); int[] newData = new int[data.length]; System.arraycopy(data, 0, newData, 0, data.length); - int uvIdx = format.getElements().indexOf(DefaultVertexFormat.ELEMENT_UV); - if (uvIdx != -1) { + int uvByteOff = format.getOffset(VertexFormatElement.UV); + //noinspection ConditionCoveredByFurtherCondition + if (uvByteOff != -1 && uvByteOff % 4 == 0) { // Byte offset / 4 = integer offset // Will break if UV is not on full ints but that is not the case in regular minecraft + int uvOff = uvByteOff / 4; TextureAtlasSprite oldSprite = quad.getSprite(); - int uvOff = format.getOffset(uvIdx) / 4; - int intSize = format.getIntegerSize(); + int intSize = format.getVertexSize() / 4; for (int off = 0; off + uvOff + 1 < newData.length; off += intSize) { newData[off + uvOff] = Float.floatToRawIntBits(((Float.intBitsToFloat(data[off + uvOff]) - oldSprite.getU0()) * newSprite.contents().width()) / oldSprite.contents().width() + newSprite.getU0()); newData[off + uvOff + 1] = Float.floatToRawIntBits(((Float.intBitsToFloat(data[off + uvOff + 1]) - oldSprite.getV0()) * newSprite.contents().height() / oldSprite.contents().height()) + newSprite.getV0()); diff --git a/src/main/java/org/moddingx/libx/render/RenderHelperFluid.java b/src/main/java/org/moddingx/libx/render/RenderHelperFluid.java index 438088a4..00555732 100644 --- a/src/main/java/org/moddingx/libx/render/RenderHelperFluid.java +++ b/src/main/java/org/moddingx/libx/render/RenderHelperFluid.java @@ -7,8 +7,8 @@ import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; /** * Helper class to render fluids into a GUI. This can either render {@link FluidStack fluid stacks} diff --git a/src/main/java/org/moddingx/libx/render/RenderHelperLevel.java b/src/main/java/org/moddingx/libx/render/RenderHelperLevel.java index 38dc61f3..e58dc4f8 100644 --- a/src/main/java/org/moddingx/libx/render/RenderHelperLevel.java +++ b/src/main/java/org/moddingx/libx/render/RenderHelperLevel.java @@ -4,7 +4,7 @@ import net.minecraft.client.Camera; import net.minecraft.core.BlockPos; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; /** * Utilities for rendering in the level. @@ -15,6 +15,9 @@ public class RenderHelperLevel { * This is meant to be called in {@link RenderLevelStageEvent}. This will move the pose stack to the * given position in the world. Do not always use this with {@code (0, 0, 0)} and translate to the * position you need afterward as it will be buggy millions of blocks away because of rounding errors. + * + * Note that this does not work correctly in the {@link RenderLevelStageEvent.Stage#AFTER_LEVEL AFTER_LEVEL} + * stage, however that stage is not meant to redner like geometries into the world anyway. */ public static void loadCameraPosition(Camera camera, PoseStack poseStack, BlockPos pos) { loadCameraPosition(camera, poseStack, pos.getX(), pos.getY(), pos.getZ()); @@ -24,6 +27,9 @@ public static void loadCameraPosition(Camera camera, PoseStack poseStack, BlockP * This is meant to be called in {@link RenderLevelStageEvent}. This will move the pose stack to the * given position in the world. Do not always use this with {@code (0, 0, 0)} and translate to the * position you need afterward as it will be buggy millions of blocks away because of rounding errors. + * + * Note that this does not work correctly in the {@link RenderLevelStageEvent.Stage#AFTER_LEVEL AFTER_LEVEL} + * stage, however that stage is not meant to redner like geometries into the world anyway. */ public static void loadCameraPosition(Camera camera, PoseStack poseStack, Vec3 pos) { loadCameraPosition(camera, poseStack, pos.x, pos.y, pos.z); @@ -33,6 +39,9 @@ public static void loadCameraPosition(Camera camera, PoseStack poseStack, Vec3 p * This is meant to be called in {@link RenderLevelStageEvent}. This will move the pose stack to the * given position in the world. Do not always use this with {@code (0, 0, 0)} and translate to the * position you need afterward as it will be buggy millions of blocks away because of rounding errors. + * + * Note that this does not work correctly in the {@link RenderLevelStageEvent.Stage#AFTER_LEVEL AFTER_LEVEL} + * stage, however that stage is not meant to redner like geometries into the world anyway. */ public static void loadCameraPosition(Camera camera, PoseStack poseStack, double x, double y, double z) { Vec3 cameraPos = camera.getPosition(); diff --git a/src/main/java/org/moddingx/libx/sandbox/generator/ExtendedNoiseChunkGenerator.java b/src/main/java/org/moddingx/libx/sandbox/generator/ExtendedNoiseChunkGenerator.java index 2b554ad6..f134c414 100644 --- a/src/main/java/org/moddingx/libx/sandbox/generator/ExtendedNoiseChunkGenerator.java +++ b/src/main/java/org/moddingx/libx/sandbox/generator/ExtendedNoiseChunkGenerator.java @@ -1,6 +1,6 @@ package org.moddingx.libx.sandbox.generator; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; @@ -27,7 +27,7 @@ */ public class ExtendedNoiseChunkGenerator extends NoiseBasedChunkGenerator { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( BiomeSource.CODEC.fieldOf("biome_source").forGetter(gen -> gen.biomeSource), NoiseGeneratorSettings.CODEC.fieldOf("settings").forGetter(gen -> gen.actualSettings), SurfaceRuleSet.CODEC.optionalFieldOf("surface_override").forGetter(gen -> gen.surfaceOverride) @@ -50,17 +50,17 @@ private ExtendedNoiseChunkGenerator(BiomeSource biomes, Holder> biomes = this.biomeSource.possibleBiomes(); - SurfaceRules.RuleSource surfaceRule = set.build(access.registryOrThrow(Registries.BIOME), access.registryOrThrow(SandBox.BIOME_SURFACE), biomes, this.actualSettings.get()); + SurfaceRules.RuleSource surfaceRule = set.build(access.registryOrThrow(Registries.BIOME), access.registryOrThrow(SandBox.BIOME_SURFACE), biomes, this.actualSettings.value()); this.fakeSettings.set(Holder.direct(withSurface(settings, surfaceRule))); } } @Nonnull @Override - protected Codec codec() { + protected MapCodec codec() { return CODEC; } @@ -75,6 +75,7 @@ public boolean stable(@Nonnull ResourceKey settings) { return this.actualSettings.is(settings); } + @SuppressWarnings("deprecation") private static NoiseGeneratorSettings withSurface(NoiseGeneratorSettings settings, SurfaceRules.RuleSource surfaceRule) { return new NoiseGeneratorSettings( settings.noiseSettings(), diff --git a/src/main/java/org/moddingx/libx/sandbox/generator/LayeredBiomeSource.java b/src/main/java/org/moddingx/libx/sandbox/generator/LayeredBiomeSource.java index 834de698..226773a6 100644 --- a/src/main/java/org/moddingx/libx/sandbox/generator/LayeredBiomeSource.java +++ b/src/main/java/org/moddingx/libx/sandbox/generator/LayeredBiomeSource.java @@ -1,7 +1,7 @@ package org.moddingx.libx.sandbox.generator; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.*; import net.minecraft.util.RandomSource; @@ -19,7 +19,7 @@ */ public class LayeredBiomeSource extends BiomeSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( RegistryCodecs.homogeneousList(SandBox.BIOME_LAYER, BiomeLayer.DIRECT_CODEC).fieldOf("layers").forGetter((LayeredBiomeSource biomes) -> biomes.layers) ).apply(instance, LayeredBiomeSource::new)); @@ -53,7 +53,7 @@ public void init(long seed) { @Nonnull @Override - protected Codec codec() { + protected MapCodec codec() { return CODEC; } diff --git a/src/main/java/org/moddingx/libx/sandbox/placement/HeightPlacementFilter.java b/src/main/java/org/moddingx/libx/sandbox/placement/HeightPlacementFilter.java index a944ed16..1cd667cf 100644 --- a/src/main/java/org/moddingx/libx/sandbox/placement/HeightPlacementFilter.java +++ b/src/main/java/org/moddingx/libx/sandbox/placement/HeightPlacementFilter.java @@ -1,6 +1,6 @@ package org.moddingx.libx.sandbox.placement; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.BlockPos; import net.minecraft.util.RandomSource; @@ -17,7 +17,7 @@ */ public class HeightPlacementFilter extends PlacementFilter { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( VerticalAnchor.CODEC.fieldOf("min_inclusive").forGetter(filter -> filter.minInclusive), VerticalAnchor.CODEC.fieldOf("max_inclusive").forGetter(filter -> filter.maxInclusive) ).apply(instance, HeightPlacementFilter::new)); diff --git a/src/main/java/org/moddingx/libx/sandbox/placement/InvertPlacementFilter.java b/src/main/java/org/moddingx/libx/sandbox/placement/InvertPlacementFilter.java index af9b047a..833345b5 100644 --- a/src/main/java/org/moddingx/libx/sandbox/placement/InvertPlacementFilter.java +++ b/src/main/java/org/moddingx/libx/sandbox/placement/InvertPlacementFilter.java @@ -1,7 +1,7 @@ package org.moddingx.libx.sandbox.placement; -import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.BlockPos; import net.minecraft.util.RandomSource; @@ -17,7 +17,7 @@ */ public class InvertPlacementFilter extends PlacementFilter { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( PlacementModifier.CODEC.fieldOf("filter").flatXmap( modifier -> modifier instanceof PlacementFilter filter ? DataResult.success(filter) : DataResult.error(() -> "Can only invert placement filters, not modifiers. Invalid filter: " + modifier), DataResult::success diff --git a/src/main/java/org/moddingx/libx/screen/ColorPicker.java b/src/main/java/org/moddingx/libx/screen/ColorPicker.java index ddb09b31..3e4ea10e 100644 --- a/src/main/java/org/moddingx/libx/screen/ColorPicker.java +++ b/src/main/java/org/moddingx/libx/screen/ColorPicker.java @@ -7,6 +7,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; import net.minecraft.util.Mth; @@ -157,38 +158,34 @@ private void update() { } @Override - public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { - super.render(graphics, mouseX, mouseY, partialTicks); - + public void renderWidgetContent(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { graphics.pose().pushPose(); graphics.pose().translate(this.getX(), this.getY(), 0); Matrix4f matrix = graphics.pose().last().pose(); { - RenderSystem.setShader(GameRenderer::getPositionColorTexShader); + RenderSystem.setShader(GameRenderer::getPositionColorTexLightmapShader); RenderSystem.setShaderTexture(0, RenderHelper.TEXTURE_WHITE); - BufferBuilder vertex = Tesselator.getInstance().getBuilder(); - vertex.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + BufferBuilder vertex = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP); if (this.enabled) { this.hsbMatrix.get().forEach(v -> v.add(vertex, matrix)); } else { this.hsbMatrix.get().forEach(v -> v.addGrayscale(vertex, matrix)); } - Tesselator.getInstance().end(); + BufferUploader.drawWithShader(vertex.buildOrThrow()); } { - RenderSystem.setShader(GameRenderer::getPositionColorTexShader); + RenderSystem.setShader(GameRenderer::getPositionColorTexLightmapShader); RenderSystem.setShaderTexture(0, RenderHelper.TEXTURE_WHITE); - BufferBuilder vertex = Tesselator.getInstance().getBuilder(); - vertex.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + BufferBuilder vertex = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP); if (this.enabled) { this.huePanel.forEach(v -> v.add(vertex, matrix)); } else { this.huePanel.forEach(v -> v.addGrayscale(vertex, matrix)); } - Tesselator.getInstance().end(); + BufferUploader.drawWithShader(vertex.buildOrThrow()); } int colorValue = ((this.red & 0xFF) << 16) | ((this.green & 0xFF) << 8) | (this.blue & 0xFF); @@ -198,7 +195,7 @@ public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float displayColor = (value << 16) | (value << 8) | value; } - int highlightColor = this.brightness > 0.5 ? 0x000000 : 0xFFFFFF; + int highlightColor = this.brightness > 0.5 ? 0xFF000000 : 0xFFFFFFFF; RenderHelper.rgb(highlightColor); graphics.blit(RenderHelper.TEXTURE_WHITE, 115, 69, 20, 0, 0, 85, 31, 256, 256); @@ -208,6 +205,7 @@ public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float String colorText = String.format("#%06X", colorValue); RenderHelper.resetColor(); + graphics.pose().translate(0, 0, 60); graphics.drawString(Minecraft.getInstance().font, colorText, 157 - (Minecraft.getInstance().font.width(colorText) / 2), 80, highlightColor, false); graphics.pose().popPose(); @@ -272,12 +270,12 @@ public static ColorValue create(int value) { private record VertexInfo(float x, float y, float u, float v, ColorValue color) { public void add(VertexConsumer vertex, Matrix4f matrix) { - vertex.vertex(matrix, this.x, this.y, 20).color(this.color.red, this.color.green, this.color.blue, 255).uv(this.u, this.v).endVertex(); + vertex.addVertex(matrix, this.x, this.y, 20).setColor(this.color.red, this.color.green, this.color.blue, 255).setUv(this.u, this.v).setLight(LightTexture.FULL_BRIGHT); } public void addGrayscale(VertexConsumer vertex, Matrix4f matrix) { int value = Math.round((this.color.red + this.color.green + this.color.blue) / 3f); - vertex.vertex(matrix, this.x, this.y, 20).color(value, value, value, 255).uv(this.u, this.v).endVertex(); + vertex.addVertex(matrix, this.x, this.y, 20).setColor(value, value, value, 255).setUv(this.u, this.v).setLight(LightTexture.FULL_BRIGHT); } } diff --git a/src/main/java/org/moddingx/libx/screen/Panel.java b/src/main/java/org/moddingx/libx/screen/Panel.java index d46798af..6f3bcc1f 100644 --- a/src/main/java/org/moddingx/libx/screen/Panel.java +++ b/src/main/java/org/moddingx/libx/screen/Panel.java @@ -68,13 +68,18 @@ public List children() { } @Override - public void renderWidget(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + public final void renderWidget(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { graphics.pose().pushPose(); graphics.pose().translate(this.getX(), this.getY(), 0); for (Renderable widget : this.renderables) { widget.render(graphics, mouseX - this.getX(), mouseY - this.getY(), partialTicks); } graphics.pose().popPose(); + this.renderWidgetContent(graphics, mouseX, mouseY, partialTicks); + } + + protected void renderWidgetContent(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + // } @Nonnull @@ -107,8 +112,8 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double dra } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double delta) { - return this.getChildAt(mouseX, mouseY).filter(child -> child.mouseScrolled(mouseX - this.getX(), mouseY - this.getY(), delta)).isPresent(); + public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { + return this.getChildAt(mouseX, mouseY).filter(child -> child.mouseScrolled(mouseX - this.getX(), mouseY - this.getY(), scrollX, scrollY)).isPresent(); } @Override diff --git a/src/main/java/org/moddingx/libx/screen/text/TextScreen.java b/src/main/java/org/moddingx/libx/screen/text/TextScreen.java index 98ef061e..fb559d0c 100644 --- a/src/main/java/org/moddingx/libx/screen/text/TextScreen.java +++ b/src/main/java/org/moddingx/libx/screen/text/TextScreen.java @@ -58,13 +58,13 @@ public boolean isPauseScreen() { @Override public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { - this.renderBackground(graphics); + this.renderBackground(graphics, mouseX, mouseY, partialTick); if (this.content == null) return; int left = this.left(); int top = this.top(); graphics.pose().pushPose(); graphics.pose().translate(0, 0, 20); - this.drawBackground(graphics, left - 10, top - 10, this.content.width() + 20, this.content.height() + 20, partialTick); + this.drawBackground(graphics, left - 10, top - 10, this.content.width() + 20, this.content.height() + 20); graphics.pose().translate(0, 0, 100); this.content.render(graphics, left, top); graphics.pose().popPose(); @@ -85,7 +85,7 @@ public void render(@Nonnull GuiGraphics graphics, int mouseX, int mouseY, float graphics.pose().popPose(); } - protected void drawBackground(GuiGraphics graphics, int x, int y, int width, int height, float partialTick) { + protected void drawBackground(GuiGraphics graphics, int x, int y, int width, int height) { RenderHelper.renderGuiBackground(graphics, x, y, width, height); } diff --git a/src/main/java/org/moddingx/libx/util/Misc.java b/src/main/java/org/moddingx/libx/util/Misc.java index ca9ff0ac..d4f8abb3 100644 --- a/src/main/java/org/moddingx/libx/util/Misc.java +++ b/src/main/java/org/moddingx/libx/util/Misc.java @@ -14,5 +14,5 @@ public class Misc { * The reason for {@code minecraft:missigno} is that minecraft uses this resource location * on it's own. See for example {@link MissingTextureAtlasSprite}. */ - public static final ResourceLocation MISSINGNO = new ResourceLocation("minecraft", "missingno"); + public static final ResourceLocation MISSINGNO = ResourceLocation.withDefaultNamespace("missingno"); } diff --git a/src/main/java/org/moddingx/libx/util/data/ResourceList.java b/src/main/java/org/moddingx/libx/util/data/ResourceList.java index 00ea102a..4993bebb 100644 --- a/src/main/java/org/moddingx/libx/util/data/ResourceList.java +++ b/src/main/java/org/moddingx/libx/util/data/ResourceList.java @@ -6,6 +6,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import org.moddingx.libx.LibX; import org.moddingx.libx.util.lazy.LazyValue; @@ -65,6 +66,8 @@ public class ResourceList implements Predicate { */ public static final ResourceList DENY_LIST = new ResourceList(false, b -> {}); + public static final StreamCodec STREAM_CODEC = StreamCodec.of((buf, value) -> value.toNetwork(buf), ResourceList::new); + private static final WildcardString NAMESPACE_MC = new WildcardString(List.of("minecraft")); private final boolean allowList; @@ -106,10 +109,7 @@ public ResourceList(JsonObject json) { this.rules = rules.build(); } - /** - * Reads a resource list from a {@link FriendlyByteBuf}. - */ - public ResourceList(FriendlyByteBuf buffer) { + private ResourceList(FriendlyByteBuf buffer) { this.allowList = buffer.readBoolean(); int ruleSize = buffer.readVarInt(); ImmutableList.Builder rules = ImmutableList.builder(); @@ -132,11 +132,8 @@ public JsonObject toJson() { json.add("elements", array); return json; } - - /** - * Writes this resource list to a {@link FriendlyByteBuf}. - */ - public void toNetwork(FriendlyByteBuf buffer) { + + private void toNetwork(FriendlyByteBuf buffer) { buffer.writeBoolean(this.allowList); buffer.writeVarInt(this.rules.size()); this.rules.forEach(rule -> rule.toNetwork(buffer)); diff --git a/src/main/java/org/moddingx/libx/util/game/ComponentUtil.java b/src/main/java/org/moddingx/libx/util/game/ComponentUtil.java index b298d1f2..534885cf 100644 --- a/src/main/java/org/moddingx/libx/util/game/ComponentUtil.java +++ b/src/main/java/org/moddingx/libx/util/game/ComponentUtil.java @@ -4,13 +4,28 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import net.minecraft.ChatFormatting; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.TypedDataComponent; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; import net.minecraft.network.chat.*; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.FormattedCharSequence; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * Utilities for {@link Component text components}. @@ -37,7 +52,7 @@ public static String getConsoleString(Component tc) { private static void formattingCodes(StringBuilder sb, Style style) { if (style.getColor() != null) { - int color = style.getColor().value; + int color = style.getColor().getValue(); sb.append("\u001B[38;2;").append((color >> 16) & 0xFF).append(";").append((color >> 8) & 0xFF).append(";").append(color & 0xFF).append("m"); } if (style.bold != null) { @@ -82,7 +97,7 @@ private static void reset(StringBuilder sb) { } /** - * Turns a {@link JsonElement} to a {@link Component} with syntax highlighting that can be used for display. + * Turns a {@link JsonElement} into a {@link Component} with syntax highlighting that can be used for display. */ public static Component toPrettyComponent(JsonElement json) { if (json.isJsonNull()) { @@ -126,6 +141,60 @@ public static Component toPrettyComponent(JsonElement json) { } } + /** + * Turns a {@link DataComponentMap} into a {@link Component} with syntax highlighting that can be used for display. + */ + public static Component toPrettyComponent(ResourceKey>> registry, DataComponentMap components) { + return toPrettyComponent(registry, components.stream().collect(Collectors.toUnmodifiableMap(TypedDataComponent::type, tc -> Optional.of(tc.value())))); + } + + /** + * Turns a {@link DataComponentPatch} into a {@link Component} with syntax highlighting that can be used for display. + */ + public static Component toPrettyComponent(ResourceKey>> registry, DataComponentPatch patch) { + return toPrettyComponent(registry, patch.entrySet().stream().collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue))); + } + + private static Component toPrettyComponent(ResourceKey>> registry, Map, Optional> map) { + //noinspection unchecked + Registry> theRegistry = (Registry>) BuiltInRegistries.REGISTRY.get(registry.location()); + if (theRegistry == null) throw new IllegalStateException("Registry not found in builtin registries: " + registry); + + Map> typeMap = new HashMap<>(); + for (DataComponentType type : map.keySet()) { + if (type.isTransient()) continue; + ResourceLocation id = theRegistry.getKey(type); + if (id == null) throw new IllegalStateException("Unregistered data component type: " + type); + typeMap.put(id, type); + } + + MutableComponent cmp = Component.literal("["); + boolean first = true; + for (ResourceLocation typeId : typeMap.keySet().stream().sorted().toList()) { + if (first) { + first = false; + cmp = cmp.append(", "); + } + DataComponentType type = typeMap.get(typeId); + Optional maybeValue = map.get(type); + if (maybeValue.isEmpty()) { + cmp.append(Component.literal("!")); + } + cmp = cmp.append(Component.literal(typeId.toString()).withStyle(ChatFormatting.DARK_RED)); + if (maybeValue.isPresent()) { + cmp = cmp.append("="); + //noinspection unchecked + DataResult result = ((Codec) type.codecOrThrow()).encode(maybeValue.get(), NbtOps.INSTANCE, NbtOps.INSTANCE.empty()); + if (result instanceof DataResult.Error) { + return Component.literal("encoder error for " + typeId).withStyle(ChatFormatting.RED); + } + cmp = cmp.append(NbtUtils.toPrettyComponent(result.getOrThrow())); + } + } + cmp = cmp.append(Component.literal("]")); + return cmp; + } + /** * Adds a {@link ClickEvent click event} to the given component to copy the given text to clipboard. */ diff --git a/src/main/java/org/moddingx/libx/util/game/LongAmountToIntUtil.java b/src/main/java/org/moddingx/libx/util/game/LongAmountToIntUtil.java index e1468887..035ebdc4 100644 --- a/src/main/java/org/moddingx/libx/util/game/LongAmountToIntUtil.java +++ b/src/main/java/org/moddingx/libx/util/game/LongAmountToIntUtil.java @@ -1,8 +1,7 @@ package org.moddingx.libx.util.game; import net.minecraft.util.Mth; -import net.minecraftforge.energy.IEnergyStorage; -import org.moddingx.libx.capability.LongEnergyStorage; +import net.neoforged.neoforge.energy.IEnergyStorage; /** * Utility methods to convert amounts (must be > 0) that are stored as {@code long} diff --git a/src/main/java/org/moddingx/libx/capability/LongEnergyStorage.java b/src/main/java/org/moddingx/libx/util/game/LongEnergyStorage.java similarity index 86% rename from src/main/java/org/moddingx/libx/capability/LongEnergyStorage.java rename to src/main/java/org/moddingx/libx/util/game/LongEnergyStorage.java index 3943ad77..9c0b22ad 100644 --- a/src/main/java/org/moddingx/libx/capability/LongEnergyStorage.java +++ b/src/main/java/org/moddingx/libx/util/game/LongEnergyStorage.java @@ -1,7 +1,6 @@ -package org.moddingx.libx.capability; +package org.moddingx.libx.util.game; -import net.minecraftforge.energy.IEnergyStorage; -import org.moddingx.libx.util.game.LongAmountToIntUtil; +import net.neoforged.neoforge.energy.IEnergyStorage; /** * An {@link IEnergyStorage} that allows storing the energy value as long. diff --git a/src/main/java/org/moddingx/libx/util/lazy/LazyValue.java b/src/main/java/org/moddingx/libx/util/lazy/LazyValue.java index d22dff2b..7ad9069e 100644 --- a/src/main/java/org/moddingx/libx/util/lazy/LazyValue.java +++ b/src/main/java/org/moddingx/libx/util/lazy/LazyValue.java @@ -1,7 +1,6 @@ package org.moddingx.libx.util.lazy; import net.minecraft.util.LazyLoadedValue; -import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import java.util.function.Function; @@ -56,14 +55,6 @@ public T get() { } } - /** - * Gets a lazy value that will have the value of the lazy optional if present. If not - * it will have the value of this lazy value. - */ - public LazyValue asDefault(LazyOptional optional) { - return new LazyValue<>(() -> optional.resolve().orElseGet(this::get)); - } - /** * Gets a new lazy value that will hold the value of this lazy value applied to * the mapper function. The mapper function will also get called lazy. diff --git a/src/main/java/org/moddingx/libx/util/math/DoublePolynomial.java b/src/main/java/org/moddingx/libx/util/math/DoublePolynomial.java index 748a11ae..ecd3c5d2 100644 --- a/src/main/java/org/moddingx/libx/util/math/DoublePolynomial.java +++ b/src/main/java/org/moddingx/libx/util/math/DoublePolynomial.java @@ -1,6 +1,10 @@ package org.moddingx.libx.util.math; import com.mojang.serialization.Codec; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.moddingx.libx.codec.MoreStreamCodecs; import java.util.Arrays; import java.util.List; @@ -17,6 +21,10 @@ public final class DoublePolynomial extends Polynomial implements Double p -> p.coefficients.length == 0 ? List.of(0d) : Arrays.stream(p.coefficients).boxed().toList() ); + public static final StreamCodec STREAM_CODEC = MoreStreamCodecs.listOf(ByteBufCodecs.DOUBLE).map( + doubles-> new DoublePolynomial(doubles.stream().mapToDouble(c -> c).dropWhile(d -> d == 0).toArray()), + p -> p.coefficients.length == 0 ? List.of(0d) : Arrays.stream(p.coefficients).boxed().toList()); + /** * The polynomial that is always zero. */ diff --git a/src/main/java/org/moddingx/libx/util/math/IntPolynomial.java b/src/main/java/org/moddingx/libx/util/math/IntPolynomial.java index a7b4b8aa..6892cc52 100644 --- a/src/main/java/org/moddingx/libx/util/math/IntPolynomial.java +++ b/src/main/java/org/moddingx/libx/util/math/IntPolynomial.java @@ -1,6 +1,10 @@ package org.moddingx.libx.util.math; import com.mojang.serialization.Codec; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.moddingx.libx.codec.MoreStreamCodecs; import java.util.Arrays; import java.util.List; @@ -17,6 +21,10 @@ public final class IntPolynomial extends Polynomial implements IntUnary ints -> new IntPolynomial(ints.dropWhile(d -> d == 0).toArray(), true), p -> p.coefficients.length == 0 ? IntStream.of(0) : Arrays.stream(p.coefficients) ); + + public static final StreamCodec STREAM_CODEC = MoreStreamCodecs.listOf(ByteBufCodecs.INT).map( + ints-> new IntPolynomial(ints.stream().mapToInt(c -> c).dropWhile(d -> d == 0).toArray()), + p -> p.coefficients.length == 0 ? List.of(0) : Arrays.stream(p.coefficients).boxed().toList()); /** * The polynomial that is always zero. diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 070149e3..65303071 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,43 +1,41 @@ public net.minecraft.client.gui.font.FontManager$Preparation -public net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterList$Preset$SourceProvider +public net.minecraft.core.Holder$Reference$Type public net.minecraft.world.level.levelgen.SurfaceRules$Context public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule public net.minecraft.world.level.storage.loot.entries.ComposableEntryContainer -public net.minecraft.client.KeyMapping f_90809_ # ALL -public net.minecraft.client.Minecraft f_91023_ # progressTasks -public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer f_172547_ # blockEntityRenderDispatcher -public net.minecraft.data.worldgen.biome.OverworldBiomes m_194843_(F)I # calculateSkyColor -public net.minecraft.data.worldgen.ProcessorLists f_127198_ # EMPTY -public net.minecraft.network.chat.Style f_131102_ # bold -public net.minecraft.network.chat.Style f_131103_ # italic -public net.minecraft.network.chat.Style f_131104_ # underlined -public net.minecraft.network.chat.Style f_131105_ # strikethrough -public net.minecraft.network.chat.Style f_131106_ # obfuscated -public net.minecraft.network.chat.TextColor f_131257_ # value -public net.minecraft.server.MinecraftServer f_129744_ # storageSource -public net.minecraft.tags.TagBuilder f_215897_ # entries -public net.minecraft.tags.TagEntry f_215914_ # tag -public net.minecraft.world.item.CreativeModeTab$Builder f_256856_ # displayName -public net.minecraft.world.item.crafting.Ingredient f_43902_ # values -public net.minecraft.world.item.crafting.Ingredient$ItemValue f_43951_ # item -public net.minecraft.world.item.crafting.Ingredient$TagValue f_43959_ # tag -public net.minecraft.world.level.biome.FixedBiomeSource f_48252_ # biome -public net.minecraft.world.level.block.entity.BlockEntity f_58856_ # blockState -public net.minecraft.world.level.block.entity.BlockEntityType f_58915_ # validBlocks -public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool f_210560_ # templates +public net.minecraft.client.KeyMapping ALL +public net.minecraft.client.Minecraft progressTasks +public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer blockEntityRenderDispatcher +public net.minecraft.core.Holder$Reference type +public net.minecraft.core.MappedRegistry unregisteredIntrusiveHolders +public net.minecraft.data.worldgen.ProcessorLists EMPTY +public net.minecraft.network.chat.Style bold +public net.minecraft.network.chat.Style italic +public net.minecraft.network.chat.Style underlined +public net.minecraft.network.chat.Style strikethrough +public net.minecraft.network.chat.Style obfuscated +public net.minecraft.server.MinecraftServer storageSource +public net.minecraft.tags.TagBuilder entries +public net.minecraft.tags.TagEntry tag +public net.minecraft.world.level.biome.FixedBiomeSource biome +public net.minecraft.world.level.block.entity.BlockEntity blockState +public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool templates +public net.minecraft.world.level.storage.loot.LootTable$Builder randomSequence -public net.minecraft.client.Minecraft m_91326_(Ljava/lang/String;)V # openChatScreen -public net.minecraft.client.gui.GuiGraphics m_280444_(Lnet/minecraft/resources/ResourceLocation;IIIIIFFFF)V # innerBlit -public net.minecraft.client.gui.font.FontManager m_284410_(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture; # prepare -public net.minecraft.data.recipes.RecipeProvider m_206406_(Lnet/minecraft/tags/TagKey;)Lnet/minecraft/advancements/critereon/InventoryChangeTrigger$TriggerInstance; # has -public net.minecraft.resources.ResourceLocation m_135841_(Ljava/lang/String;)Z # isValidPath -public net.minecraft.world.item.crafting.RecipeManager m_44054_(Lnet/minecraft/world/item/crafting/RecipeType;)Ljava/util/Map; # byType -public net.minecraft.world.level.levelgen.structure.pools.FeaturePoolElement (Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V # -public net.minecraft.world.level.levelgen.structure.pools.LegacySinglePoolElement (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V # -public net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V # -public net.minecraft.world.level.storage.loot.LootTable m_230922_(Lnet/minecraft/world/level/storage/loot/LootContext;)Lit/unimi/dsi/fastutil/objects/ObjectArrayList; # getRandomItems -public net.minecraft.world.level.storage.loot.entries.EntryGroup ([Lnet/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer;[Lnet/minecraft/world/level/storage/loot/predicates/LootItemCondition;)V # -public net.minecraft.world.level.storage.loot.entries.SequentialEntry ([Lnet/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer;[Lnet/minecraft/world/level/storage/loot/predicates/LootItemCondition;)V # +public net.minecraft.client.Minecraft openChatScreen(Ljava/lang/String;)V +public net.minecraft.client.gui.GuiGraphics innerBlit(Lnet/minecraft/resources/ResourceLocation;IIIIIFFFF)V +public net.minecraft.client.gui.font.FontManager prepare(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture; +public net.minecraft.data.worldgen.biome.OverworldBiomes calculateSkyColor(F)I +public net.minecraft.network.chat.Component$Serializer deserialize(Lcom/google/gson/JsonElement;Lnet/minecraft/core/HolderLookup$Provider;)Lnet/minecraft/network/chat/MutableComponent; +public net.minecraft.network.chat.Component$Serializer serialize(Lnet/minecraft/network/chat/Component;Lnet/minecraft/core/HolderLookup$Provider;)Lcom/google/gson/JsonElement; +public net.minecraft.world.level.levelgen.structure.pools.FeaturePoolElement (Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V +public net.minecraft.world.level.levelgen.structure.pools.LegacySinglePoolElement (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;Ljava/util/Optional;)V +public net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;Ljava/util/Optional;)V +public net.minecraft.world.level.storage.loot.LootTable getRandomItems(Lnet/minecraft/world/level/storage/loot/LootContext;)Lit/unimi/dsi/fastutil/objects/ObjectArrayList; +public net.minecraft.world.level.storage.loot.entries.EntryGroup (Ljava/util/List;Ljava/util/List;)V +public net.minecraft.world.level.storage.loot.entries.SequentialEntry (Ljava/util/List;Ljava/util/List;)V +public net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction simpleBuilder(Ljava/util/function/Function;)Lnet/minecraft/world/level/storage/loot/functions/LootItemConditionalFunction$Builder; +public net.minecraft.world.level.storage.loot.functions.SetComponentsFunction (Ljava/util/List;Lnet/minecraft/core/component/DataComponentPatch;)V -public-f net.minecraft.data.recipes.RecipeProvider m_6055_()Ljava/lang/String; # getName +public-f net.minecraft.data.recipes.RecipeProvider getName()Ljava/lang/String; diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json new file mode 100644 index 00000000..98f18c36 --- /dev/null +++ b/src/main/resources/META-INF/coremods.json @@ -0,0 +1,6 @@ +{ + "holder_serialize": "coremods/holder_serialize.js", + "interact": "coremods/interact.js", + "level_load": "coremods/level_load.js", + "registry_load": "coremods/registry_load.js" +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/neoforge.mods.toml similarity index 71% rename from src/main/resources/META-INF/mods.toml rename to src/main/resources/META-INF/neoforge.mods.toml index 30cda807..1ca251b3 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -1,11 +1,11 @@ modLoader="javafml" -loaderVersion="[${fml},)" +loaderVersion="[4,)" license="APACHE-2.0" issueTrackerURL="https://github.com/ModdingX/LibX/issues" [[mods]] modId="libx" -version="${version}" +version="${mod.version}" displayName="LibX" displayURL="https://www.curseforge.com/minecraft/mc-mods/libx" updateJSONURL="https://assets.melanx.de/updates/libx.json" @@ -15,15 +15,15 @@ A library mod for minecraft. ''' [[dependencies.libx]] - modId="forge" - mandatory=true - versionRange="[${forge},)" + modId="neoforge" + type="required" + versionRange="[${mod.neoforge},)" ordering="NONE" side="BOTH" [[dependencies.libx]] modId="minecraft" - mandatory=true - versionRange="[${minecraft},)" + type="required" + versionRange="[${mod.minecraft},)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/assets/libx/lang/de_de.json b/src/main/resources/assets/libx/lang/de_de.json index e916c9c4..c40e2dd9 100644 --- a/src/main/resources/assets/libx/lang/de_de.json +++ b/src/main/resources/assets/libx/lang/de_de.json @@ -1,13 +1,13 @@ { "libx.misc.copy": "Klicke zum Kopieren.", - "libx.tooltip.fluidbase.bucket": "%seimer", + "libx.tooltip.fluid_base.bucket": "%seimer", "libx.gui.color_picker.red": "Rot: %s", "libx.gui.color_picker.green": "Grün: %s", "libx.gui.color_picker.blue": "Blau: %s", "libx.command.argument.enum.invalid": "Ungültiger %s-Wert: %s", - "libx.command.entitydata.modified": "NBT-Daten von %s Mobs wurden geändert.", - "libx.command.entitydata.modified_player": "NBT-Daten von %s Mobs wurden geändert. (Achtung: Du hast Spieler-NBT geändert))", - "libx.command.entitydata.player_modify_no_permission": "Nur Operatoren mit Berechtigungslevel 4 können Spieler-NBT bearbeiten.", + "libx.command.entity_data.modified": "NBT-Daten von %s Mobs wurden geändert.", + "libx.command.entity_data.modified_player": "NBT-Daten von %s Mobs wurden geändert. (Achtung: Du hast Spieler-NBT geändert))", + "libx.command.entity_data.player_modify_no_permission": "Nur Operatoren mit Berechtigungslevel 4 können Spieler-NBT bearbeiten.", "libx.command.reload.common": "Lade alle serverseitigen LibX-Konfigurationen neu.", "libx.command.reload.client": "Lade alle clientseitigen LibX-Konfigurationen neu.", "libx.config.editor.unsupported.title": "Nicht unterstützt", diff --git a/src/main/resources/assets/libx/lang/en_us.json b/src/main/resources/assets/libx/lang/en_us.json index c5c7b020..26d36ebc 100644 --- a/src/main/resources/assets/libx/lang/en_us.json +++ b/src/main/resources/assets/libx/lang/en_us.json @@ -1,13 +1,13 @@ { "libx.misc.copy": "Click to copy to clipboard.", - "libx.tooltip.fluidbase.bucket": "%s Bucket", + "libx.tooltip.fluid_base.bucket": "%s Bucket", "libx.gui.color_picker.red": "Red: %s", "libx.gui.color_picker.green": "Green: %s", "libx.gui.color_picker.blue": "Blue: %s", "libx.command.argument.enum.invalid": "Invalid %s value: %s", - "libx.command.entitydata.modified": "Modified data of %s entities", - "libx.command.entitydata.modified_player": "Modified data of %s entities. (Warning: You modified player nbt)", - "libx.command.entitydata.player_modify_no_permission": "Only Operators with permission level 4 can modify player NBT.", + "libx.command.entity_data.modified": "Modified data of %s entities", + "libx.command.entity_data.modified_player": "Modified data of %s entities. (Warning: You modified player nbt)", + "libx.command.entity_data.player_modify_no_permission": "Only Operators with permission level 4 can modify player NBT.", "libx.command.reload.common": "Reloading all LibX common configs.", "libx.command.reload.client": "Reloading all LibX client configs.", "libx.config.editor.unsupported.title": "Unsupported", diff --git a/src/main/resources/assets/libx/lang/pt_br.json b/src/main/resources/assets/libx/lang/pt_br.json index 1008ae11..037df2d7 100644 --- a/src/main/resources/assets/libx/lang/pt_br.json +++ b/src/main/resources/assets/libx/lang/pt_br.json @@ -1,13 +1,13 @@ { "libx.misc.copy": "Clique para copiar para a área de transferência.", - "libx.tooltip.fluidbase.bucket": "Balde %s", + "libx.tooltip.fluid_base.bucket": "Balde %s", "libx.gui.color_picker.red": "Vermelho: %s", "libx.gui.color_picker.green": "Verde: %s", "libx.gui.color_picker.blue": "Azul: %s", "libx.command.argument.enum.invalid": "Valor %s inválido: %s", - "libx.command.entitydata.modified": "Dados modificados de %s entidades", - "libx.command.entitydata.modified_player": "Dados modificados de %s entidades. (Aviso: você modificou o nbt do jogador)", - "libx.command.entitydata.player_modify_no_permission": "Somente Operadores com nível de permissão 4 podem modificar o NBT do jogador.", + "libx.command.entity_data.modified": "Dados modificados de %s entidades", + "libx.command.entity_data.modified_player": "Dados modificados de %s entidades. (Aviso: você modificou o nbt do jogador)", + "libx.command.entity_data.player_modify_no_permission": "Somente Operadores com nível de permissão 4 podem modificar o NBT do jogador.", "libx.command.reload.common": "Recarregando todas as configurações comuns do LibX.", "libx.command.reload.client": "Recarregando todas as configurações do cliente LibX.", "libx.config.editor.unsupported.title": "Sem Suporte", diff --git a/src/main/resources/coremods/holder_serialize.js b/src/main/resources/coremods/holder_serialize.js new file mode 100644 index 00000000..b1a79a65 --- /dev/null +++ b/src/main/resources/coremods/holder_serialize.js @@ -0,0 +1,37 @@ +function initializeCoreMod() { + var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var InsnList = Java.type('org.objectweb.asm.tree.InsnList'); + var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); + var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); + var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + + return { + 'holder_serialize': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraft.core.Holder$Reference', + 'methodName': 'canSerializeIn', + 'methodDesc': '(Lnet/minecraft/core/HolderOwner;)Z' + }, + 'transformer': function (method) { + var label = new LabelNode(); + var target = new InsnList(); + target.add(new VarInsnNode(Opcodes.ALOAD, 0)); + target.add(new VarInsnNode(Opcodes.ALOAD, 1)); + target.add(ASMAPI.buildMethodCall( + 'org/moddingx/libx/impl/libxcore/CoreHolderSerialize', 'forceSerializeIn', + '(Lnet/minecraft/core/Holder$Reference;Lnet/minecraft/core/HolderOwner;)Z', + ASMAPI.MethodType.STATIC + )); + target.add(new JumpInsnNode(Opcodes.IFEQ, label)); + target.add(new InsnNode(Opcodes.ICONST_1)); + target.add(new InsnNode(Opcodes.IRETURN)); + target.add(label); + method.instructions.insert(target); + return method; + } + } + }; +} diff --git a/src/main/resources/coremods/interact.js b/src/main/resources/coremods/interact.js new file mode 100644 index 00000000..94d011e4 --- /dev/null +++ b/src/main/resources/coremods/interact.js @@ -0,0 +1,47 @@ +function initializeCoreMod() { + var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var InsnList = Java.type('org.objectweb.asm.tree.InsnList'); + var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); + var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); + var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + + return { + 'interact': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraft.server.level.ServerPlayerGameMode', + 'methodName': 'useItemOn', + 'methodDesc': '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;' + }, + 'transformer': function (method) { + var label = new LabelNode(); + var target = new InsnList(); + target.add(new VarInsnNode(Opcodes.ALOAD, 1)); + target.add(new VarInsnNode(Opcodes.ALOAD, 2)); + target.add(new VarInsnNode(Opcodes.ALOAD, 3)); + target.add(new VarInsnNode(Opcodes.ALOAD, 4)); + target.add(new VarInsnNode(Opcodes.ALOAD, 5)); + target.add(ASMAPI.buildMethodCall( + 'org/moddingx/libx/impl/libxcore/CoreInteract', 'useItemOn', + '(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;', + ASMAPI.MethodType.STATIC + )); + target.add(new InsnNode(Opcodes.DUP)); + target.add(new JumpInsnNode(Opcodes.IFNULL, label)); + target.add(new InsnNode(Opcodes.ARETURN)); + target.add(label); + target.add(new InsnNode(Opcodes.POP)); + for (var i = method.instructions.size() - 1; i >= 0; i--) { + var inst = method.instructions.get(i); + if (inst != null && inst.getOpcode() == Opcodes.ARETURN) { + method.instructions.insertBefore(inst, target); + return method; + } + } + throw new Error("Failed to patch ServerPlayerGameMode.class"); + } + } + }; +} diff --git a/src/coremods/coremods/level_load.js b/src/main/resources/coremods/level_load.js similarity index 54% rename from src/coremods/coremods/level_load.js rename to src/main/resources/coremods/level_load.js index 58d57615..47b41f30 100644 --- a/src/coremods/coremods/level_load.js +++ b/src/main/resources/coremods/level_load.js @@ -1,7 +1,10 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var coremods_1 = require("coremods"); function initializeCoreMod() { + var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var InsnList = Java.type('org.objectweb.asm.tree.InsnList'); + var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + return { 'level_load': { 'target': { @@ -11,15 +14,19 @@ function initializeCoreMod() { 'methodDesc': '(Lnet/minecraft/server/MinecraftServer;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lnet/minecraft/world/level/storage/ServerLevelData;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/level/dimension/LevelStem;Lnet/minecraft/server/level/progress/ChunkProgressListener;ZJLjava/util/List;ZLnet/minecraft/world/RandomSequences;)V' }, 'transformer': function (method) { - var target = new coremods_1.InsnList(); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.DUP)); - target.add(new coremods_1.VarInsnNode(coremods_1.Opcodes.ALOAD, 1)); - target.add(new coremods_1.MethodInsnNode(coremods_1.Opcodes.INVOKESTATIC, 'org/moddingx/libx/impl/libxcore/CoreLevelLoad', 'startLevelLoad', '(Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/MinecraftServer;)V')); + var target = new InsnList(); + target.add(new InsnNode(Opcodes.DUP)); + target.add(new VarInsnNode(Opcodes.ALOAD, 1)); + target.add(ASMAPI.buildMethodCall( + 'org/moddingx/libx/impl/libxcore/CoreLevelLoad', 'startLevelLoad', + '(Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/MinecraftServer;)V', + ASMAPI.MethodType.STATIC + )); for (var i = 0; i < method.instructions.size(); i++) { var node = method.instructions.get(i); - if (node.getOpcode() == coremods_1.Opcodes.INVOKEVIRTUAL) { + if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) { var methodNode = node; - if (methodNode.owner == 'net/minecraft/world/level/dimension/LevelStem' && methodNode.name == coremods_1.ASMAPI.mapField('f_63976_') /* record method */ && methodNode.desc == '()Lnet/minecraft/world/level/chunk/ChunkGenerator;') { + if (methodNode.owner == 'net/minecraft/world/level/dimension/LevelStem' && methodNode.name == 'generator' && methodNode.desc == '()Lnet/minecraft/world/level/chunk/ChunkGenerator;') { method.instructions.insert(node, target); return method; } diff --git a/src/coremods/coremods/registry_load.js b/src/main/resources/coremods/registry_load.js similarity index 50% rename from src/coremods/coremods/registry_load.js rename to src/main/resources/coremods/registry_load.js index 3d21813a..6e45286b 100644 --- a/src/coremods/coremods/registry_load.js +++ b/src/main/resources/coremods/registry_load.js @@ -1,31 +1,40 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var coremods_1 = require("coremods"); function initializeCoreMod() { + var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI'); + var Opcodes = Java.type('org.objectweb.asm.Opcodes'); + var InsnList = Java.type('org.objectweb.asm.tree.InsnList'); + var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); + var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); + var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode'); + var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); + return { 'registry_load': { 'target': { 'type': 'METHOD', 'class': 'net.minecraft.server.WorldLoader', - 'methodName': 'm_214362_', + 'methodName': 'load', 'methodDesc': '(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;' }, 'transformer': function (method) { - var target = new coremods_1.InsnList(); - target.add(new coremods_1.InsnNode(coremods_1.Opcodes.DUP)); - target.add(new coremods_1.MethodInsnNode(coremods_1.Opcodes.INVOKESTATIC, 'org/moddingx/libx/impl/libxcore/CoreRegistryLoad', 'afterWorldGenLayerLoad', '(Lnet/minecraft/core/LayeredRegistryAccess;)V')); + var target = new InsnList(); + target.add(new InsnNode(Opcodes.DUP)); + target.add(ASMAPI.buildMethodCall( + 'org/moddingx/libx/impl/libxcore/CoreRegistryLoad', 'afterWorldGenLayerLoad', + '(Lnet/minecraft/core/LayeredRegistryAccess;)V', + ASMAPI.MethodType.STATIC + )); var foundWorldGenField = false; for (var i = 0; i < method.instructions.size(); i++) { var node = method.instructions.get(i); - if (node.getOpcode() == coremods_1.Opcodes.GETSTATIC && !foundWorldGenField) { + if (node.getOpcode() == Opcodes.GETSTATIC && !foundWorldGenField) { var fieldNode = node; if (fieldNode.owner == 'net/minecraft/server/RegistryLayer' && fieldNode.name == 'WORLDGEN') { foundWorldGenField = true; } } - else if (node.getOpcode() == coremods_1.Opcodes.INVOKESTATIC && foundWorldGenField) { + else if (node.getOpcode() == Opcodes.INVOKESTATIC && foundWorldGenField) { var methodNode = node; - if (methodNode.owner == 'net/minecraft/server/WorldLoader' && methodNode.name == coremods_1.ASMAPI.mapMethod('m_245736_') && methodNode.desc == '(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/LayeredRegistryAccess;Lnet/minecraft/server/RegistryLayer;Ljava/util/List;)Lnet/minecraft/core/LayeredRegistryAccess;') { + if (methodNode.owner == 'net/minecraft/server/WorldLoader' && methodNode.name == 'loadAndReplaceLayer' && methodNode.desc == '(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/LayeredRegistryAccess;Lnet/minecraft/server/RegistryLayer;Ljava/util/List;)Lnet/minecraft/core/LayeredRegistryAccess;') { method.instructions.insert(node, target); return method; } diff --git a/src/sourcegen/java/org/moddingx/libx/sourcegen/LibXSourceGen.java b/src/sourcegen/java/org/moddingx/libx/sourcegen/LibXSourceGen.java index a51e76a6..f749a63a 100644 --- a/src/sourcegen/java/org/moddingx/libx/sourcegen/LibXSourceGen.java +++ b/src/sourcegen/java/org/moddingx/libx/sourcegen/LibXSourceGen.java @@ -2,15 +2,15 @@ import net.minecraft.core.registries.Registries; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.data.event.GatherDataEvent; -@Mod("libx_sourcegen") +@Mod("libx") public class LibXSourceGen { - public LibXSourceGen() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::gatherData); + public LibXSourceGen(IEventBus modBus) { + modBus.addListener(this::gatherData); } private void gatherData(GatherDataEvent event) { diff --git a/src/sourcegen/java/org/moddingx/libx/sourcegen/RegistryKeyProvider.java b/src/sourcegen/java/org/moddingx/libx/sourcegen/RegistryKeyProvider.java index 23f39d21..2cc1fd2b 100644 --- a/src/sourcegen/java/org/moddingx/libx/sourcegen/RegistryKeyProvider.java +++ b/src/sourcegen/java/org/moddingx/libx/sourcegen/RegistryKeyProvider.java @@ -8,7 +8,7 @@ import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.data.event.GatherDataEvent; +import net.neoforged.neoforge.data.event.GatherDataEvent; import javax.annotation.Nonnull; import java.io.File; @@ -70,7 +70,7 @@ public CompletableFuture run(@Nonnull CachedOutput output) { sourceFile.append("import ").append(this.registryClass.getName().replace('$', '.')).append(";\n\n"); sourceFile.append("public class ").append(this.className).append(" {\n\n"); sourceFile.append(" private ").append(this.className).append("() {}\n\n"); - sourceFile.append(" private static final ResourceKey> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(") + sourceFile.append(" private static final ResourceKey> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(") .append(quote(this.registry.location().getNamespace())).append(",").append(quote(this.registry.location().getPath())) .append("));\n\n"); for (ResourceLocation key : lookup.listElementIds().map(ResourceKey::location).sorted(ResourceLocation::compareNamespaced).toList()) { @@ -88,7 +88,7 @@ public CompletableFuture run(@Nonnull CachedOutput output) { } } String fn = fnb.toString(); - sourceFile.append(" public static final ResourceKey<").append(type).append("> ").append(fn).append(" = ResourceKey.create(REGISTRY, new ResourceLocation(") + sourceFile.append(" public static final ResourceKey<").append(type).append("> ").append(fn).append(" = ResourceKey.create(REGISTRY, ResourceLocation.fromNamespaceAndPath(") .append(quote(key.getNamespace())).append(",").append(quote(key.getPath())) .append("));\n"); } diff --git a/src/sourcegen/resources/META-INF/mods.toml b/src/sourcegen/resources/META-INF/mods.toml deleted file mode 100644 index a063f77c..00000000 --- a/src/sourcegen/resources/META-INF/mods.toml +++ /dev/null @@ -1,8 +0,0 @@ -modLoader="javafml" -loaderVersion="[0,)" -license="APACHE-2.0" - -[[mods]] -modId="libx_sourcegen" -version="${file.jarVersion}" -displayName="LibX SourceGen" diff --git a/src/test/java/org/moddingx/libx/test/AccessTransformerTest.java b/src/test/java/org/moddingx/libx/test/AccessTransformerTest.java index 9dd0a273..6625492c 100644 --- a/src/test/java/org/moddingx/libx/test/AccessTransformerTest.java +++ b/src/test/java/org/moddingx/libx/test/AccessTransformerTest.java @@ -2,14 +2,12 @@ import org.junit.jupiter.api.Test; import org.moddingx.libx.LibX; -import org.moddingx.libx.test.util.Mappings; import org.objectweb.asm.Type; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.List; import java.util.Objects; -import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -22,9 +20,9 @@ public class AccessTransformerTest { private static final String CLASS_NAME = Pattern.compile(IDENT + "(?:\\." + IDENT + ")*").pattern(); private static final Pattern CLASS_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")"); - private static final Pattern FIELD_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+(" + IDENT + ")\\s*#\\s*(" + IDENT + ")"); - private static final Pattern CTOR_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+\\s*(.+?)(\\s*?:#\\s*)?"); - private static final Pattern METHOD_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+(" + IDENT + ")\\s*(.+?)\\s*#\\s*(" + IDENT + ")"); + private static final Pattern FIELD_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+(" + IDENT + ")"); + private static final Pattern CTOR_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+\\s*(.+?)"); + private static final Pattern METHOD_PATTERN = Pattern.compile("(?U)" + ACCESS + "\\s+(" + CLASS_NAME + ")\\s+(" + IDENT + ")\\s*(.+?)"); @Test public void testAT() throws Throwable { @@ -38,7 +36,7 @@ public void testAT() throws Throwable { } m = FIELD_PATTERN.matcher(line); if (m.matches()) { - this.testField(m.group(1), m.group(2), m.group(3)); + this.testField(m.group(1), m.group(2)); continue; } m = CTOR_PATTERN.matcher(line); @@ -48,7 +46,7 @@ public void testAT() throws Throwable { } m = METHOD_PATTERN.matcher(line); if (m.matches()) { - this.testMethod(m.group(1), m.group(2), m.group(3), m.group(4)); + this.testMethod(m.group(1), m.group(2), m.group(3)); continue; } fail("AccessTransformer line matches no pattern. Is the comment with the mapped name missing? " + line); @@ -60,10 +58,9 @@ private Class testClass(String name) { return assertDoesNotThrow(() -> Class.forName(name, false, ClassLoader.getSystemClassLoader()), "Class in AccessTransformer not found: " + name); } - private void testField(String clsName, String srg, String mapped) { + private void testField(String clsName, String name) { Class cls = this.testClass(clsName); - String actualName = this.testRemap(srg, mapped, "field", n -> Mappings.remapField(cls, n)); - assertDoesNotThrow(() -> cls.getDeclaredField(actualName), "Unknown field in accesstransformer: " + clsName + "#" + srg + " (" + actualName + ")"); + assertDoesNotThrow(() -> cls.getDeclaredField(name), "Unknown field in accesstransformer: " + clsName + "#" + name); } private void testConstructor(String clsName, String descriptor) { @@ -72,11 +69,10 @@ private void testConstructor(String clsName, String descriptor) { assertDoesNotThrow(() -> cls.getDeclaredConstructor(args), "Unknown constructor in accesstransformer: " + clsName + "#" + descriptor + " ()"); } - private void testMethod(String clsName, String srg, String descriptor, String mapped) { + private void testMethod(String clsName, String name, String descriptor) { Class cls = this.testClass(clsName); Class[] args = this.resolveArgs(descriptor); - String actualName = this.testRemap(srg, mapped, "method", n -> Mappings.remapMethod(cls, n, descriptor)); - assertDoesNotThrow(() -> cls.getDeclaredMethod(actualName, args), "Unknown method in accesstransformer: " + clsName + "#" + srg + descriptor + " (" + actualName + ")"); + assertDoesNotThrow(() -> cls.getDeclaredMethod(name, args), "Unknown method in accesstransformer: " + clsName + "#" + name + descriptor); } private Class[] resolveArgs(String descriptor) { @@ -112,10 +108,4 @@ private Class resolveClassType(Type type) { default -> fail("Unknown type in method descriptor: " + type); }; } - - private String testRemap(String srg, String mapped, String domain, Function remap) { - String mappedName = assertDoesNotThrow(() -> remap.apply(srg), "Failed to remap name: " + srg); - assertEquals(mappedName, mapped, "Mapped " + domain + " name mismatch in accesstransformer: " + srg); - return mappedName; - } } diff --git a/src/test/java/org/moddingx/libx/test/FilterGuiGraphicsTest.java b/src/test/java/org/moddingx/libx/test/FilterGuiGraphicsTest.java index be806199..40e31f8d 100644 --- a/src/test/java/org/moddingx/libx/test/FilterGuiGraphicsTest.java +++ b/src/test/java/org/moddingx/libx/test/FilterGuiGraphicsTest.java @@ -1,7 +1,7 @@ package org.moddingx.libx.test; import net.minecraft.client.gui.GuiGraphics; -import net.minecraftforge.client.extensions.IForgeGuiGraphics; +import net.neoforged.neoforge.client.extensions.IGuiGraphicsExtension; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.moddingx.libx.render.FilterGuiGraphics; @@ -16,7 +16,7 @@ public class FilterGuiGraphicsTest { @Test public void testThatAllMethodsAreOverridden() { - List methodsToOverride = Stream.of(GuiGraphics.class, IForgeGuiGraphics.class) + List methodsToOverride = Stream.of(GuiGraphics.class, IGuiGraphicsExtension.class) .flatMap(cls -> Arrays.stream(cls.getDeclaredMethods())) .filter(m -> Modifier.isPublic(m.getModifiers()) || Modifier.isProtected(m.getModifiers())) .filter(m -> !Modifier.isStatic(m.getModifiers())) // Do not filter final methods, these need to be ATed diff --git a/src/test/java/org/moddingx/libx/test/ReflectionHacksTest.java b/src/test/java/org/moddingx/libx/test/ReflectionHacksTest.java index 58e0aafa..b219d262 100644 --- a/src/test/java/org/moddingx/libx/test/ReflectionHacksTest.java +++ b/src/test/java/org/moddingx/libx/test/ReflectionHacksTest.java @@ -4,7 +4,6 @@ import org.moddingx.libx.impl.reflect.ReflectionHacks; import java.io.IOException; -import java.util.Date; import static org.junit.jupiter.api.Assertions.*; @@ -13,28 +12,7 @@ public class ReflectionHacksTest { public static final WrappedString staticField = new WrappedString("Hello, world!"); @Test - public void testReflectionHacks() throws Throwable { - A a = new A("aaa", 42); - B b = new B("bbb"); - - ReflectionHacks.setFinalField(ReflectionHacksTest.class.getField("staticField"), null, new WrappedString("Changed!")); - assertEquals(new WrappedString("Changed!"), staticField, "Static final field was not changed."); - - ReflectionHacks.setFinalField(A.class.getField("field"), a, "Changed!"); - assertEquals("Changed!", a.field, "Final instance field was not changed."); - - ReflectionHacks.setFinalField(A.class.getField("primitive"), a, 17); - assertEquals(17, a.primitive, "Primitive final instance field was not changed."); - - ReflectionHacks.setFinalField(A.class.getField("field"), a, null); - assertNull(a.field, "Static final field was not changed."); - - assertThrows(NullPointerException.class, () -> ReflectionHacks.setFinalField(A.class.getField("field"), null, "")); - assertThrows(IllegalArgumentException.class, () -> ReflectionHacks.setFinalField(A.class.getField("field"), b, "")); - assertThrows(NullPointerException.class, () -> ReflectionHacks.setFinalField(A.class.getField("primitive"), a, null)); - assertThrows(ClassCastException.class, () -> ReflectionHacks.setFinalField(A.class.getField("field"), a, new Date())); - assertThrows(IllegalArgumentException.class, () -> ReflectionHacks.setFinalField(C.class.getField("VALUE"), null, null)); - + public void testReflectionHacks() { assertThrows(IOException.class, () -> ReflectionHacks.throwUnchecked(new IOException()), "ReflectionHacks.throwUnchecked did not throw an IOException"); ClassWithThrowingConstructor emptyInstance = assertDoesNotThrow(() -> ReflectionHacks.newInstance(ClassWithThrowingConstructor.class), "ReflectionHacks.newInstance threw an exception"); @@ -42,34 +20,10 @@ public void testReflectionHacks() throws Throwable { assertNull(emptyInstance.value, "ReflectionHacks.newInstance did not produce an empty object"); } - private static class A { - - public final String field; - public final int primitive; - - private A(String field, int primitive) { - this.field = field; - this.primitive = primitive; - } - } - - private static class B { - - public final String field; - - private B(String field) { - this.field = field; - } - } - - private enum C { - VALUE - } - // Can't use strings in static final fields as they are inlined by the compiler. - private record WrappedString(String value) {} - - private static class ClassWithThrowingConstructor { + public record WrappedString(String value) {} + + public static class ClassWithThrowingConstructor { public final WrappedString value = new WrappedString(""); diff --git a/src/test/java/org/moddingx/libx/test/ResourcePackTest.java b/src/test/java/org/moddingx/libx/test/ResourcePackTest.java deleted file mode 100644 index 2b996bc7..00000000 --- a/src/test/java/org/moddingx/libx/test/ResourcePackTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.moddingx.libx.test; - -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import net.minecraft.SharedConstants; -import org.junit.jupiter.api.Test; -import org.moddingx.libx.LibX; - -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.Objects; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -// Test the datapack version in pack.mcmeta and the version for dynamic datapacks -public class ResourcePackTest { - - @Test - @SuppressWarnings("deprecation") - public void testPackVersion() throws Throwable { - try (Reader in = new InputStreamReader(Objects.requireNonNull(LibX.class.getResourceAsStream("/pack.mcmeta"), "pack.mcmeta file not found"))) { - JsonObject packInfo = new GsonBuilder().create().fromJson(in, JsonObject.class); - int mainPackVersion = packInfo.get("pack").getAsJsonObject().get("pack_format").getAsInt(); - int resourcePackVersion = packInfo.get("pack").getAsJsonObject().get("forge:client_resources_pack_format").getAsInt(); - int dataPackVersion = packInfo.get("pack").getAsJsonObject().get("forge:server_data_pack_format").getAsInt(); - assertEquals(Math.max(SharedConstants.RESOURCE_PACK_FORMAT, SharedConstants.DATA_PACK_FORMAT), mainPackVersion, "pack.mcmeta does not match current resource/data version"); - assertEquals(SharedConstants.RESOURCE_PACK_FORMAT, resourcePackVersion, "pack.mcmeta does not match current resource version"); - assertEquals(SharedConstants.DATA_PACK_FORMAT, dataPackVersion, "pack.mcmeta does not match current data version"); - } - } -} diff --git a/src/test/java/org/moddingx/libx/test/util/Mappings.java b/src/test/java/org/moddingx/libx/test/util/Mappings.java deleted file mode 100644 index 3f6c5e03..00000000 --- a/src/test/java/org/moddingx/libx/test/util/Mappings.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.moddingx.libx.test.util; - -import net.minecraftforge.srgutils.IMappingFile; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Optional; - -public class Mappings { - - private static IMappingFile mappings; - - public static String remapField(Class cls, String srg) { - loadMappings(); - return getMappedClass(cls).map(c -> c.remapField(srg)).orElse(srg); - } - - public static String remapMethod(Class cls, String srg, String descriptor) { - loadMappings(); - return getMappedClass(cls).map(c -> c.remapMethod(srg, descriptor)).orElse(srg); - } - - private static Optional getMappedClass(Class cls) { - IMappingFile.IClass mapped = mappings.getClass(cls.getName().replace('.', '/')); - return Optional.ofNullable(mapped); - } - - private static void loadMappings() { - if (mappings == null) { - Path mappingsPath = Paths.get("build", "createSrgToMcp", "output.srg").toAbsolutePath().normalize(); - if (!Files.exists(mappingsPath)) throw new IllegalStateException("Mappings have not been created by ForgeGradle: " + mappingsPath); - try (InputStream in = Files.newInputStream(mappingsPath)) { - mappings = IMappingFile.load(in); - } catch (IOException e) { - throw new IllegalStateException("Failed to load mappings from " + mappingsPath, e); - } - } - } -}