From 6a94fa1e329b01cde9aae387142a0991b69c2c91 Mon Sep 17 00:00:00 2001 From: alpha Date: Sat, 13 Jul 2024 23:26:37 -0500 Subject: [PATCH] WIP 1.21 refactors --- README.md | 1 - build.gradle | 14 +- gradle.properties | 6 + .../client/accessor/ModelBakeryAccessor.java | 20 - .../accessor/PotionBrewing$MixAccessor.java | 20 - .../porting_lib_accessors.mixins.json | 10 +- modules/base/build.gradle | 1 - .../porting_lib/PortingLibBase.java | 9 +- ...bClient.java => PortingLibBaseClient.java} | 19 +- .../CustomDataPacketHandlingBlockEntity.java | 19 +- .../porting_lib/block/CustomExpBlock.java | 27 +- .../block/CustomRunningEffectsBlock.java | 15 +- .../CustomUpdateTagHandlingBlockEntity.java | 12 +- .../event/client/ClientWorldEvents.java | 35 - .../client/TextureAtlasStitchedEvent.java | 49 + .../event/client/TextureStitchCallback.java | 19 - .../event/common/AddPackFindersCallback.java | 21 - .../event/common/AdvancementEvent.java | 4 +- .../event/common/AttackAirCallback.java | 22 - .../porting_lib/event/common/BlockEvents.java | 206 --- ...dstoneEvents.java => GrindstoneEvent.java} | 90 +- .../event/common/PotionEvents.java | 41 - .../event/common/TagsUpdatedCallback.java | 14 - .../event/common/TagsUpdatedEvent.java | 72 + .../fixes/ForgeBlockEntityFix.java | 31 + .../porting_lib/item/ArmorTextureItem.java | 29 +- .../porting_lib/item/ContinueUsingItem.java | 6 +- .../porting_lib/item/CustomMaxCountItem.java | 7 - .../porting_lib/item/DamageableItem.java | 14 +- .../mixin/client/ClientLevelMixin.java | 2 +- .../client/ClientPacketListenerMixin.java | 7 - .../mixin/client/HumanoidArmorLayerMixin.java | 35 +- .../mixin/client/MinecraftMixin.java | 35 - .../mixin/client/TagCollectorMixin.java | 19 + .../mixin/client/TextureAtlasMixin.java | 11 +- .../common/BlockBehavior$PropertiesMixin.java | 2 +- .../mixin/common/BlockEntityMixin.java | 37 +- .../mixin/common/BlockItemMixin.java | 50 - .../mixin/common/ChunkStatusMixin.java | 16 - .../mixin/common/DataFixersMixin.java | 22 + .../mixin/common/EnchantmentHelperMixin.java | 133 +- .../mixin/common/EnchantmentMenuMixin.java | 8 +- .../porting_lib/mixin/common/EntityMixin.java | 17 +- .../mixin/common/GrindstoneMenuMixin.java | 23 +- .../mixin/common/ItemStackMixin.java | 55 +- .../mixin/common/LevelChunkMixin.java | 4 +- .../porting_lib/mixin/common/LevelMixin.java | 49 +- .../mixin/common/LivingEntityMixin.java | 47 +- .../mixin/common/MobEffectInstanceMixin.java | 43 - .../mixin/common/PackRepositoryMixin.java | 33 - .../porting_lib/mixin/common/PlayerMixin.java | 16 - .../ReloadableServerResourcesMixin.java | 16 +- .../mixin/common/SpawnEggItemMixin.java | 30 + .../mixin/common/StartAttackingMixin.java | 56 - .../util/AbstractSpawnerHelper.java | 2 +- .../util/ArmorTextureRegistry.java | 25 - .../porting_lib/util/BiomeManagerHelper.java | 2 +- .../porting_lib/util/BlockEntityHelper.java | 2 +- .../porting_lib/util/BlockSnapshot.java | 182 --- ...EggItem.java => DeferredSpawnEggItem.java} | 84 +- .../porting_lib/util/FontRenderUtil.java | 2 +- .../porting_lib/util/GameRendererHelper.java | 2 +- .../porting_lib/util/ItemRendererHelper.java | 2 +- .../porting_lib/util/KeyBindingHelper.java | 2 +- .../porting_lib/util/LazyOptional.java | 159 --- .../porting_lib/util/MinecartAndRailUtil.java | 2 +- .../porting_lib/util/MinecraftServerUtil.java | 2 +- .../porting_lib/util/NBTSerializer.java | 22 - .../porting_lib/util/PlayerEntityHelper.java | 2 +- .../porting_lib/util/PortingHooks.java | 129 +- .../porting_lib/util/PotionHelper.java | 32 - .../porting_lib/util/SimpleFlowableFluid.java | 200 --- .../porting_lib/util/TierSortingRegistry.java | 354 ----- .../porting_lib/util/client/ClientHooks.java | 90 +- .../{ForgeSlider.java => ExtendedSlider.java} | 60 +- .../porting_lib/util/client/ScreenUtils.java | 287 ---- .../porting_lib/util/client/ScrollPanel.java | 219 ++-- .../base/src/main/resources/fabric.mod.json | 2 +- .../resources/porting_lib_base.accesswidener | 2 + .../resources/porting_lib_base.mixins.json | 11 +- .../porting_lib/brewing/BrewingHandler.java | 28 - .../porting_lib/brewing/BrewingRecipe.java | 10 +- .../brewing/BrewingRecipeRegistry.java | 94 +- .../porting_lib/brewing/IBrewingRecipe.java | 7 +- .../brewing/RegisterBrewingRecipesEvent.java | 35 + .../brewing/VanillaBrewingRecipe.java | 49 - .../brewing/ext/PotionBrewingBuilderExt.java | 26 + .../brewing/ext/PotionBrewingExt.java | 33 + .../mixin/BrewingStandBlockEntityMixin.java | 77 +- ...BrewingStandMenu$IngredientsSlotMixin.java | 10 +- .../BrewingStandMenu$PotionSlotMixin.java | 10 +- .../brewing/mixin/PotionBrewingMixin.java | 107 ++ .../src/main/resources/fabric.mod.json | 8 +- .../porting_lib_brewing.accesswidener | 3 + .../resources/porting_lib_brewing.mixins.json | 4 +- .../chunk/loading/PortingLibChunkManager.java | 16 +- .../loading/mixin/MinecraftServerMixin.java | 2 +- .../porting_lib/common/PortingLibCommon.java | 11 + .../common/ext/LanguageManagerExt.java | 14 + .../extensions/LanguageManagerExtensions.java | 18 - .../mixin/client/LanguageManagerMixin.java | 15 +- .../client/accessor/MinecraftAccessor.java | 15 - .../porting_lib/common}/util/EnvExecutor.java | 2 +- .../common/util/FriendlyByteBufUtil.java | 33 + .../common/util/MinecraftClientUtil.java | 28 - .../common/util/NonNullConsumer.java | 16 - .../common/util/NonNullFunction.java | 12 - .../common/util/NonNullSupplier.java | 20 - .../common}/util/SimpleRecipeType.java | 2 +- .../porting_lib/common}/util/SimpleTier.java | 2 +- .../common}/util/TrueCondition.java | 2 +- .../common/src/main/resources/fabric.mod.json | 7 +- .../porting_lib_common.accesswidener} | 0 .../resources/porting_lib_common.mixins.json | 3 +- .../porting_lib/core/PortingLib.java | 4 + .../core/client/PortingLibClient.java | 12 + .../porting_lib/core/event/BaseEvent.java | 58 +- .../core/event/CancellableEvent.java | 44 + .../core/util/INBTSerializable.java | 17 +- .../core}/util/LogicalSidedProvider.java | 2 +- .../porting_lib/core}/util/MixinHelper.java | 2 +- .../core}/util/ServerLifecycleHooks.java | 2 +- .../core/src/main/resources/fabric.mod.json | 10 +- modules/data/build.gradle | 2 +- .../porting_lib/entity/EffectCure.java | 65 + .../porting_lib/entity/EffectCures.java | 20 + .../porting_lib/entity/EntityHooks.java | 441 +++++++ .../entity/IEntityAdditionalSpawnData.java | 29 - .../entity/IEntityWithComplexSpawn.java | 25 + .../porting_lib/entity/ITeleporter.java | 84 -- .../porting_lib/entity/PartEntity.java | 3 +- .../porting_lib/entity/PortingLibEntity.java | 63 +- .../entity/client/PortingLibEntityClient.java | 41 +- .../entity/events/CriticalHitEvent.java | 85 -- .../entity/events/EntityEvent.java | 201 +++ .../entity/events/EntityEventFactory.java | 62 - .../entity/events/EntityEvents.java | 212 --- .../entity/events/EntityInteractCallback.java | 30 - .../entity/events/EntityJoinLevelEvent.java | 67 + .../entity/events/EntityMountEvent.java | 66 + .../entity/events/EntityMountEvents.java | 57 - .../events/EntityReadExtraDataCallback.java | 18 - .../events/EntityStruckByLightningEvent.java | 21 +- .../entity/events/EntityTeleportEvent.java | 279 ++++ .../entity/events/LivingEntityEvents.java | 395 ------ .../events/LivingEntityUseItemEvents.java | 25 - .../events/MobEntitySetTargetCallback.java | 15 - .../entity/events/PlayerEvents.java | 161 --- .../events/PlayerInteractionEvents.java | 193 --- .../entity/events/PlayerTickEvents.java | 29 - .../events/ProjectileImpactCallback.java | 22 - .../entity/events/ProjectileImpactEvent.java | 53 +- .../{ => living}/LivingAttackEvent.java | 27 +- .../living/LivingChangeTargetEvent.java | 113 ++ .../events/living/LivingDamageEvent.java | 3 +- .../events/{ => living}/LivingDeathEvent.java | 16 +- .../events/living/LivingDropsEvent.java | 64 + .../living/LivingEntityUseItemEvent.java | 162 +++ .../entity/events/living/LivingEvent.java | 109 ++ .../living/LivingExperienceDropEvent.java | 62 + .../entity/events/living/LivingFallEvent.java | 62 + .../entity/events/living/LivingHurtEvent.java | 24 +- .../events/living/LivingKnockBackEvent.java | 92 ++ .../events/living/LivingUseTotemEvent.java | 68 + .../entity/events/living/MobEffectEvent.java | 183 ++- .../events/{ => living}/ShieldBlockEvent.java | 18 +- .../events/player/AttackEntityEvent.java | 21 +- .../events/player/CriticalHitEvent.java | 111 ++ .../events/player/PlayerDestroyItemEvent.java | 73 ++ .../entity/events/player/PlayerEvent.java | 639 +++++++++ .../events/player/PlayerInteractEvent.java | 536 ++++++++ .../entity/events/player/PlayerXpEvent.java | 120 ++ .../entity/events/tick/EntityTickEvent.java | 81 ++ .../entity/events/tick/PlayerTickEvent.java | 82 ++ .../AbstractMinecartExt.java} | 4 +- .../porting_lib/entity/ext/EntityExt.java | 48 + .../ItemExtensions.java => ext/ItemExt.java} | 27 +- .../LevelExt.java} | 4 +- .../entity/ext/LivingEntityExt.java | 14 + .../porting_lib/entity/ext/MobEffectExt.java | 29 + .../entity/ext/MobEffectInstanceExt.java | 12 + .../PlayerExt.java} | 4 +- .../SlimeExtension.java => ext/SlimeExt.java} | 4 +- .../entity/extensions/EntityExtensions.java | 37 - .../extensions/MobEffectExtensions.java | 12 - .../accessor/PlayerDataStorageAccessor.java | 14 + .../entity/mixin/client/ClientLevelMixin.java | 34 +- .../EffectRenderingInventoryScreenMixin.java | 26 +- .../client/EntityRenderDispatcherMixin.java | 10 +- .../entity/mixin/client/GuiMixin.java | 20 +- .../entity/mixin/client/LocalPlayerMixin.java | 6 +- .../entity/mixin/client/MinecraftMixin.java | 22 +- .../client/MultiPlayerGameModeMixin.java | 94 +- .../mixin/client/RemotePlayerMixin.java | 6 +- .../mixin/common/AbstractArrowMixin.java | 106 +- .../mixin/common/AbstractHorseMixin.java | 6 +- .../AbstractHurtingProjectileMixin.java | 15 +- .../mixin/common/AbstractMinecartMixin.java | 4 +- .../mixin/common/BundlePacketMixin.java | 4 +- .../entity/mixin/common/CatSpawnerMixin.java | 29 - .../mixin/common/ChorusFruitItemMixin.java | 38 +- .../entity/mixin/common/EnderManMixin.java | 24 +- .../entity/mixin/common/EntityMixin.java | 124 +- .../mixin/common/ExperienceOrbMixin.java | 7 +- .../common/FireworkRocketEntityMixin.java | 20 +- .../entity/mixin/common/FishingHookMixin.java | 15 +- .../mixin/common/FurnaceResultSlotMixin.java | 26 + .../entity/mixin/common/ItemMixin.java | 4 +- .../entity/mixin/common/LevelMixin.java | 8 +- .../mixin/common/LightningBoltMixin.java | 10 +- .../mixin/common/LivingEntityMixin.java | 314 +++-- .../entity/mixin/common/LlamaSpitMixin.java | 17 +- .../entity/mixin/common/MagmaCubeMixin.java | 6 +- .../mixin/common/MobEffectInstanceMixin.java | 40 + .../entity/mixin/common/MobEffectMixin.java | 4 +- .../entity/mixin/common/MobMixin.java | 31 +- .../mixin/common/NaturalSpawnerMixin.java | 63 - .../mixin/common/PatrolSpawnerMixin.java | 25 - ...entEntitySectionManager$CallbackMixin.java | 9 +- .../PersistentEntitySectionManagerMixin.java | 10 +- .../mixin/common/PhantomSpawnerMixin.java | 33 - .../mixin/common/PlayerDataStorageMixin.java | 33 + .../entity/mixin/common/PlayerListMixin.java | 27 +- .../entity/mixin/common/PlayerMixin.java | 141 +- .../mixin/common/PortalForcerMixin.java | 12 - .../entity/mixin/common/ProjectileMixin.java | 20 - .../entity/mixin/common/ResultSlotMixin.java | 35 + .../mixin/common/ServerEntityMixin.java | 26 +- .../ServerGamePacketListenerImpl$1Mixin.java | 24 + .../entity/mixin/common/ServerLevelMixin.java | 36 +- .../common/ServerPlayerGameModeMixin.java | 67 +- .../mixin/common/ServerPlayerMixin.java | 153 +-- .../mixin/common/ShulkerBulletMixin.java | 15 +- .../entity/mixin/common/ShulkerMixin.java | 41 + .../entity/mixin/common/SlimeMixin.java | 12 +- .../entity/mixin/common/SpiderMixin.java | 26 - .../common/SpreadPlayersCommandMixin.java | 25 +- .../mixin/common/StartAttackingMixin.java | 48 + .../mixin/common/TeleportCommandMixin.java | 13 +- .../common/ThrowableProjectileMixin.java | 10 +- .../mixin/common/ThrownEnderpearlMixin.java | 31 +- ...entEntitySectionManager$CallbackMixin.java | 17 +- .../network/AdvancedAddEntityPayload.java | 52 + .../assets/porting_lib_entity/lang/en_us.json | 3 + .../entity/src/main/resources/fabric.mod.json | 15 +- .../resources/porting_lib_entity.mixins.json | 16 +- .../entity/testmod/CustomSlime.java | 18 +- .../extensions/BlockEntityExtensions.java | 25 +- .../extensions/extensions/ItemExtensions.java | 68 +- .../MobEffectInstanceExtensions.java | 47 - .../src/main/resources/fabric.mod.json | 1 - .../porting_lib/fluids/FluidStack.java | 59 +- .../porting_lib/fluids/PortingLibFluids.java | 16 + .../wrapper/FluidAttributeFluidType.java | 6 +- .../MergingFluidAttributeFluidType.java | 6 +- .../gui/events/GatherComponentsEvent.java | 13 +- .../gui/extensions/GuiGraphicsExtension.java | 196 +++ .../porting_lib_gui_utils.accesswidener | 2 + .../porting_lib/level/BlockSnapshot.java | 256 ++++ .../porting_lib/level/LevelHooks.java | 117 ++ .../level/events/BlockDropsEvent.java | 122 ++ .../porting_lib/level/events/BlockEvent.java | 465 +++++++ .../porting_lib/level/events/LevelEvent.java | 248 +++- .../level/events/SleepFinishedTimeEvent.java | 8 +- .../level/mixin/ServerLevelMixin.java | 33 - .../level/mixin/client/ClientLevelMixin.java | 35 + .../level/mixin/client/MinecraftMixin.java | 37 + .../level}/mixin/common/DiodeBlockMixin.java | 7 +- .../level/mixin/common/LavaFluidMixin.java | 27 + .../level/mixin/common/LevelMixin.java | 30 + .../mixin/common/MinecraftServerMixin.java | 57 + .../mixin/common/NaturalSpawnerMixin.java | 29 + .../level}/mixin/common/ServerLevelMixin.java | 28 +- .../common/ServerPlayerGameModeMixin.java | 33 + .../porting_lib_level_events.mixins.json | 12 +- .../porting_lib/tags/Tags.java | 1159 ++++++++++++----- .../tags/data/BiomeTagsProvider.java | 293 ++++- .../tags/data/BlockTagProvider.java | 411 +++--- .../porting_lib/tags/data/DataGenerators.java | 7 +- .../tags/data/ItemTagLangProvider.java | 12 +- .../tags/data/ItemTagProvider.java | 355 ++++- .../porting_lib/tags/mixin/DyeColorMixin.java | 2 +- .../transfer/MutableContainerItemContext.java | 2 +- .../porting_lib/transfer/TransferUtil.java | 8 +- .../porting_lib/transfer/fluid/FluidTank.java | 23 +- .../transfer/fluid/SimpleFluidContent.java | 129 ++ .../fluid/item/FluidBucketWrapper.java | 246 ++-- .../fluid/item/FluidHandlerItemStack.java | 472 +++---- .../transfer/item/ItemHandlerHelper.java | 16 - .../transfer/item/ItemStackHandler.java | 15 +- .../item/ItemStackHandlerContainer.java | 4 +- .../transfer/item/ItemStackHandlerSlot.java | 12 +- .../transfer/item/RecipeWrapper.java | 9 +- .../porting_lib/util/ItemStackUtil.java | 34 - modules/utility/build.gradle | 0 .../porting_lib/PortingLibUtility.java | 13 - .../src/main/resources/fabric.mod.json | 12 - 297 files changed, 10302 insertions(+), 7027 deletions(-) delete mode 100644 modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/client/accessor/ModelBakeryAccessor.java delete mode 100644 modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/common/accessor/PotionBrewing$MixAccessor.java rename modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/{PortingLibClient.java => PortingLibBaseClient.java} (81%) delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/ClientWorldEvents.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureAtlasStitchedEvent.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureStitchCallback.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AddPackFindersCallback.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AttackAirCallback.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java rename modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/{GrindstoneEvents.java => GrindstoneEvent.java} (63%) delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/PotionEvents.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedCallback.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedEvent.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/fixes/ForgeBlockEntityFix.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/CustomMaxCountItem.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TagCollectorMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockItemMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ChunkStatusMixin.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DataFixersMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/MobEffectInstanceMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PackRepositoryMixin.java create mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/SpawnEggItemMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/StartAttackingMixin.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ArmorTextureRegistry.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockSnapshot.java rename modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/{LazySpawnEggItem.java => DeferredSpawnEggItem.java} (51%) delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazyOptional.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/NBTSerializer.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PotionHelper.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleFlowableFluid.java delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/TierSortingRegistry.java rename modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/{ForgeSlider.java => ExtendedSlider.java} (66%) delete mode 100644 modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScreenUtils.java delete mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingHandler.java create mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/RegisterBrewingRecipesEvent.java delete mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/VanillaBrewingRecipe.java create mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingBuilderExt.java create mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingExt.java create mode 100644 modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/PotionBrewingMixin.java create mode 100644 modules/brewing/src/main/resources/porting_lib_brewing.accesswidener create mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/PortingLibCommon.java create mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/ext/LanguageManagerExt.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/extensions/LanguageManagerExtensions.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/accessor/MinecraftAccessor.java rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => common/src/main/java/io/github/fabricators_of_create/porting_lib/common}/util/EnvExecutor.java (93%) create mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/FriendlyByteBufUtil.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MinecraftClientUtil.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullConsumer.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullFunction.java delete mode 100644 modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullSupplier.java rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => common/src/main/java/io/github/fabricators_of_create/porting_lib/common}/util/SimpleRecipeType.java (83%) rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => common/src/main/java/io/github/fabricators_of_create/porting_lib/common}/util/SimpleTier.java (96%) rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => common/src/main/java/io/github/fabricators_of_create/porting_lib/common}/util/TrueCondition.java (95%) rename modules/{utility/src/main/resources/porting_lib_utility.accesswidener => common/src/main/resources/porting_lib_common.accesswidener} (100%) create mode 100644 modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/client/PortingLibClient.java create mode 100644 modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/CancellableEvent.java rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => core/src/main/java/io/github/fabricators_of_create/porting_lib/core}/util/LogicalSidedProvider.java (95%) rename modules/{common/src/main/java/io/github/fabricators_of_create/porting_lib/common => core/src/main/java/io/github/fabricators_of_create/porting_lib/core}/util/MixinHelper.java (88%) rename modules/{utility/src/main/java/io/github/fabricators_of_create/porting_lib => core/src/main/java/io/github/fabricators_of_create/porting_lib/core}/util/ServerLifecycleHooks.java (87%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCure.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCures.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EntityHooks.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityAdditionalSpawnData.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityWithComplexSpawn.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ITeleporter.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/CriticalHitEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvent.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEventFactory.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityInteractCallback.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityJoinLevelEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvent.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityReadExtraDataCallback.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityTeleportEvent.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityUseItemEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/MobEntitySetTargetCallback.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerInteractionEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerTickEvents.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactCallback.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/{ => living}/LivingAttackEvent.java (64%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingChangeTargetEvent.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/{ => living}/LivingDeathEvent.java (75%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDropsEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEntityUseItemEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingExperienceDropEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingFallEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingKnockBackEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingUseTotemEvent.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/{ => living}/ShieldBlockEvent.java (86%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/CriticalHitEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerDestroyItemEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerInteractEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerXpEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/EntityTickEvent.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/PlayerTickEvent.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/{extensions/AbstractMinecartExtensions.java => ext/AbstractMinecartExt.java} (75%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/EntityExt.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/{extensions/ItemExtensions.java => ext/ItemExt.java} (56%) rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/{extensions/LevelExtensions.java => ext/LevelExt.java} (84%) create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LivingEntityExt.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectExt.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectInstanceExt.java rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/{extensions/PlayerExtension.java => ext/PlayerExt.java} (81%) rename modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/{extensions/SlimeExtension.java => ext/SlimeExt.java} (66%) delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/EntityExtensions.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/MobEffectExtensions.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/accessor/PlayerDataStorageAccessor.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/CatSpawnerMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FurnaceResultSlotMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectInstanceMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/NaturalSpawnerMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PatrolSpawnerMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PhantomSpawnerMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerDataStorageMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PortalForcerMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ProjectileMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ResultSlotMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerGamePacketListenerImpl$1Mixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerMixin.java delete mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpiderMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/StartAttackingMixin.java create mode 100644 modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/network/AdvancedAddEntityPayload.java create mode 100644 modules/entity/src/main/resources/assets/porting_lib_entity/lang/en_us.json delete mode 100644 modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectInstanceExtensions.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/BlockSnapshot.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/LevelHooks.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockDropsEvent.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockEvent.java delete mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/ServerLevelMixin.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/ClientLevelMixin.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/MinecraftMixin.java rename modules/{base/src/main/java/io/github/fabricators_of_create/porting_lib => level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level}/mixin/common/DiodeBlockMixin.java (73%) create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LavaFluidMixin.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LevelMixin.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/MinecraftServerMixin.java create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/NaturalSpawnerMixin.java rename modules/{base/src/main/java/io/github/fabricators_of_create/porting_lib => level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level}/mixin/common/ServerLevelMixin.java (57%) create mode 100644 modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerPlayerGameModeMixin.java create mode 100644 modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/SimpleFluidContent.java delete mode 100644 modules/utility/build.gradle delete mode 100644 modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibUtility.java delete mode 100644 modules/utility/src/main/resources/fabric.mod.json diff --git a/README.md b/README.md index 1d59fe73f..0b944e9f9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ Just choose a version and use its version number. | `tags` | Forge tags | | `tool_actions` | Utilities for tool interactions | | `transfer` | Storage implementations, client-side lookup, FluidStack, assorted transfer utilities | -| `utility` | Miscellaneous utilities that are too niche for other modules | ### Contributing See [the contribution information](CONTRIBUTING.md). diff --git a/build.gradle b/build.gradle index 98cb10160..f17b86048 100644 --- a/build.gradle +++ b/build.gradle @@ -97,11 +97,12 @@ allprojects { dependencies { // dev environment minecraft("com.mojang:minecraft:$minecraft_version") - mappings(loom.layered { - if (parchment_version != "none") - it.parchment("org.parchmentmc.data:parchment-$minecraft_version:$parchment_version@zip") - it.officialMojangMappings { nameSyntheticMembers = false } - }) +// mappings(loom.layered { +// if (parchment_version != "none") +// it.parchment("org.parchmentmc.data:parchment-$minecraft_version:$parchment_version@zip") +// it.officialMojangMappings { nameSyntheticMembers = false } +// }) + mappings(loom.officialMojangMappings()) modImplementation("net.fabricmc:fabric-loader:$loader_version") modLocalRuntime("com.terraformersmc:modmenu:$modmenu_version") { exclude group: "net.fabricmc"; exclude group: "net.fabricmc.fabric-api" } @@ -112,6 +113,9 @@ allprojects { implementation("javax.annotation:javax.annotation-api:1.3.2") implementation("com.google.code.findbugs:jsr305:3.0.2") + + if (mixin_extras_version != "none") + include(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:${mixin_extras_version}"))) } loom { diff --git a/gradle.properties b/gradle.properties index 19051f644..a4982020b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,6 +12,12 @@ minecraft_dependency = 1.21 loader_version = 0.15.11 fabric_version = 0.100.2+1.21 +# Mixin Extra's +# https://github.com/LlamaLad7/MixinExtras +# If set to 'none' Mixin Extra's will not be JiJ'd and Porting Lib will use whatever version fabric loader bundles +# ! Currently we use 0.4.0-beta.2 for @WrapMethod +mixin_extras_version = 0.4.0-beta.2 + # Mappings # https://lambdaurora.dev/tools/import_quilt.html # unused diff --git a/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/client/accessor/ModelBakeryAccessor.java b/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/client/accessor/ModelBakeryAccessor.java deleted file mode 100644 index cf56b41f9..000000000 --- a/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/client/accessor/ModelBakeryAccessor.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor; - -import net.minecraft.client.resources.model.ModelBakery; - -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -import java.util.function.Predicate; - -@Mixin(ModelBakery.class) -public interface ModelBakeryAccessor { - @Invoker("predicate") - static Predicate port_lib$predicate(StateDefinition container, String variant) { - throw new RuntimeException("mixin failed!"); - } -} diff --git a/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/common/accessor/PotionBrewing$MixAccessor.java b/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/common/accessor/PotionBrewing$MixAccessor.java deleted file mode 100644 index c4418aa91..000000000 --- a/modules/accessors/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/accessors/common/accessor/PotionBrewing$MixAccessor.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor; - -import net.minecraft.world.item.alchemy.PotionBrewing; - -import net.minecraft.world.item.crafting.Ingredient; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(PotionBrewing.Mix.class) -public interface PotionBrewing$MixAccessor { - @Accessor("from") - T port_lib$from(); - - @Accessor("ingredient") - Ingredient port_lib$ingredient(); - - @Accessor("to") - T port_lib$to(); -} diff --git a/modules/accessors/src/main/resources/porting_lib_accessors.mixins.json b/modules/accessors/src/main/resources/porting_lib_accessors.mixins.json index 8de6a9de9..22bdfc15b 100644 --- a/modules/accessors/src/main/resources/porting_lib_accessors.mixins.json +++ b/modules/accessors/src/main/resources/porting_lib_accessors.mixins.json @@ -16,7 +16,6 @@ "common.accessor.BlockEntityAccessor", "common.accessor.BlockLootSubProviderAccessor", "common.accessor.BucketItemAccessor", - "common.accessor.BundleItemAccessor", "common.accessor.ClientboundPlayerAbilitiesPacketAccessor", "common.accessor.CubeVoxelShapeAccessor", "common.accessor.EntityAccessor", @@ -26,14 +25,10 @@ "common.accessor.LiquidBlockAccessor", "common.accessor.LivingEntityAccessor", "common.accessor.MinecraftServerAccessor", - "common.accessor.MobAccessor", "common.accessor.PackRepositoryAccessor", "common.accessor.PaintingAccessor", "common.accessor.PlayerAccessor", - "common.accessor.PotionBrewing$MixAccessor", - "common.accessor.PotionBrewingAccessor", "common.accessor.RailStateAccessor", - "common.accessor.RecipeManagerAccessor", "common.accessor.ServerGamePacketListenerImplAccessor", "common.accessor.ServerPlayerAccessor", "common.accessor.SlotAccessor", @@ -52,12 +47,10 @@ "client.accessor.CommandSuggestions$SuggestionsListAccessor", "client.accessor.FontAccessor", "client.accessor.GameRendererAccessor", - "client.accessor.GuiAccessor", "client.accessor.HumanoidModelAccessor", "client.accessor.ItemInHandRendererAccessor", "client.accessor.ItemRendererAccessor", "client.accessor.KeyMappingAccessor", - "client.accessor.ModelBakeryAccessor", "client.accessor.ModelPartAccessor", "client.accessor.ParticleAccessor", "client.accessor.ParticleEngineAccessor", @@ -68,8 +61,7 @@ "client.accessor.SimpleBakedModel$BuilderAccessor", "client.accessor.TextureAtlasSprite$AnimatedTextureAccessor", "client.accessor.TextureSheetParticleAccessor", - "client.accessor.TextureStateShardAccessor", - "client.accessor.TitleScreenAccessor" + "client.accessor.TextureStateShardAccessor" ], "injectors": { "defaultRequire": 1, diff --git a/modules/base/build.gradle b/modules/base/build.gradle index 4686053e2..013dda30c 100644 --- a/modules/base/build.gradle +++ b/modules/base/build.gradle @@ -3,7 +3,6 @@ portingLib.addModuleDependencies([ "extensions", "gui_utils", "transfer", - "utility", "entity", "common", "config", diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBase.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBase.java index 35ed966bc..7cd9cff3d 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBase.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBase.java @@ -2,6 +2,8 @@ import io.github.fabricators_of_create.porting_lib.command.ConfigCommand; import io.github.fabricators_of_create.porting_lib.command.EnumArgument; +import io.github.fabricators_of_create.porting_lib.event.common.ModsLoadedCallback; +import io.github.fabricators_of_create.porting_lib.util.DeferredSpawnEggItem; import io.github.fabricators_of_create.porting_lib.util.UsernameCache; import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; @@ -15,20 +17,15 @@ import io.github.fabricators_of_create.porting_lib.core.PortingLib; import io.github.fabricators_of_create.porting_lib.transfer.item.ItemItemStorages; import io.github.fabricators_of_create.porting_lib.util.PortingHooks; -import io.github.fabricators_of_create.porting_lib.util.TierSortingRegistry; import net.fabricmc.api.ModInitializer; -import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.commands.synchronization.SingletonArgumentInfo; -import net.minecraft.core.registries.BuiltInRegistries; public class PortingLibBase implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger("Porting Lib Base"); @Override public void onInitialize() { - TierSortingRegistry.init(); ItemItemStorages.init(); UsernameCache.load(); - PortingHooks.init(); // can be used to force all mixins to apply // MixinEnvironment.getCurrentEnvironment().audit(); @@ -38,5 +35,7 @@ public void onInitialize() { new EnumArgument.Info()); CommandRegistrationCallback.EVENT.register(ConfigCommand::register); + + ModsLoadedCallback.EVENT.register(envType -> DeferredSpawnEggItem.init()); } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibClient.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBaseClient.java similarity index 81% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibClient.java rename to modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBaseClient.java index 11fd5d0f2..c06f180df 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibClient.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibBaseClient.java @@ -1,14 +1,20 @@ package io.github.fabricators_of_create.porting_lib; +import io.github.fabricators_of_create.porting_lib.event.common.ModsLoadedCallback; + +import io.github.fabricators_of_create.porting_lib.util.DeferredSpawnEggItem; +import net.fabricmc.api.EnvType; + +import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; +import net.minecraft.util.FastColor; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.github.fabricators_of_create.porting_lib.util.FluidTextUtil; -import io.github.fabricators_of_create.porting_lib.util.LogicalSidedProvider; import io.github.fabricators_of_create.porting_lib.util.NetworkHooks; import io.netty.buffer.Unpooled; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; @@ -23,7 +29,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; -public class PortingLibClient implements ClientModInitializer { +public class PortingLibBaseClient implements ClientModInitializer { private final Logger LOGGER = LoggerFactory.getLogger("porting_lib_client"); @Override @@ -40,9 +46,12 @@ public void onInitializeClient() { client.execute(() -> openScreen(typeId, syncId, title, extraData)); }); - ClientLifecycleEvents.CLIENT_STARTED.register(client -> LogicalSidedProvider.setClient(() -> client)); - + ModsLoadedCallback.EVENT.register(envType -> { + if (envType == EnvType.CLIENT) { + DeferredSpawnEggItem.MOD_EGGS.forEach(egg -> ColorProviderRegistry.ITEM.register((stack, layer) -> FastColor.ARGB32.opaque(egg.getColor(layer)), egg)); + } + }); } private void openScreen(int typeId, int syncId, Component title, FriendlyByteBuf buf) { diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomDataPacketHandlingBlockEntity.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomDataPacketHandlingBlockEntity.java index e2309b8ae..da2958074 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomDataPacketHandlingBlockEntity.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomDataPacketHandlingBlockEntity.java @@ -1,8 +1,25 @@ package io.github.fabricators_of_create.porting_lib.block; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.level.block.entity.BlockEntity; public interface CustomDataPacketHandlingBlockEntity { - void onDataPacket(Connection connection, ClientboundBlockEntityDataPacket packet); + /** + * Called when you receive a {@link ClientboundBlockEntityDataPacket} packet for the location this + * BlockEntity is currently in. On the client, the Connection will always + * be the remote server. On the server, it will be whomever is responsible for + * sending the packet. + * + * @param net The Connection the packet originated from + * @param pkt The data packet + */ + default void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt, HolderLookup.Provider lookupProvider) { + CompoundTag compoundtag = pkt.getTag(); + if (!compoundtag.isEmpty()) { + ((BlockEntity) this).loadWithComponents(compoundtag, lookupProvider); + } + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomExpBlock.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomExpBlock.java index 285334ba7..a678c096c 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomExpBlock.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomExpBlock.java @@ -1,23 +1,28 @@ package io.github.fabricators_of_create.porting_lib.block; import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.LevelReader; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentEffectComponents; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + public interface CustomExpBlock { /** - * Gathers how much experience this block drops when broken. + * Returns how many experience points this block drops when broken, before application of {@linkplain EnchantmentEffectComponents#BLOCK_EXPERIENCE enchantments}. * - * @param state The current state - * @param level The level - * @param randomSource Random source to use for experience randomness - * @param pos Block position - * @param fortuneLevel fortune enchantment level of tool being used - * @param silkTouchLevel silk touch enchantment level of tool being used - * @return Amount of XP from breaking this block. + * @param state The state of the block being broken + * @param level The level + * @param pos The position of the block being broken + * @param blockEntity The block entity, if any + * @param breaker The entity who broke the block, if known + * @param tool The item stack used to break the block. May be empty + * @return The amount of experience points dropped by this block */ - default int getExpDrop(BlockState state, LevelReader level, RandomSource randomSource, BlockPos pos, int fortuneLevel, int silkTouchLevel) { + default int getExpDrop(BlockState state, LevelAccessor level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity breaker, ItemStack tool) { return 0; } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomRunningEffectsBlock.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomRunningEffectsBlock.java index 021cbb1a4..0421930ca 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomRunningEffectsBlock.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomRunningEffectsBlock.java @@ -7,7 +7,18 @@ public interface CustomRunningEffectsBlock { /** - * @return true to prevent vanilla particles spawning + * Allows a block to override the standard vanilla running particles. + * This is called from Entity.spawnSprintParticle and is called both, + * Client and server side, it's up to the implementor to client check / server check. + * By default vanilla spawns particles only on the client and the server methods no-op. + * + * @param state The BlockState the entity is running on. + * @param level The level. + * @param pos The position at the entities feet. + * @param entity The entity running on the block. + * @return True to prevent vanilla running particles from spawning. */ - boolean addRunningEffects(BlockState state, Level world, BlockPos pos, Entity entity); + default boolean addRunningEffects(BlockState state, Level level, BlockPos pos, Entity entity) { + return false; + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomUpdateTagHandlingBlockEntity.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomUpdateTagHandlingBlockEntity.java index f7a16ad11..7f3fe1ac4 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomUpdateTagHandlingBlockEntity.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/block/CustomUpdateTagHandlingBlockEntity.java @@ -1,10 +1,18 @@ package io.github.fabricators_of_create.porting_lib.block; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntity; public interface CustomUpdateTagHandlingBlockEntity { - default void handleUpdateTag(CompoundTag tag) { - ((BlockEntity) this).load(tag); + /** + * Called when the chunk's BE update tag, gotten from {@link BlockEntity#getUpdateTag(HolderLookup.Provider)}, is received on the client. + *

+ * Used to handle this tag in a special way. By default this simply calls {@link BlockEntity#loadWithComponents(CompoundTag, HolderLookup.Provider)}. + * + * @param tag The {@link CompoundTag} sent from {@link BlockEntity#getUpdateTag(HolderLookup.Provider)} + */ + default void handleUpdateTag(CompoundTag tag, HolderLookup.Provider lookupProvider) { + ((BlockEntity) this).loadWithComponents(tag, lookupProvider); } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/ClientWorldEvents.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/ClientWorldEvents.java deleted file mode 100644 index 4ebace490..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/ClientWorldEvents.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.client; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; - -@Environment(EnvType.CLIENT) -public final class ClientWorldEvents { - public static final Event LOAD = EventFactory.createArrayBacked(Load.class, callbacks -> (client, world) -> { - for (Load callback : callbacks) { - callback.onWorldLoad(client, world); - } - }); - - public static final Event UNLOAD = EventFactory.createArrayBacked(Unload.class, callbacks -> (client, world) -> { - for (Unload callback : callbacks) { - callback.onWorldUnload(client, world); - } - }); - - private ClientWorldEvents() {} - - @FunctionalInterface - public interface Load { - void onWorldLoad(Minecraft client, ClientLevel world); - } - - @FunctionalInterface - public interface Unload { - void onWorldUnload(Minecraft client, ClientLevel world); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureAtlasStitchedEvent.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureAtlasStitchedEvent.java new file mode 100644 index 000000000..f5dfd6da5 --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureAtlasStitchedEvent.java @@ -0,0 +1,49 @@ +package io.github.fabricators_of_create.porting_lib.event.client; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.renderer.texture.TextureAtlas; + +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired after a texture atlas is stitched together and all textures therein have been loaded. + * + *

This event is not {@linkplain CancellableEvent cancellable}.

+ * + *

This event is fired on the mod-specific event bus, only on the {@linkplain EnvType#CLIENT logical client}.

+ * + * @see TextureAtlas + */ +public class TextureAtlasStitchedEvent extends BaseEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onStitched(event); + }); + + private final TextureAtlas atlas; + + @ApiStatus.Internal + public TextureAtlasStitchedEvent(TextureAtlas atlas) { + this.atlas = atlas; + } + + /** + * {@return the texture atlas} + */ + public TextureAtlas getAtlas() { + return atlas; + } + + @Override + public void sendEvent() { + EVENT.invoker().onStitched(this); + } + + public interface Callback { + void onStitched(TextureAtlasStitchedEvent event); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureStitchCallback.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureStitchCallback.java deleted file mode 100644 index 5ac756c23..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/client/TextureStitchCallback.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.client; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.client.renderer.texture.TextureAtlas; - -public interface TextureStitchCallback { - Event POST = EventFactory.createArrayBacked(Post.class, callbacks -> atlas -> { - for(Post e : callbacks) - e.stitch(atlas); - }); - - @Environment(EnvType.CLIENT) - interface Post { - void stitch(TextureAtlas atlas); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AddPackFindersCallback.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AddPackFindersCallback.java deleted file mode 100644 index 514469f78..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AddPackFindersCallback.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.common; - -import java.util.function.Consumer; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.server.packs.repository.RepositorySource; - -/** - * Use {@link AddPackFindersEvent} - */ -@Deprecated(forRemoval = true) -public interface AddPackFindersCallback { - Event EVENT = EventFactory.createArrayBacked(AddPackFindersCallback.class, callbacks -> (sources) -> { - for (AddPackFindersCallback e : callbacks) { - e.addPack(sources); - } - }); - - void addPack(Consumer sources); -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AdvancementEvent.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AdvancementEvent.java index f4fdc9397..f361eced6 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AdvancementEvent.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AdvancementEvent.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.event.common; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerEvents; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.advancements.AdvancementHolder; @@ -13,7 +13,7 @@ * @see AdvancementEarnEvent * @see AdvancementProgressEvent */ -public abstract class AdvancementEvent extends PlayerEvents { +public abstract class AdvancementEvent extends PlayerEvent { public static final Event EARN = EventFactory.createArrayBacked(EarnCallback.class, callbacks -> event -> { for (EarnCallback c : callbacks) c.onAdvancementEarn(event); diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AttackAirCallback.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AttackAirCallback.java deleted file mode 100644 index 086eadbca..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/AttackAirCallback.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.common; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.client.player.LocalPlayer; - -// TODO 1.20: rename to AttackMissedCallback or similar -/** - * An Event fired when an attack hits nothing. - */ -@Environment(EnvType.CLIENT) -public interface AttackAirCallback { - Event EVENT = EventFactory.createArrayBacked(AttackAirCallback.class, callbacks -> (player) -> { - for (AttackAirCallback callback : callbacks) { - callback.attackAir(player); - } - }); - - void attackAir(LocalPlayer player); -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java deleted file mode 100644 index e7d73fba1..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/BlockEvents.java +++ /dev/null @@ -1,206 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.common; - -import io.github.fabricators_of_create.porting_lib.block.CustomExpBlock; -import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.util.PortingHooks; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.state.BlockState; - -import org.jetbrains.annotations.Nullable; - -import java.util.EnumSet; - -public abstract class BlockEvents extends BaseEvent { - - public static final Event BLOCK_BREAK = EventFactory.createArrayBacked(BlockBreak.class, callbacks -> event -> { - for (BlockBreak e : callbacks) - e.onBlockBreak(event); - }); - public static final Event NEIGHBORS_NOTIFY = EventFactory.createArrayBacked(NotifyNeighbors.class, callbacks -> event -> { - for (NotifyNeighbors e : callbacks) - e.onNotifyNeighbors(event); - }); - - @FunctionalInterface - public interface BlockBreak { - void onBlockBreak(BreakEvent event); - } - - @FunctionalInterface - public interface NotifyNeighbors { - void onNotifyNeighbors(NeighborNotifyEvent event); - } - - /** - * Invoked before a block is placed from the head of {@link BlockItem#useOn(UseOnContext)}. Called on both client and server. - * Return null to fall back to further processing. Any non-null value will result in placement being cancelled. - */ - public static final Event BEFORE_PLACE = EventFactory.createArrayBacked(BeforePlace.class, callbacks -> context -> { - for (BeforePlace callback : callbacks) { - InteractionResult result = callback.beforePlace(context); - if (result != null) - return result; - } - return null; - }); - - public interface BeforePlace { - @Nullable - InteractionResult beforePlace(BlockPlaceContext ctx); - } - - /** - * Invoked after a block is placed, from {@link BlockItem#useOn(UseOnContext)}. Called on both client and server. - * - * @deprecated Use {@link BlockEvents#POST_PROCESS_PLACE} instead. - */ - @Deprecated - public static final Event AFTER_PLACE = EventFactory.createArrayBacked(AfterPlace.class, callbacks -> context -> { - for (AfterPlace callback : callbacks) - callback.afterPlace(context); - }); - - public interface AfterPlace { - void afterPlace(BlockPlaceContext ctx); - } - - /** - * Invoked after a block is placed, from the TAIL of {@link BlockItem#place(BlockPlaceContext)}. - * Called on both client and server. - * Provides the block's Position and BlockState as well. - */ - public static final Event POST_PROCESS_PLACE = EventFactory.createArrayBacked(PostProcessPlace.class, callbacks -> (context, blockPos, blockState) -> { - for (PostProcessPlace callback : callbacks) - callback.postProcessPlace(context, blockPos, blockState); - }); - - public interface PostProcessPlace { - void postProcessPlace(BlockPlaceContext ctx, BlockPos blockPos, BlockState blockState); - } - - private final LevelAccessor level; - private final BlockPos pos; - private final BlockState state; - - public BlockEvents(LevelAccessor world, BlockPos pos, BlockState state) { - this.pos = pos; - this.level = world; - this.state = state; - } - - public LevelAccessor getLevel() { - return level; - } - - @Deprecated(forRemoval = true) - public LevelAccessor getWorld() { - return level; - } - - public BlockPos getPos() { - return pos; - } - - public BlockState getState() { - return state; - } - - public static class BreakEvent extends BlockEvents { - /** - * Reference to the Player who broke the block. If no player is available, use a EntityFakePlayer - */ - private final Player player; - private int exp; - - public BreakEvent(Level world, BlockPos pos, BlockState state, Player player) { - super(world, pos, state); - this.player = player; - - if (state == null || !PortingHooks.isCorrectToolForDrops(state, player)) { // Handle empty block or player unable to break block scenario - this.exp = 0; - } else { - int bonusLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, player.getMainHandItem()); - int silklevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, player.getMainHandItem()); - this.exp = state.getBlock() instanceof CustomExpBlock exp ? exp.getExpDrop(state, world, world.getRandom(), pos, bonusLevel, silklevel) : 0; - } - } - - public Player getPlayer() { - return player; - } - - /** - * Get the experience dropped by the block after the event has processed - * - * @return The experience to drop or 0 if the event was canceled - */ - public int getExpToDrop() { - return this.isCanceled() ? 0 : exp; - } - - /** - * Set the amount of experience dropped by the block after the event has processed - * - * @param exp 1 or higher to drop experience, else nothing will drop - */ - public void setExpToDrop(int exp) { - this.exp = exp; - } - - @Override - public void sendEvent() { - BLOCK_BREAK.invoker().onBlockBreak(this); - } - } - - /** - * Fired when a physics update occurs on a block. This event acts as - * a way for mods to detect physics updates, in the same way a BUD switch - * does. This event is only called on the server. - */ - public static class NeighborNotifyEvent extends BlockEvents { - private final EnumSet notifiedSides; - private final boolean forceRedstoneUpdate; - - public NeighborNotifyEvent(Level level, BlockPos pos, BlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { - super(level, pos, state); - this.notifiedSides = notifiedSides; - this.forceRedstoneUpdate = forceRedstoneUpdate; - } - - /** - * Gets a list of directions from the base block that updates will occur upon. - * - * @return list of notified directions - */ - public EnumSet getNotifiedSides() { - return notifiedSides; - } - - /** - * Get if redstone update was forced during setBlock call (0x16 to flags) - * - * @return if the flag was set - */ - public boolean getForceRedstoneUpdate() { - return forceRedstoneUpdate; - } - - @Override - public void sendEvent() { - NEIGHBORS_NOTIFY.invoker().onNotifyNeighbors(this); - } - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvents.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvent.java similarity index 63% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvents.java rename to modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvent.java index 39a08f58c..fc4793906 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvents.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/GrindstoneEvent.java @@ -1,28 +1,19 @@ package io.github.fabricators_of_create.porting_lib.event.common; import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.GrindstoneMenu; import net.minecraft.world.item.ItemStack; -public abstract class GrindstoneEvents extends BaseEvent { - public static final Event ON_PLACE_ITEM = EventFactory.createArrayBacked(PlaceItemCallback.class, placeItemCallbacks -> event -> { - for (PlaceItemCallback e : placeItemCallbacks) - e.onGrindstonePlace(event); - }); - - public static final Event ON_TAKE_ITEM = EventFactory.createArrayBacked(OnTakeItemCallback.class, takeItemCallbacks -> event -> { - for (OnTakeItemCallback e : takeItemCallbacks) - e.onGrindstoneTake(event); - }); - +public abstract class GrindstoneEvent extends BaseEvent { private final ItemStack top; private final ItemStack bottom; private int xp; - protected GrindstoneEvents(ItemStack top, ItemStack bottom, int xp) { + protected GrindstoneEvent(ItemStack top, ItemStack bottom, int xp) { this.top = top; this.bottom = bottom; this.xp = xp; @@ -44,6 +35,7 @@ public ItemStack getBottomItem() { /** * This is the experience amount determined by the event. It will be {@code -1} unless {@link #setXp(int)} is called.
+ * * @return The experience amount given to the player.
*/ public int getXp() { @@ -52,6 +44,7 @@ public int getXp() { /** * Sets the experience amount.
+ * * @param xp The experience amount given to the player.
*/ public void setXp(int xp) { @@ -59,29 +52,34 @@ public void setXp(int xp) { } /** - * This event is cancelable
- * {@link OnplaceItem} is fired when the inputs to a grindstone are changed.
- * + * This event is {@link CancellableEvent}
+ * {@link OnPlaceItem} is fired when the inputs to a grindstone are changed.
+ *

* The following rules apply: *

    - *
  • If the event is canceled, vanilla behavior will not run, and the output will be {@linkplain ItemStack#EMPTY empty}.
  • - *
  • If the event is not canceled
  • - *
      - *
    • and the output is empty, the output will be determined by vanilla.
    • - *
    • and the output is not empty, the output will be set, without running vanilla behavior.
    • - *
    - *
  • Vanilla XP calculation logic will be used unless all of the following criterias are met:
  • - *
      - *
    • the amount of experience is greater than or equal to {@code 0};
    • - *
    • the event is not {@linkplain #isCanceled() canceled};
    • - *
    • the {@linkplain #getOutput() output} is not empty.
    • - *
    + *
  • If the event is canceled, vanilla behavior will not run, and the output will be {@linkplain ItemStack#EMPTY empty}.
  • + *
  • If the event is not canceled
  • + *
      + *
    • and the output is empty, the output will be determined by vanilla.
    • + *
    • and the output is not empty, the output will be set, without running vanilla behavior.
    • + *
    + *
  • Vanilla XP calculation logic will be used unless all of the following criterias are met:
  • + *
      + *
    • the amount of experience is greater than or equal to {@code 0};
    • + *
    • the event is not {@linkplain #isCanceled() canceled};
    • + *
    • the {@linkplain #getOutput() output} is not empty.
    • + *
    *
*/ - public static class OnplaceItem extends GrindstoneEvents { + public static class OnPlaceItem extends GrindstoneEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onGrindstonePlaceItem(event); + }); + private ItemStack output; - public OnplaceItem(ItemStack top, ItemStack bottom, int xp) { + public OnPlaceItem(ItemStack top, ItemStack bottom, int xp) { super(top, bottom, xp); this.output = ItemStack.EMPTY; } @@ -91,6 +89,7 @@ public OnplaceItem(ItemStack top, ItemStack bottom, int xp) { * If you are the first receiver of this event, it is guaranteed to be empty.
* It will only be non-empty if changed by an event handler.
* If this event is cancelled, this output stack is discarded.
+ * * @return The item to set in the output grindstone slot.
*/ public ItemStack getOutput() { @@ -99,6 +98,7 @@ public ItemStack getOutput() { /** * Sets the output slot to a specific itemstack. + * * @param output The stack to change the output to. */ public void setOutput(ItemStack output) { @@ -107,18 +107,27 @@ public void setOutput(ItemStack output) { @Override public void sendEvent() { - ON_PLACE_ITEM.invoker().onGrindstonePlace(this); + EVENT.invoker().onGrindstonePlaceItem(this); + } + + public interface Callback { + void onGrindstonePlaceItem(OnPlaceItem event); } } /** - * This event is cancelable
+ * This event is {@link CancellableEvent}
* {@link OnTakeItem} is fired when the output in a grindstone are is taken.
* It is called from {@link GrindstoneMenu#GrindstoneMenu(int, Inventory)}.
* If the event is canceled, vanilla behavior will not run, and no inputs will be consumed.
* if the amount of experience is larger than or equal 0, the vanilla behavior for calculating experience will not run.
*/ - public static class OnTakeItem extends GrindstoneEvents { + public static class OnTakeItem extends GrindstoneEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onGrindstoneTakeItem(event); + }); + private ItemStack newTop = ItemStack.EMPTY; private ItemStack newBottom = ItemStack.EMPTY; @@ -142,6 +151,7 @@ public ItemStack getNewBottomItem() { /** * Sets the itemstack in the top slot.
+ * * @param newTop */ public void setNewTopItem(ItemStack newTop) { @@ -150,6 +160,7 @@ public void setNewTopItem(ItemStack newTop) { /** * Sets the itemstack in the bottom slot.
+ * * @param newBottom */ public void setNewBottomItem(ItemStack newBottom) { @@ -158,6 +169,7 @@ public void setNewBottomItem(ItemStack newBottom) { /** * This is the experience amount that will be returned by the event.
+ * * @return The experience amount given to the player.
*/ public int getXp() { @@ -166,17 +178,11 @@ public int getXp() { @Override public void sendEvent() { - ON_TAKE_ITEM.invoker().onGrindstoneTake(this); + EVENT.invoker().onGrindstoneTakeItem(this); } - } - - @FunctionalInterface - public interface PlaceItemCallback { - void onGrindstonePlace(OnplaceItem event); - } - @FunctionalInterface - public interface OnTakeItemCallback { - void onGrindstoneTake(OnTakeItem event); + public interface Callback { + void onGrindstoneTakeItem(OnTakeItem event); + } } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/PotionEvents.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/PotionEvents.java deleted file mode 100644 index 9aa6fb49b..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/PotionEvents.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.common; - -import javax.annotation.Nullable; - -import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; - -/** - * Use {@link MobEffectEvent} - */ -@Deprecated(forRemoval = true) -public class PotionEvents { - public static Event POTION_ADDED = EventFactory.createArrayBacked(PotionAdded.class, callbacks -> (entity, newEffect, oldEffect, source) -> { - for (PotionAdded e : callbacks) - e.onPotionAdded(entity, newEffect, oldEffect, source); - }); - - public static Event POTION_APPLICABLE = EventFactory.createArrayBacked(PotionApplicable.class, callbacks -> (entity, effect) -> { - for (PotionApplicable e : callbacks) { - InteractionResult result = e.onPotionApplicable(entity, effect); - if (result != InteractionResult.PASS) - return result; - } - return InteractionResult.PASS; - }); - - @FunctionalInterface - public interface PotionAdded { - void onPotionAdded(LivingEntity entity, MobEffectInstance newEffect, MobEffectInstance oldEffect, @Nullable Entity source); - } - - @FunctionalInterface - public interface PotionApplicable { - InteractionResult onPotionApplicable(LivingEntity entity, MobEffectInstance effect); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedCallback.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedCallback.java deleted file mode 100644 index a3c339c4f..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedCallback.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.event.common; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.core.RegistryAccess; - -public interface TagsUpdatedCallback { - Event EVENT = EventFactory.createArrayBacked(TagsUpdatedCallback.class, callbacks -> registryAccess -> { - for (TagsUpdatedCallback e : callbacks) - e.onTagsUpdated(registryAccess); - }); - - void onTagsUpdated(RegistryAccess registries); -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedEvent.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedEvent.java new file mode 100644 index 000000000..9f870fbd7 --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/event/common/TagsUpdatedEvent.java @@ -0,0 +1,72 @@ +package io.github.fabricators_of_create.porting_lib.event.common; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.core.RegistryAccess; + +/** + * Fired when tags are updated on either server or client. This event can be used to refresh data that depends on tags. + */ +public class TagsUpdatedEvent extends BaseEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onTagsUpdated(event); + }); + + private final RegistryAccess registryAccess; + private final UpdateCause updateCause; + private final boolean integratedServer; + + public TagsUpdatedEvent(RegistryAccess registryAccess, boolean fromClientPacket, boolean isIntegratedServerConnection) { + this.registryAccess = registryAccess; + this.updateCause = fromClientPacket ? UpdateCause.CLIENT_PACKET_RECEIVED : UpdateCause.SERVER_DATA_LOAD; + this.integratedServer = isIntegratedServerConnection; + } + + /** + * @return The dynamic registries that have had their tags rebound. + */ + public RegistryAccess getRegistryAccess() { + return registryAccess; + } + + /** + * @return the cause for this tag update + */ + public UpdateCause getUpdateCause() { + return updateCause; + } + + /** + * Whether static data (which in single player is shared between server and client thread) should be updated as a + * result of this event. Effectively this means that in single player only the server-side updates this data. + */ + public boolean shouldUpdateStaticData() { + return updateCause == UpdateCause.SERVER_DATA_LOAD || !integratedServer; + } + + @Override + public void sendEvent() { + EVENT.invoker().onTagsUpdated(this); + } + + /** + * Represents the cause for a tag update. + */ + public enum UpdateCause { + /** + * The tag update is caused by the server loading datapack data. Note that in single player this still happens + * on the client thread. + */ + SERVER_DATA_LOAD, + /** + * The tag update is caused by the client receiving the tag data from the server. + */ + CLIENT_PACKET_RECEIVED + } + + public interface Callback { + void onTagsUpdated(TagsUpdatedEvent event); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/fixes/ForgeBlockEntityFix.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/fixes/ForgeBlockEntityFix.java new file mode 100644 index 000000000..187a68adf --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/fixes/ForgeBlockEntityFix.java @@ -0,0 +1,31 @@ +package io.github.fabricators_of_create.porting_lib.fixes; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFix; +import com.mojang.datafixers.TypeRewriteRule; + +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; + +import io.github.fabricators_of_create.porting_lib.util.BlockEntityHelper; +import net.minecraft.util.datafix.fixes.References; + +public class ForgeBlockEntityFix extends DataFix { + public static final String LEGACY_DATA_KEY = "ForgeData"; + public static final String NEO_DATA_KEY = "NeoForgeData"; + + public ForgeBlockEntityFix(Schema outputSchema, boolean changesType) { + super(outputSchema, changesType); + } + + public Dynamic fix(Dynamic original) { + return original.renameField(LEGACY_DATA_KEY, BlockEntityHelper.EXTRA_DATA_KEY).renameField(NEO_DATA_KEY, BlockEntityHelper.EXTRA_DATA_KEY); + } + + @Override + protected TypeRewriteRule makeRule() { + return this.fixTypeEverywhereTyped("jigsaw_rotation_fix", this.getInputSchema().getType(References.BLOCK_ENTITY), (typed) -> { + return typed.update(DSL.remainderFinder(), this::fix); + }); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ArmorTextureItem.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ArmorTextureItem.java index c0122f8b9..deb7c22e9 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ArmorTextureItem.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ArmorTextureItem.java @@ -1,12 +1,39 @@ package io.github.fabricators_of_create.porting_lib.item; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ArmorMaterial; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + /** * An Armor Item with custom logic for getting the texture. */ public interface ArmorTextureItem { - String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String type); + /** + * Called by {@link HumanoidArmorLayer#renderArmorPiece(PoseStack, MultiBufferSource, LivingEntity, EquipmentSlot, int, HumanoidModel)} to determine the armor texture that + * should be use for the currently equipped item. This will only be called on + * instances of ItemArmor. + * + * Returning null from this function will use the default value. + * + * @param stack ItemStack for the equipped armor + * @param entity The entity wearing the armor + * @param slot The slot the armor is in + * @param layer The armor layer + * @param innerModel Whether the inner model is used + * @return Path of texture to bind, or null to use default + */ + @Nullable + default ResourceLocation getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, ArmorMaterial.Layer layer, boolean innerModel) { + return null; + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ContinueUsingItem.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ContinueUsingItem.java index 3650591c8..8dc5d7a01 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ContinueUsingItem.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/ContinueUsingItem.java @@ -13,6 +13,10 @@ public interface ContinueUsingItem { * @return true to set the new stack to active and continue using it */ default boolean canContinueUsing(ItemStack oldStack, ItemStack newStack) { - return ItemStack.isSameItem(oldStack, newStack); + if (oldStack == newStack) { + return true; + } else { + return !oldStack.isEmpty() && !newStack.isEmpty() && ItemStack.isSameItem(newStack, oldStack); + } } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/CustomMaxCountItem.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/CustomMaxCountItem.java deleted file mode 100644 index bc93e5e6e..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/CustomMaxCountItem.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.item; - -import net.minecraft.world.item.ItemStack; - -public interface CustomMaxCountItem { - int getItemStackLimit(ItemStack stack); -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/DamageableItem.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/DamageableItem.java index 41623e2c6..32d3df382 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/DamageableItem.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/item/DamageableItem.java @@ -1,13 +1,10 @@ package io.github.fabricators_of_create.porting_lib.item; -import net.minecraft.world.item.Item; +import net.minecraft.core.component.DataComponents; +import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; public interface DamageableItem { - private Item self() { - return (Item) this; - } - /** * Return the itemDamage represented by this ItemStack. Defaults to the Damage * entry in the stack NBT, but can be overridden here for other sources. @@ -16,7 +13,7 @@ private Item self() { * @return the damage value */ default int getDamage(ItemStack stack) { - return !stack.hasTag() ? 0 : stack.getTag().getInt("Damage"); + return Mth.clamp(stack.getOrDefault(DataComponents.DAMAGE, 0), 0, stack.getMaxDamage()); } /** @@ -26,9 +23,8 @@ default int getDamage(ItemStack stack) { * @param stack The itemstack that is damaged * @return the damage value */ - @SuppressWarnings("deprecation") default int getMaxDamage(ItemStack stack) { - return self().getMaxDamage(); + return stack.getOrDefault(DataComponents.MAX_DAMAGE, 0); } /** @@ -39,6 +35,6 @@ default int getMaxDamage(ItemStack stack) { * @param damage the new damage value */ default void setDamage(ItemStack stack, int damage) { - stack.getOrCreateTag().putInt("Damage", Math.max(0, damage)); + stack.set(DataComponents.DAMAGE, Mth.clamp(damage, 0, stack.getMaxDamage())); } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientLevelMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientLevelMixin.java index 01a465887..1ce4592d3 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientLevelMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientLevelMixin.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.event.client.ClientWorldEvents; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientPacketListenerMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientPacketListenerMixin.java index 8913809b4..52d2c3cc0 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientPacketListenerMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/ClientPacketListenerMixin.java @@ -1,12 +1,10 @@ package io.github.fabricators_of_create.porting_lib.mixin.client; import io.github.fabricators_of_create.porting_lib.event.common.RecipesUpdatedCallback; -import io.github.fabricators_of_create.porting_lib.event.common.TagsUpdatedCallback; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; import net.minecraft.client.multiplayer.CommonListenerCookie; import net.minecraft.core.RegistryAccess; -import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; @@ -54,9 +52,4 @@ protected ClientPacketListenerMixin(Minecraft client, Connection connection, Com public void port_lib$updateRecipes(ClientboundUpdateRecipesPacket packet, CallbackInfo ci) { RecipesUpdatedCallback.EVENT.invoker().onRecipesUpdated(this.recipeManager); } - - @Inject(method = "handleUpdateTags", at = @At("TAIL")) - public void port_lib$updateTags(ClientboundUpdateTagsPacket packet, CallbackInfo ci) { - TagsUpdatedCallback.EVENT.invoker().onTagsUpdated(this.registryAccess); - } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/HumanoidArmorLayerMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/HumanoidArmorLayerMixin.java index 19d81d6f1..a0cd2b5bd 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/HumanoidArmorLayerMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/HumanoidArmorLayerMixin.java @@ -4,13 +4,11 @@ import io.github.fabricators_of_create.porting_lib.client.armor.ArmorRendererRegistry; import io.github.fabricators_of_create.porting_lib.item.ArmorTextureItem; -import io.github.fabricators_of_create.porting_lib.util.ArmorTextureRegistry; import io.github.fabricators_of_create.porting_lib.util.client.ClientHooks; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -28,7 +26,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.ItemStack; @Environment(EnvType.CLIENT) @@ -39,26 +36,18 @@ public HumanoidArmorLayerMixin(RenderLayerParent cir) { - ResourceLocation id = ArmorTextureRegistry.get(armorItem.getMaterial()); - if (id != null) { - cir.setReturnValue(id); - } - } - - @Inject(method = "renderArmorPiece", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;renderModel(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/item/ArmorItem;Lnet/minecraft/client/model/HumanoidModel;ZFFFLjava/lang/String;)V", ordinal = 2), cancellable = true) - public> void port_lib$fixArmorTextures(PoseStack matrices, MultiBufferSource vertexConsumers, T entity, EquipmentSlot armorSlot, int light, A model, CallbackInfo ci) { - ItemStack itemStack = entity.getItemBySlot(armorSlot); - if(itemStack.getItem() instanceof ArmorTextureItem) { - ResourceLocation resourceLocation = ClientHooks.getArmorResource(entity, itemStack, armorSlot, null); - VertexConsumer vertexConsumer = ItemRenderer.getArmorFoilBuffer( - vertexConsumers, RenderType.armorCutoutNoCull(resourceLocation), false, itemStack.hasFoil() - ); - model.renderToBuffer(matrices, vertexConsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); - ci.cancel(); - } - } +// @Inject(method = "renderArmorPiece", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;renderModel(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/item/ArmorItem;Lnet/minecraft/client/model/HumanoidModel;ZFFFLjava/lang/String;)V", ordinal = 2), cancellable = true) +// public> void port_lib$fixArmorTextures(PoseStack matrices, MultiBufferSource vertexConsumers, T entity, EquipmentSlot armorSlot, int light, A model, CallbackInfo ci) { +// ItemStack itemStack = entity.getItemBySlot(armorSlot); +// if(itemStack.getItem() instanceof ArmorTextureItem) { +// ResourceLocation resourceLocation = ClientHooks.getArmorTexture(entity, itemStack, armorSlot, null); +// VertexConsumer vertexConsumer = ItemRenderer.getArmorFoilBuffer( +// vertexConsumers, RenderType.armorCutoutNoCull(resourceLocation), false, itemStack.hasFoil() +// ); +// model.renderToBuffer(matrices, vertexConsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); +// ci.cancel(); +// } +// } TODO: PORT @Inject(method = "renderArmorPiece", at = @At("HEAD"), cancellable = true) public> void port_lib$armorRegistry(PoseStack matrices, MultiBufferSource vertexConsumers, T entity, EquipmentSlot armorSlot, int light, HumanoidModel armorModel, CallbackInfo ci) { diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/MinecraftMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/MinecraftMixin.java index 60d466cdc..656eb4484 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/MinecraftMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/MinecraftMixin.java @@ -12,7 +12,6 @@ import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -26,17 +25,14 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import io.github.fabricators_of_create.porting_lib.event.client.ClientWorldEvents; import io.github.fabricators_of_create.porting_lib.event.client.InteractEvents; import io.github.fabricators_of_create.porting_lib.event.client.MinecraftTailCallback; import io.github.fabricators_of_create.porting_lib.event.client.ParticleManagerRegistrationCallback; import io.github.fabricators_of_create.porting_lib.event.client.RenderTickStartCallback; -import io.github.fabricators_of_create.porting_lib.event.common.AttackAirCallback; import io.github.fabricators_of_create.porting_lib.event.common.ModsLoadedCallback; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.main.GameConfig; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.MultiPlayerGameMode; @@ -92,26 +88,6 @@ private void addClientResources(GameConfig gameConfig, CallbackInfo ci) { new AddPackFindersEvent(PackType.CLIENT_RESOURCES, this.resourcePackRepository::pl$addPackFinder).sendEvent(); } - @Inject(method = "setLevel", at = @At("HEAD")) - public void port_lib$onHeadJoinWorld(ClientLevel world, CallbackInfo ci) { - if (this.level != null) { - ClientWorldEvents.UNLOAD.invoker().onWorldUnload((Minecraft) (Object) this, this.level); - } - } - - @Inject( - method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;)V", - at = @At( - value = "JUMP", - opcode = Opcodes.IFNULL, - ordinal = 1, - shift = Shift.AFTER - ) - ) - public void port_lib$onDisconnect(Screen screen, CallbackInfo ci) { - ClientWorldEvents.UNLOAD.invoker().onWorldUnload((Minecraft) (Object) this, this.level); - } - @Inject( method = "startAttack", at = @At( @@ -148,17 +124,6 @@ private void addClientResources(GameConfig gameConfig, CallbackInfo ci) { return original.call(gameMode, posBlock, directionFacing); // continue to continueDestroyBlock } - @Inject( - method = "startAttack", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/player/LocalPlayer;resetAttackStrengthTicker()V" - ) - ) - private void port_lib$onAttackMiss(CallbackInfoReturnable cir) { - AttackAirCallback.EVENT.invoker().attackAir(player); - } - @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;render(FJZ)V", shift = Shift.BEFORE)) private void port_lib$renderTickStart(CallbackInfo ci) { RenderTickStartCallback.EVENT.invoker().tick(); diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TagCollectorMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TagCollectorMixin.java new file mode 100644 index 000000000..4cb6451c6 --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TagCollectorMixin.java @@ -0,0 +1,19 @@ +package io.github.fabricators_of_create.porting_lib.mixin.client; + +import io.github.fabricators_of_create.porting_lib.event.common.TagsUpdatedEvent; +import net.minecraft.client.multiplayer.TagCollector; + +import net.minecraft.core.RegistryAccess; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TagCollector.class) +public class TagCollectorMixin { + @Inject(method = "updateTags", at = @At("TAIL")) + private void onUpdateTags(RegistryAccess registryAccess, boolean isIntegratedServerConnection, CallbackInfo ci) { + new TagsUpdatedEvent(registryAccess, true, isIntegratedServerConnection).sendEvent(); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TextureAtlasMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TextureAtlasMixin.java index 7419260bc..0d58a2384 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TextureAtlasMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/client/TextureAtlasMixin.java @@ -1,6 +1,7 @@ package io.github.fabricators_of_create.porting_lib.mixin.client; -import io.github.fabricators_of_create.porting_lib.event.client.TextureStitchCallback; +import io.github.fabricators_of_create.porting_lib.util.client.ClientHooks; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -11,8 +12,8 @@ @Mixin(TextureAtlas.class) public abstract class TextureAtlasMixin { - @Inject(method = "upload", at = @At("RETURN")) - private void port_lib$postStitch(SpriteLoader.Preparations preparations, CallbackInfo ci) { - TextureStitchCallback.POST.invoker().stitch((TextureAtlas) (Object) this); - } + @Inject(method = "upload", at = @At("RETURN")) + private void postStitch(SpriteLoader.Preparations preparations, CallbackInfo ci) { + ClientHooks.onTextureAtlasStitched((TextureAtlas) (Object) this); + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockBehavior$PropertiesMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockBehavior$PropertiesMixin.java index bf27476f4..f6589ec8d 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockBehavior$PropertiesMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockBehavior$PropertiesMixin.java @@ -18,7 +18,7 @@ public class BlockBehavior$PropertiesMixin { @WrapOperation( // isValidSpawn lambda - method = { "method_26239", "m_vuhrtmql", "lambda$new$1" }, + method = "method_26239", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;getLightEmission()I") ) private static int port_lib$customLight(BlockState state, Operation original, diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockEntityMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockEntityMixin.java index 9391f9b64..9838dd1c7 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockEntityMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockEntityMixin.java @@ -1,9 +1,8 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; -import io.github.fabricators_of_create.porting_lib.extensions.extensions.INBTSerializableCompound; +import net.minecraft.core.HolderLookup; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,19 +12,12 @@ import io.github.fabricators_of_create.porting_lib.util.BlockEntityHelper; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; @Mixin(BlockEntity.class) -public abstract class BlockEntityMixin implements BlockEntityExtensions, INBTSerializableCompound { +public abstract class BlockEntityMixin implements BlockEntityExtensions { @Unique private CompoundTag port_lib$extraData = null; - @Shadow - public abstract void load(CompoundTag tag); - - @Shadow - public abstract CompoundTag saveWithFullMetadata(); - @Inject(at = @At("RETURN"), method = "saveMetadata") private void port_lib$saveMetadata(CompoundTag nbt, CallbackInfo ci) { if (port_lib$extraData != null && !port_lib$extraData.isEmpty()) { @@ -33,37 +25,18 @@ public abstract class BlockEntityMixin implements BlockEntityExtensions, INBTSer } } - @Inject(at = @At("RETURN"), method = "load") - private void port_lib$load(CompoundTag tag, CallbackInfo ci) { + @Inject(at = @At("RETURN"), method = "loadWithComponents") + private void port_lib$load(CompoundTag tag, HolderLookup.Provider provider, CallbackInfo ci) { if (tag.contains(BlockEntityHelper.EXTRA_DATA_KEY)) { port_lib$extraData = tag.getCompound(BlockEntityHelper.EXTRA_DATA_KEY); } } - @Inject(method = "setRemoved", at = @At("TAIL")) - public void port_lib$invalidate(CallbackInfo ci) { - invalidateCaps(); - } - - @Override - public CompoundTag serializeNBT() { - return this.saveWithFullMetadata(); - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - deserializeNBT(null, nbt); - } - @Override - public CompoundTag getCustomData() { + public CompoundTag getPersistentData() { if (port_lib$extraData == null) { port_lib$extraData = new CompoundTag(); } return port_lib$extraData; } - - public void deserializeNBT(BlockState state, CompoundTag nbt) { - this.load(nbt); - } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockItemMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockItemMixin.java deleted file mode 100644 index 23bbd92d0..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/BlockItemMixin.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; - -import com.llamalad7.mixinextras.sugar.Local; - -import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; - -import net.minecraft.core.BlockPos; - -import net.minecraft.world.level.block.state.BlockState; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import io.github.fabricators_of_create.porting_lib.extensions.extensions.BlockItemExtensions; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; - -@Mixin(BlockItem.class) -public abstract class BlockItemMixin implements BlockItemExtensions { - @Inject(method = "useOn", at = @At("HEAD"), cancellable = true) - private void port_lib$beforePlace(UseOnContext context, CallbackInfoReturnable cir) { - InteractionResult result = BlockEvents.BEFORE_PLACE.invoker().beforePlace(new BlockPlaceContext(context)); - if (result != null) - cir.setReturnValue(result); - } - - @ModifyExpressionValue( - method = "useOn", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/item/BlockItem;place(Lnet/minecraft/world/item/context/BlockPlaceContext;)Lnet/minecraft/world/InteractionResult;" - ) - ) - private InteractionResult port_lib$afterPlace(InteractionResult placeResult, UseOnContext context) { - if (placeResult.consumesAction()) - BlockEvents.AFTER_PLACE.invoker().afterPlace(new BlockPlaceContext(context)); - return placeResult; - } - - @Inject(method = "place", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/InteractionResult;sidedSuccess(Z)Lnet/minecraft/world/InteractionResult;")) - private void port_lib$postProcessPlace(BlockPlaceContext context, CallbackInfoReturnable cir, @Local BlockPos blockPos, @Local BlockState blockState) { - BlockEvents.POST_PROCESS_PLACE.invoker().postProcessPlace(context, blockPos, blockState); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ChunkStatusMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ChunkStatusMixin.java deleted file mode 100644 index 62282f540..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ChunkStatusMixin.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.world.level.chunk.ChunkStatus; - -@Mixin(ChunkStatus.class) -public abstract class ChunkStatusMixin { - @Shadow - @Final - @Mutable - public static ChunkStatus FULL; -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DataFixersMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DataFixersMixin.java new file mode 100644 index 000000000..cffbbea5c --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DataFixersMixin.java @@ -0,0 +1,22 @@ +package io.github.fabricators_of_create.porting_lib.mixin.common; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.datafixers.DataFixerBuilder; + +import com.mojang.datafixers.schemas.Schema; + +import io.github.fabricators_of_create.porting_lib.fixes.ForgeBlockEntityFix; +import net.minecraft.util.datafix.DataFixers; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(DataFixers.class) +public class DataFixersMixin { + @Inject(method = "addFixers", at = @At("TAIL")) + private static void addBlockEntityDataFix(DataFixerBuilder dataFixerBuilder, CallbackInfo ci, @Local(index = 234) Schema lastSchema) { + dataFixerBuilder.addFixer(new ForgeBlockEntityFix(lastSchema, false)); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentHelperMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentHelperMixin.java index 5fb904e86..e829d6fd9 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentHelperMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentHelperMixin.java @@ -14,7 +14,6 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentCategory; import net.minecraft.world.item.enchantment.EnchantmentHelper; import io.github.fabricators_of_create.porting_lib.item.CustomEnchantmentLevelItem; @@ -30,70 +29,70 @@ @Mixin(EnchantmentHelper.class) public abstract class EnchantmentHelperMixin { - @Unique - private static Enchantment port_lib$currentEnchantment = null; - - @ModifyExpressionValue( - method = "getAvailableEnchantmentResults", - at = @At( - value = "INVOKE", - target = "Ljava/util/Iterator;next()Ljava/lang/Object;" - ) - ) - private static Object port_lib$grabEnchantment(Object o) { - if (o instanceof Enchantment e) { - port_lib$currentEnchantment = e; - } - return o; - } - - /** - * Same behavior as {@link EnchantmentMixin#port_lib$canEnchant(ItemStack, CallbackInfoReturnable)} - */ - @SuppressWarnings("JavadocReference") - @WrapOperation( - method = "getAvailableEnchantmentResults", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/item/enchantment/EnchantmentCategory;canEnchant(Lnet/minecraft/world/item/Item;)Z" - ) - ) - private static boolean port_lib$customEnchantability(EnchantmentCategory category, Item item, Operation original, - int level, ItemStack stack, boolean allowTreasure) { - Enchantment enchantment = port_lib$currentEnchantment; - if (enchantment instanceof CustomEnchantingTableBehaviorEnchantment custom) { - // custom enchantment? let the custom logic take over - return custom.canApplyAtEnchantingTable(stack); - } else if (enchantment != null && stack.getItem() instanceof CustomEnchantingBehaviorItem custom) { - // enchantment not custom, but item is - let item decide - return custom.canApplyAtEnchantingTable(stack, enchantment); - } - // neither - vanilla logic - return original.call(category, item); - } - - @ModifyReturnValue(method = "getItemEnchantmentLevel", at = @At("RETURN")) - private static int modifyEnchantmentLevel(int original, Enchantment enchantment, ItemStack stack) { - if (stack.getItem() instanceof CustomEnchantmentLevelItem custom) - return custom.modifyEnchantmentLevel(stack, enchantment, original); - return original; - } - - @ModifyReturnValue(method = "getEnchantments", at = @At("RETURN")) - private static Map customEnchantments(Map enchantments, ItemStack stack) { - if (!(enchantments instanceof HashMap)) // mutability is expected, fix it if something else changed it - enchantments = new LinkedHashMap<>(enchantments); - - if (stack.getItem() instanceof CustomEnchantmentsItem custom) - custom.modifyEnchantments(enchantments, stack); - return enchantments; - } - - @Inject(method = "runIterationOnItem", at = @At("HEAD"), cancellable = true) - private static void useCustomEnchantmentList(EnchantmentHelper.EnchantmentVisitor visitor, ItemStack stack, CallbackInfo ci) { - if (stack.getItem() instanceof CustomEnchantmentsItem) { - EnchantmentHelper.getEnchantments(stack).forEach(visitor::accept); - ci.cancel(); - } - } +// @Unique +// private static Enchantment port_lib$currentEnchantment = null; TODO: PORT +// +// @ModifyExpressionValue( +// method = "getAvailableEnchantmentResults", +// at = @At( +// value = "INVOKE", +// target = "Ljava/util/Iterator;next()Ljava/lang/Object;" +// ) +// ) +// private static Object port_lib$grabEnchantment(Object o) { +// if (o instanceof Enchantment e) { +// port_lib$currentEnchantment = e; +// } +// return o; +// } +// +// /** +// * Same behavior as {@link EnchantmentMixin#port_lib$canEnchant(ItemStack, CallbackInfoReturnable)} +// */ +// @SuppressWarnings("JavadocReference") +// @WrapOperation( +// method = "getAvailableEnchantmentResults", +// at = @At( +// value = "INVOKE", +// target = "Lnet/minecraft/world/item/enchantment/EnchantmentCategory;canEnchant(Lnet/minecraft/world/item/Item;)Z" +// ) +// ) +// private static boolean port_lib$customEnchantability(EnchantmentCategory category, Item item, Operation original, +// int level, ItemStack stack, boolean allowTreasure) { +// Enchantment enchantment = port_lib$currentEnchantment; +// if (enchantment instanceof CustomEnchantingTableBehaviorEnchantment custom) { +// // custom enchantment? let the custom logic take over +// return custom.canApplyAtEnchantingTable(stack); +// } else if (enchantment != null && stack.getItem() instanceof CustomEnchantingBehaviorItem custom) { +// // enchantment not custom, but item is - let item decide +// return custom.canApplyAtEnchantingTable(stack, enchantment); +// } +// // neither - vanilla logic +// return original.call(category, item); +// } +// +// @ModifyReturnValue(method = "getItemEnchantmentLevel", at = @At("RETURN")) +// private static int modifyEnchantmentLevel(int original, Enchantment enchantment, ItemStack stack) { +// if (stack.getItem() instanceof CustomEnchantmentLevelItem custom) +// return custom.modifyEnchantmentLevel(stack, enchantment, original); +// return original; +// } +// +// @ModifyReturnValue(method = "getEnchantments", at = @At("RETURN")) +// private static Map customEnchantments(Map enchantments, ItemStack stack) { +// if (!(enchantments instanceof HashMap)) // mutability is expected, fix it if something else changed it +// enchantments = new LinkedHashMap<>(enchantments); +// +// if (stack.getItem() instanceof CustomEnchantmentsItem custom) +// custom.modifyEnchantments(enchantments, stack); +// return enchantments; +// } +// +// @Inject(method = "runIterationOnItem", at = @At("HEAD"), cancellable = true) +// private static void useCustomEnchantmentList(EnchantmentHelper.EnchantmentVisitor visitor, ItemStack stack, CallbackInfo ci) { +// if (stack.getItem() instanceof CustomEnchantmentsItem) { +// EnchantmentHelper.getEnchantments(stack).forEach(visitor::accept); +// ci.cancel(); +// } +// } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentMenuMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentMenuMixin.java index 1cd448d93..2e0c5901a 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentMenuMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EnchantmentMenuMixin.java @@ -1,5 +1,6 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; +import net.minecraft.world.level.block.EnchantingTableBlock; import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; @@ -11,16 +12,15 @@ import net.minecraft.world.inventory.EnchantmentMenu; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.EnchantmentTableBlock; @Mixin(EnchantmentMenu.class) public abstract class EnchantmentMenuMixin { @ModifyVariable( - method = { "method_17411", "m_mpsetdhw", "lambda$slotsChanged$0" }, - at = @At(value = "STORE", ordinal = 0), ordinal = 0, remap = false + method = "method_17411", + at = @At(value = "STORE", ordinal = 1), ordinal = 0, remap = false ) private int port_lib$modifyEnchantValue(int obj, ItemStack stack, Level level, BlockPos pos) { - for (BlockPos blockPos : EnchantmentTableBlock.BOOKSHELF_OFFSETS) { + for (BlockPos blockPos : EnchantingTableBlock.BOOKSHELF_OFFSETS) { BlockPos actualPos = pos.offset(blockPos); BlockState state = level.getBlockState(actualPos); if (state.getBlock() instanceof EnchantmentBonusBlock bonusBlock) diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EntityMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EntityMixin.java index 03260a2cd..d82051696 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EntityMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/EntityMixin.java @@ -1,5 +1,7 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; +import net.minecraft.core.HolderLookup; + import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -35,21 +37,20 @@ public abstract class EntityMixin implements INBTSerializableCompound { @Unique @Override - public CompoundTag serializeNBT() { + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { + load(nbt); + } + + @Override + public CompoundTag serializeNBT(HolderLookup.Provider provider) { CompoundTag ret = new CompoundTag(); String id = getEncodeId(); if (id != null) { - ret.putString("id", id); + ret.putString("id", getEncodeId()); } return saveWithoutId(ret); } - @Unique - @Override - public void deserializeNBT(CompoundTag nbt) { - load(nbt); - } - // RUNNING EFFECTS @Inject( diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/GrindstoneMenuMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/GrindstoneMenuMixin.java index bd73fa708..b78756df1 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/GrindstoneMenuMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/GrindstoneMenuMixin.java @@ -6,8 +6,8 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvents; -import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvents.OnTakeItem; +import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvent; +import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvent.OnTakeItem; import io.github.fabricators_of_create.porting_lib.extensions.extensions.GrindstoneMenuExtension; import io.github.fabricators_of_create.porting_lib.util.PortingHooks; import net.minecraft.server.level.ServerLevel; @@ -34,10 +34,6 @@ @Mixin(GrindstoneMenu.class) public abstract class GrindstoneMenuMixin extends AbstractContainerMenu implements GrindstoneMenuExtension { - @Shadow - @Final - public Container repairSlots; - @Shadow @Final private Container resultSlots; @@ -47,23 +43,18 @@ protected GrindstoneMenuMixin(@Nullable MenuType menuType, int i) { } @Inject( - method = "createResult", + method = "computeResult", at = @At( value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", - ordinal = 3, + ordinal = 1, shift = At.Shift.AFTER ), cancellable = true ) - private void handleResult(CallbackInfo ci) { - ItemStack top = this.repairSlots.getItem(0); - ItemStack bottom = this.repairSlots.getItem(1); + private void handleResult(ItemStack top, ItemStack bottom, CallbackInfoReturnable cir) { this.xp = PortingHooks.onGrindstoneChange(top, bottom, this.resultSlots, -1); - if (this.xp != Integer.MIN_VALUE) { - ci.cancel(); - broadcastChanges(); - } + if (this.xp != Integer.MIN_VALUE) cir.setReturnValue(ItemStack.EMPTY); // NF Porting 1.20.5 check if this is correct } @Unique @@ -95,7 +86,7 @@ private void onGrindStoneTake(ServerLevel level, Vec3 pos, int amount, Operation Container input = this.menu.repairSlots; ItemStack top = input.getItem(0); ItemStack bottom = input.getItem(1); - this.takeEvent = new GrindstoneEvents.OnTakeItem(top, bottom, amount); + this.takeEvent = new GrindstoneEvent.OnTakeItem(top, bottom, amount); takeEvent.sendEvent(); if (!takeEvent.isCanceled()) original.call(level, pos, takeEvent.getXp()); diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ItemStackMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ItemStackMixin.java index 05b8cc520..7f9c5fb62 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ItemStackMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ItemStackMixin.java @@ -1,13 +1,11 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; -import com.llamalad7.mixinextras.injector.ModifyReturnValue; - -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; -import io.github.fabricators_of_create.porting_lib.extensions.extensions.INBTSerializableCompound; +import io.github.fabricators_of_create.porting_lib.core.util.MutableDataComponentHolder; import io.github.fabricators_of_create.porting_lib.extensions.extensions.ItemStackExtensions; import io.github.fabricators_of_create.porting_lib.item.DamageableItem; -import org.jetbrains.annotations.Nullable; +import net.minecraft.world.item.Item; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -15,51 +13,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import io.github.fabricators_of_create.porting_lib.item.CustomMaxCountItem; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @Mixin(ItemStack.class) -public abstract class ItemStackMixin implements INBTSerializableCompound, ItemStackExtensions { - - @Shadow - public abstract CompoundTag save(CompoundTag compoundTag); - - @Shadow - public abstract void setTag(@Nullable CompoundTag compoundTag); - +public abstract class ItemStackMixin implements MutableDataComponentHolder, ItemStackExtensions { @Shadow public abstract Item getItem(); - @Shadow - public abstract boolean hasTag(); - - @Shadow - private @Nullable CompoundTag tag; - - @Inject(method = "getMaxStackSize", at = @At("HEAD"), cancellable = true) - public void port_lib$onGetMaxCount(CallbackInfoReturnable cir) { - ItemStack self = (ItemStack) (Object) this; - Item item = self.getItem(); - if (item instanceof CustomMaxCountItem) { - cir.setReturnValue(((CustomMaxCountItem) item).getItemStackLimit(self)); - } - } - - @Override - public CompoundTag serializeNBT() { - CompoundTag nbt = new CompoundTag(); - this.save(nbt); - return nbt; - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - this.setTag(ItemStack.of(nbt).getTag()); - } - @Inject(method = "setDamageValue", at = @At("HEAD"), cancellable = true) public void port_lib$itemSetDamage(int damage, CallbackInfo ci) { if(getItem() instanceof DamageableItem damagableItem) { @@ -81,11 +41,4 @@ public void deserializeNBT(CompoundTag nbt) { cir.setReturnValue(damagableItem.getDamage((ItemStack) (Object) this)); } } - - @ModifyReturnValue(method = "getHideFlags", at = @At(value = "RETURN", ordinal = 1)) - public int port_lib$itemFlags(int val) { - if (val == 0 && !(this.hasTag() && this.tag.contains("HideFlags", 99))) - return getItem().getDefaultTooltipHideFlags(MixinHelper.cast(this)); - return val; - } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelChunkMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelChunkMixin.java index d39808cda..06d967eeb 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelChunkMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelChunkMixin.java @@ -52,8 +52,8 @@ public LevelChunkMixin(ChunkPos chunkPos, UpgradeData upgradeData, LevelHeightAc }); } - @Inject(method = { "method_31716", "m_pptwysxt", "lambda$replaceWithPacketData$3" }, - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BlockEntity;load(Lnet/minecraft/nbt/CompoundTag;)V"), + @Inject(method = "method_31716", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BlockEntity;loadWithComponents(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/core/HolderLookup$Provider;)V"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true ) private void port_lib$handleBlockEntityUpdateTag(BlockPos pos, BlockEntityType type, CompoundTag tag, CallbackInfo ci, BlockEntity blockEntity) { diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelMixin.java index 2d7329678..c2922d2aa 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LevelMixin.java @@ -7,26 +7,19 @@ import java.util.LinkedList; import java.util.List; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; - import com.llamalad7.mixinextras.sugar.Local; -import io.github.fabricators_of_create.porting_lib.block.LightEmissiveBlock; import io.github.fabricators_of_create.porting_lib.core.PortingLib; -import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; import io.github.fabricators_of_create.porting_lib.event.common.ExplosionEvents; import io.github.fabricators_of_create.porting_lib.extensions.extensions.BlockEntityExtensions; import io.github.fabricators_of_create.porting_lib.extensions.extensions.LevelExtensions; import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant; import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.ExplosionDamageCalculator; @@ -41,13 +34,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import io.github.fabricators_of_create.porting_lib.block.NeighborChangeListeningBlock; -import io.github.fabricators_of_create.porting_lib.block.WeakPowerCheckingBlock; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -178,23 +169,23 @@ public SnapshotParticipant snapshotParticipant() { } } - @Inject( - method = "explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Level$ExplosionInteraction;ZLnet/minecraft/core/particles/ParticleOptions;Lnet/minecraft/core/particles/ParticleOptions;Lnet/minecraft/sounds/SoundEvent;)Lnet/minecraft/world/level/Explosion;", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/level/Explosion;explode()V" - ), - locals = LocalCapture.CAPTURE_FAILHARD, - cancellable = true - ) - public void port_lib$onStartExplosion(Entity entity, DamageSource damageSource, ExplosionDamageCalculator explosionDamageCalculator, - double d, double e, double f, float g, boolean bl, Level.ExplosionInteraction explosionInteraction, - boolean bl2, ParticleOptions particleOptions, ParticleOptions particleOptions2, SoundEvent soundEvent, - CallbackInfoReturnable cir, @Local(ordinal = 0) Explosion explosion) { - if (ExplosionEvents.START.invoker().onExplosionStart((Level) (Object) this, explosion)) { - cir.setReturnValue(explosion); - } - } +// @Inject( TODO: PORT +// method = "explode(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Level$ExplosionInteraction;ZLnet/minecraft/core/particles/ParticleOptions;Lnet/minecraft/core/particles/ParticleOptions;Lnet/minecraft/sounds/SoundEvent;)Lnet/minecraft/world/level/Explosion;", +// at = @At( +// value = "INVOKE", +// target = "Lnet/minecraft/world/level/Explosion;explode()V" +// ), +// locals = LocalCapture.CAPTURE_FAILHARD, +// cancellable = true +// ) +// public void port_lib$onStartExplosion(Entity entity, DamageSource damageSource, ExplosionDamageCalculator explosionDamageCalculator, +// double d, double e, double f, float g, boolean bl, Level.ExplosionInteraction explosionInteraction, +// boolean bl2, ParticleOptions particleOptions, ParticleOptions particleOptions2, SoundEvent soundEvent, +// CallbackInfoReturnable cir, @Local(ordinal = 0) Explosion explosion) { +// if (ExplosionEvents.START.invoker().onExplosionStart((Level) (Object) this, explosion)) { +// cir.setReturnValue(explosion); +// } +// } @Inject(method = "tickBlockEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;)V", shift = Shift.AFTER)) public void port_lib$pendingBlockEntities(CallbackInfo ci) { @@ -257,10 +248,4 @@ public void markAndNotifyBlock(BlockPos pos, @Nullable LevelChunk levelchunk, Bl } } } - - @Inject(method = "updateNeighborsAt", at = @At("HEAD")) - private void neighborNotify(BlockPos pPos, Block block, CallbackInfo ci) { - BlockEvents.NeighborNotifyEvent event = new BlockEvents.NeighborNotifyEvent((Level) (Object) this, pPos, this.getBlockState(pPos), EnumSet.allOf(Direction.class), false); - event.sendEvent(); - } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LivingEntityMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LivingEntityMixin.java index 0c114942e..c9b681b1f 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LivingEntityMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/LivingEntityMixin.java @@ -1,8 +1,12 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + import io.github.fabricators_of_create.porting_lib.block.CustomScaffoldingBlock; -import org.jetbrains.annotations.Nullable; +import io.github.fabricators_of_create.porting_lib.item.ShieldBlockItem; + +import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -19,7 +23,6 @@ import io.github.fabricators_of_create.porting_lib.block.CustomFrictionBlock; import io.github.fabricators_of_create.porting_lib.block.CustomLandingEffectsBlock; -import io.github.fabricators_of_create.porting_lib.event.common.PotionEvents; import io.github.fabricators_of_create.porting_lib.item.ContinueUsingItem; import io.github.fabricators_of_create.porting_lib.item.EntitySwingListenerItem; import io.github.fabricators_of_create.porting_lib.item.EquipmentItem; @@ -27,13 +30,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -53,6 +53,10 @@ public abstract class LivingEntityMixin extends Entity { @Shadow public abstract InteractionHand getUsedItemHand(); + @Shadow + @NotNull + public abstract ItemStack getWeaponItem(); + public LivingEntityMixin(EntityType entityType, Level world) { super(entityType, world); } @@ -107,29 +111,6 @@ protected void updateFallState(double y, boolean onGround, BlockState state, Blo } } - @Inject( - method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", - at = @At( - value = "INVOKE", - target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", - shift = Shift.BY, - by = 3, - remap = false - ), - locals = LocalCapture.CAPTURE_FAILHARD - ) - public void port_lib$addEffect(MobEffectInstance newEffect, @Nullable Entity source, CallbackInfoReturnable cir, - MobEffectInstance oldEffect) { - PotionEvents.POTION_ADDED.invoker().onPotionAdded((LivingEntity) (Object) this, newEffect, oldEffect, source); - } - - @Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true) - public void port_lib$canBeAffected(MobEffectInstance effect, CallbackInfoReturnable cir) { - InteractionResult result = PotionEvents.POTION_APPLICABLE.invoker().onPotionApplicable((LivingEntity) (Object) this, effect); - if (result != InteractionResult.PASS) - cir.setReturnValue(result == InteractionResult.SUCCESS); - } - @Inject(method = "updatingUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;", shift = Shift.AFTER, ordinal = 1)) public void port_lib$onUsingTick(CallbackInfo ci) { if (useItem.getItem() instanceof UsingTickItem usingTickItem) { @@ -166,4 +147,14 @@ private boolean customScaffoldingMovement(boolean original) { return custom.isScaffolding(state, level(), blockPosition(), (LivingEntity) (Object) this); return original; } + + @ModifyReturnValue(method = "canDisableShield", at = @At("RETURN")) + private boolean canDisableShieldItem(boolean original) { + if (!original) { + ItemStack weapon = getWeaponItem(); + if (weapon.getItem() instanceof ShieldBlockItem shieldBlockItem) + return shieldBlockItem.canDisableShield(weapon, this.useItem, (LivingEntity) (Object) this, (LivingEntity) (Object) this); + } + return original; + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/MobEffectInstanceMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/MobEffectInstanceMixin.java deleted file mode 100644 index b2ef8e528..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/MobEffectInstanceMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; - -import io.github.fabricators_of_create.porting_lib.extensions.extensions.MobEffectInstanceExtensions; -import net.minecraft.core.Holder; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.effect.MobEffectInstance; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(MobEffectInstance.class) -public abstract class MobEffectInstanceMixin implements MobEffectInstanceExtensions { - - - @Shadow - public abstract Holder getEffect(); - - private java.util.List curativeItems; - - @Override - public java.util.List getCurativeItems() { - if (this.curativeItems == null) //Lazy load this so that we don't create a circular dep on Items. - this.curativeItems = getEffect().value().getCurativeItems(); - return this.curativeItems; - } - @Override - public void setCurativeItems(java.util.List curativeItems) { - this.curativeItems = curativeItems; - } - private static MobEffectInstance readCurativeItems(MobEffectInstance effect, CompoundTag nbt) { - if (nbt.contains("CurativeItems", net.minecraft.nbt.Tag.TAG_LIST)) { - java.util.List items = new java.util.ArrayList(); - net.minecraft.nbt.ListTag list = nbt.getList("CurativeItems", net.minecraft.nbt.Tag.TAG_COMPOUND); - for (int i = 0; i < list.size(); i++) { - items.add(net.minecraft.world.item.ItemStack.of(list.getCompound(i))); - } - effect.setCurativeItems(items); - } - - return effect; - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PackRepositoryMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PackRepositoryMixin.java deleted file mode 100644 index 5eac582c7..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PackRepositoryMixin.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; - -import io.github.fabricators_of_create.porting_lib.event.common.AddPackFindersCallback; -import io.github.fabricators_of_create.porting_lib.extensions.PackRepositoryExtension; - -import net.minecraft.server.packs.repository.PackRepository; -import net.minecraft.server.packs.repository.RepositorySource; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Set; - -@Mixin(PackRepository.class) -public class PackRepositoryMixin implements PackRepositoryExtension { - @Shadow - @Final - private Set sources; - - @Override - public synchronized void pl$addPackFinder(RepositorySource packFinder) { - this.sources.add(packFinder); - } - - @Inject(method = "", at = @At("TAIL")) - public void addModdedPacks(RepositorySource[] repositorySources, CallbackInfo ci) { - AddPackFindersCallback.EVENT.invoker().addPack(this::pl$addPackFinder); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PlayerMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PlayerMixin.java index 331ff786f..c8663b68a 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PlayerMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/PlayerMixin.java @@ -21,26 +21,10 @@ @Mixin(Player.class) public abstract class PlayerMixin extends LivingEntity { - @Shadow - public abstract void disableShield(boolean sprinting); - protected PlayerMixin(EntityType entityType, Level level) { super(entityType, level); } - @Inject(method = "blockUsingShield", at = @At("TAIL")) - public void port_lib$blockShieldItem(LivingEntity entity, CallbackInfo ci) { - if(entity.getMainHandItem().getItem() instanceof ShieldBlockItem shieldBlockItem) { - if (shieldBlockItem.canDisableShield(entity.getMainHandItem(), this.useItem, this, entity)) - disableShield(true); - } - } - - @Inject(method = "attack", at = @At("HEAD"), cancellable = true) - public void port_lib$itemAttack(Entity targetEntity, CallbackInfo ci) { - if(getMainHandItem().getItem().onLeftClickEntity(getMainHandItem(), (Player) (Object) this, targetEntity)) ci.cancel(); - } - @ModifyReturnValue(method = "createAttributes", at = @At("RETURN")) private static AttributeSupplier.Builder port_lib$addKnockback(AttributeSupplier.Builder original) { return original.add(Attributes.ATTACK_KNOCKBACK); diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ReloadableServerResourcesMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ReloadableServerResourcesMixin.java index 99e26813d..5677cd56e 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ReloadableServerResourcesMixin.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ReloadableServerResourcesMixin.java @@ -1,18 +1,24 @@ package io.github.fabricators_of_create.porting_lib.mixin.common; -import io.github.fabricators_of_create.porting_lib.event.common.TagsUpdatedCallback; -import net.minecraft.core.RegistryAccess; +import io.github.fabricators_of_create.porting_lib.event.common.TagsUpdatedEvent; +import net.minecraft.server.ReloadableServerRegistries; import net.minecraft.server.ReloadableServerResources; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ReloadableServerResources.class) public abstract class ReloadableServerResourcesMixin { - @Inject(method = "updateRegistryTags(Lnet/minecraft/core/RegistryAccess;)V", at = @At("TAIL")) - public void port_lib$updateTags(RegistryAccess dynamicRegistryManager, CallbackInfo ci) { - TagsUpdatedCallback.EVENT.invoker().onTagsUpdated(dynamicRegistryManager); + @Shadow + @Final + private ReloadableServerRegistries.Holder fullRegistryHolder; + + @Inject(method = "updateRegistryTags()V", at = @At("TAIL")) + public void port_lib$updateTags(CallbackInfo ci) { + new TagsUpdatedEvent(this.fullRegistryHolder.get(), false, false).sendEvent(); } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/SpawnEggItemMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/SpawnEggItemMixin.java new file mode 100644 index 000000000..805ef2b9c --- /dev/null +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/SpawnEggItemMixin.java @@ -0,0 +1,30 @@ +package io.github.fabricators_of_create.porting_lib.mixin.common; + +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; + +import io.github.fabricators_of_create.porting_lib.util.DeferredSpawnEggItem; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.SpawnEggItem; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +@Mixin(SpawnEggItem.class) +public class SpawnEggItemMixin { + @Inject(method = "byId", at = @At("HEAD"), cancellable = true) + private static void lazyMap(EntityType entityType, CallbackInfoReturnable cir) { + var ret = DeferredSpawnEggItem.deferredOnlyById(entityType); + if (ret != null) + cir.setReturnValue(ret); + } + + @WrapWithCondition(method = "", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) + private boolean cancelIfNull(Map instance, Object key, Object v) { + return key != null; + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/StartAttackingMixin.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/StartAttackingMixin.java deleted file mode 100644 index 9926c6fb4..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/StartAttackingMixin.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; - -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Predicate; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import com.mojang.datafixers.kinds.Const; -import com.mojang.datafixers.kinds.OptionalBox; -import com.mojang.datafixers.util.Unit; - -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents.ChangeTarget.ChangeTargetEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents.ChangeTarget.ChangeTargetEvent.LivingTargetType; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.behavior.StartAttacking; -import net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor; - -@Mixin(StartAttacking.class) -public class StartAttackingMixin { - @Inject( - method = "method_47123(Ljava/util/function/Predicate;Ljava/util/function/Function;Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Mob;J)Z", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;set(Ljava/lang/Object;)V" - ), - cancellable = true - ) - private static void port_lib$onChangeTarget(Predicate predicate, Function> function, MemoryAccessor, LivingEntity> memoryAccessor, MemoryAccessor memoryAccessor2, ServerLevel serverLevel, Mob mob, long l, CallbackInfoReturnable cir, @Local LivingEntity livingEntity, @Share("changeTargetEvent") LocalRef changeTargetEvent) { - changeTargetEvent.set(new ChangeTargetEvent(mob, livingEntity, LivingTargetType.BEHAVIOR_TARGET)); - changeTargetEvent.get().sendEvent(); - if (changeTargetEvent.get().isCanceled()) - cir.setReturnValue(false); - } - - @WrapOperation( - method = "method_47123(Ljava/util/function/Predicate;Ljava/util/function/Function;Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Mob;J)Z", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;set(Ljava/lang/Object;)V" - ) - ) - private static void port_lib$wrapToChangeTarget(MemoryAccessor, LivingEntity> instance, Object object, Operation original, @Share("changeTargetEvent") LocalRef changeTargetEvent) { - original.call(instance, changeTargetEvent.get().getNewTarget()); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/AbstractSpawnerHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/AbstractSpawnerHelper.java index 3bb61bdc6..1a945d2d9 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/AbstractSpawnerHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/AbstractSpawnerHelper.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.BaseSpawnerAccessor; import net.minecraft.util.random.SimpleWeightedRandomList; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ArmorTextureRegistry.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ArmorTextureRegistry.java deleted file mode 100644 index ac1e1b206..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ArmorTextureRegistry.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ArmorMaterial; - -import javax.annotation.Nullable; - -import java.util.IdentityHashMap; -import java.util.Map; - -/** - * A Map of ArmorMaterials to ResourceLocations for armor textures. - */ -public class ArmorTextureRegistry { - private static final Map TEXTURES = new IdentityHashMap<>(); - - public static void register(ArmorMaterial material, ResourceLocation location) { - TEXTURES.put(material, location); - } - - @Nullable - public static ResourceLocation get(ArmorMaterial material) { - return TEXTURES.get(material); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BiomeManagerHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BiomeManagerHelper.java index 7fd92939d..e5e9e0e5a 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BiomeManagerHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BiomeManagerHelper.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.BiomeManagerAccessor; import net.minecraft.world.level.biome.BiomeManager; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockEntityHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockEntityHelper.java index 02be99f32..0f63b9636 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockEntityHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockEntityHelper.java @@ -1,5 +1,5 @@ package io.github.fabricators_of_create.porting_lib.util; public class BlockEntityHelper { - public static final String EXTRA_DATA_KEY = "ForgeData"; + public static final String EXTRA_DATA_KEY = "PortingLibData"; } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockSnapshot.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockSnapshot.java deleted file mode 100644 index 93556f409..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/BlockSnapshot.java +++ /dev/null @@ -1,182 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import java.lang.ref.WeakReference; -import java.util.Objects; - -import javax.annotation.Nullable; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -/** - * Represents a captured snapshot of a block which will not change - * automatically. - *

- * Unlike Block, which only one object can exist per coordinate, BlockSnapshot - * can exist multiple times for any given Block. - */ -public class BlockSnapshot { - private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockSnapshot", "false")); - - private final ResourceKey dim; - private final BlockPos pos; - private final int flags; - private final BlockState block; - @Nullable - private final CompoundTag nbt; - - @Nullable - private WeakReference level; - private String toString = null; - - private BlockSnapshot(ResourceKey dim, LevelAccessor level, BlockPos pos, BlockState state, @Nullable CompoundTag nbt, int flags) { - this.dim = dim; - this.pos = pos.immutable(); - this.block = state; - this.flags = flags; - this.nbt = nbt; - - this.level = new WeakReference<>(level); - - if (DEBUG) - System.out.println("Created " + this.toString()); - } - - public static BlockSnapshot create(ResourceKey dim, LevelAccessor world, BlockPos pos) { - return create(dim, world, pos, 3); - } - - public static BlockSnapshot create(ResourceKey dim, LevelAccessor world, BlockPos pos, int flag) { - return new BlockSnapshot(dim, world, pos, world.getBlockState(pos), getBlockEntityTag(world.getBlockEntity(pos)), flag); - } - - @Nullable - private static CompoundTag getBlockEntityTag(@Nullable BlockEntity te) { - return te == null ? null : te.saveWithFullMetadata(); - } - - public BlockState getCurrentBlock() { - LevelAccessor world = getLevel(); - return world == null ? Blocks.AIR.defaultBlockState() : world.getBlockState(this.pos); - } - - @Nullable - public LevelAccessor getLevel() { - LevelAccessor world = this.level != null ? this.level.get() : null; - if (world == null) { - world = ServerLifecycleHooks.getCurrentServer().getLevel(this.dim); - this.level = new WeakReference(world); - } - return world; - } - - public BlockState getReplacedBlock() { - return this.block; - } - - @Nullable - public BlockEntity getBlockEntity() { - return getTag() != null ? BlockEntity.loadStatic(getPos(), getReplacedBlock(), getTag()) : null; - } - - public boolean restore() { - return restore(false); - } - - public boolean restore(boolean force) - { - return restore(force, true); - } - - public boolean restore(boolean force, boolean notifyNeighbors) { - return restoreToLocation(getLevel(), getPos(), force, notifyNeighbors); - } - - public boolean restoreToLocation(LevelAccessor world, BlockPos pos, boolean force, boolean notifyNeighbors) { - BlockState current = getCurrentBlock(); - BlockState replaced = getReplacedBlock(); - - int flags = notifyNeighbors ? Block.UPDATE_ALL : Block.UPDATE_CLIENTS; - - if (current != replaced) { - if (force) - world.setBlock(pos, replaced, flags); - else - return false; - } - - world.setBlock(pos, replaced, flags); - if (world instanceof Level) - ((Level)world).sendBlockUpdated(pos, current, replaced, flags); - - BlockEntity te = null; - if (getTag() != null) { - te = world.getBlockEntity(pos); - if (te != null) { - te.load(getTag()); - te.setChanged(); - } - } - - if (DEBUG) - System.out.println("Restored " + this.toString()); - return true; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - - final BlockSnapshot other = (BlockSnapshot) obj; - return this.dim.equals(other.dim) && - this.pos.equals(other.pos) && - this.block == other.block && - this.flags == other.flags && - Objects.equals(this.nbt, other.nbt); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 73 * hash + this.dim.hashCode(); - hash = 73 * hash + this.pos.hashCode(); - hash = 73 * hash + this.block.hashCode(); - hash = 73 * hash + this.flags; - hash = 73 * hash + Objects.hashCode(this.getTag()); - return hash; - } - - @Override - public String toString() { - if (toString == null) { - this.toString = - "BlockSnapshot[" + - "World:" + this.dim.location() + ',' + - "Pos: " + this.pos + ',' + - "State: " + this.block + ',' + - "Flags: " + this.flags + ',' + - "NBT: " + (this.nbt == null ? "null" : this.nbt.toString()) + - ']'; - } - return this.toString; - } - - public BlockPos getPos() { return pos; } - - - public int getFlag() { return flags; } - - @Nullable - public CompoundTag getTag() { return nbt; } - -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazySpawnEggItem.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/DeferredSpawnEggItem.java similarity index 51% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazySpawnEggItem.java rename to modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/DeferredSpawnEggItem.java index 5e0b1ad01..f46bade0c 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazySpawnEggItem.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/DeferredSpawnEggItem.java @@ -1,31 +1,56 @@ package io.github.fabricators_of_create.porting_lib.util; +import java.util.ArrayList; import java.util.IdentityHashMap; +import java.util.List; import java.util.Map; import java.util.function.Supplier; - -import javax.annotation.Nullable; - -import net.fabricmc.api.EnvType; -import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.dispenser.DispenseItemBehavior; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.SpawnEggItem; +import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.gameevent.GameEvent; -public class LazySpawnEggItem extends SpawnEggItem { +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +public class DeferredSpawnEggItem extends SpawnEggItem { + public static final List MOD_EGGS = new ArrayList<>(); + private static final Map, DeferredSpawnEggItem> TYPE_MAP = new IdentityHashMap<>(); + private final Supplier> typeSupplier; + + public DeferredSpawnEggItem(Supplier> type, int backgroundColor, int highlightColor, Properties props) { + super(null, backgroundColor, highlightColor, props); + this.typeSupplier = type; + + MOD_EGGS.add(this); + } + + @Nullable + protected DispenseItemBehavior createDispenseBehavior() { + return DEFAULT_DISPENSE_BEHAVIOR; + } + + @ApiStatus.Internal + @Nullable + public static SpawnEggItem deferredOnlyById(@Nullable EntityType type) { + return TYPE_MAP.get(type); + } + + protected EntityType getDefaultType() { + return this.typeSupplier.get(); + } - private static final Map, LazySpawnEggItem> TYPE_MAP = new IdentityHashMap<>(); private static final DispenseItemBehavior DEFAULT_DISPENSE_BEHAVIOR = (source, stack) -> { Direction face = source.state().getValue(DispenserBlock.FACING); - EntityType type = ((SpawnEggItem)stack.getItem()).getType(stack.getTag()); + EntityType type = ((SpawnEggItem) stack.getItem()).getType(stack); try { type.spawn(source.level(), stack, null, source.pos().relative(face), MobSpawnType.DISPENSER, face != Direction.UP, false); @@ -38,41 +63,26 @@ public class LazySpawnEggItem extends SpawnEggItem { source.level().gameEvent(GameEvent.ENTITY_PLACE, source.pos(), GameEvent.Context.of(source.state())); return stack; }; - private final Supplier> typeSupplier; - - public LazySpawnEggItem(Supplier> type, int backgroundColor, int highlightColor, Properties props) { - super(null, backgroundColor, highlightColor, props); - this.typeSupplier = type; - - DispenseItemBehavior dispenseBehavior = this.createDispenseBehavior(); - if (dispenseBehavior != null) { - DispenserBlock.registerBehavior(this, dispenseBehavior); - } - - TYPE_MAP.put(this.typeSupplier.get(), this); - - EnvExecutor.runWhenOn(EnvType.CLIENT, () -> () -> ColorProviderRegistry.ITEM.register((stack, layer) -> getColor(layer), this)); - } - - @Nullable - public static SpawnEggItem fromEntityType(@Nullable EntityType type) { - SpawnEggItem ret = TYPE_MAP.get(type); - return ret != null ? ret : SpawnEggItem.byId(type); - } @Override - public EntityType getType(@Nullable CompoundTag tag) { - EntityType type = super.getType(tag); - return type != null ? type : typeSupplier.get(); + public EntityType getType(ItemStack p_330335_) { + CustomData customdata = p_330335_.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY); + return !customdata.isEmpty() ? customdata.read(ENTITY_TYPE_FIELD_CODEC).result().orElse(getDefaultType()) : getDefaultType(); } @Override public FeatureFlagSet requiredFeatures() { - return this.typeSupplier.get().requiredFeatures(); + return getDefaultType().requiredFeatures(); } - @Nullable - protected DispenseItemBehavior createDispenseBehavior() { - return DEFAULT_DISPENSE_BEHAVIOR; + public static void init() { + MOD_EGGS.forEach(egg -> { + DispenseItemBehavior dispenseBehavior = egg.createDispenseBehavior(); + if (dispenseBehavior != null) { + DispenserBlock.registerBehavior(egg, dispenseBehavior); + } + + TYPE_MAP.put(egg.typeSupplier.get(), egg); + }); } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/FontRenderUtil.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/FontRenderUtil.java index 1d1da45f1..0baa5631f 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/FontRenderUtil.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/FontRenderUtil.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor.FontAccessor; import net.fabricmc.api.EnvType; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/GameRendererHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/GameRendererHelper.java index d8102e83d..388d457a9 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/GameRendererHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/GameRendererHelper.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor.GameRendererAccessor; import net.minecraft.client.Camera; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemRendererHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemRendererHelper.java index fee1e35f2..be9d70caa 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemRendererHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemRendererHelper.java @@ -5,7 +5,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor.ItemRendererAccessor; import net.fabricmc.api.EnvType; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/KeyBindingHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/KeyBindingHelper.java index 8977150c4..07710d40e 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/KeyBindingHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/KeyBindingHelper.java @@ -3,7 +3,7 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.platform.InputConstants.Key; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.client.accessor.KeyMappingAccessor; import net.fabricmc.api.EnvType; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazyOptional.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazyOptional.java deleted file mode 100644 index 550ccdc2f..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/LazyOptional.java +++ /dev/null @@ -1,159 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import java.util.HashSet; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import io.github.fabricators_of_create.porting_lib.common.util.NonNullConsumer; -import io.github.fabricators_of_create.porting_lib.common.util.NonNullFunction; -import io.github.fabricators_of_create.porting_lib.common.util.NonNullSupplier; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.MethodsReturnNonnullByDefault; - -/** - * This is pretty much the Forge class copied over, theres really not much change you can do while keeping things functioning. - * Made some things public and added {@link #getValueUnsafer()} to allow for Bad Ideasâ„¢ - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class LazyOptional { - public static final @Nonnull LazyOptional EMPTY = new LazyOptional<>(null); - private static final Logger LOGGER = LogManager.getLogger(); - public NonNullSupplier supplier; - private final Object lock = new Object(); - // null -> not resolved yet - // non-null and contains non-null value -> resolved - // non-null and contains null -> resolved, but supplier returned null (contract violation) - private Mutable resolved; - private final Set>> listeners = new HashSet<>(); - private boolean isValid = true; - - private LazyOptional(@Nullable NonNullSupplier instanceSupplier) { - this.supplier = instanceSupplier; - } - - public static LazyOptional of(final @Nullable NonNullSupplier instanceSupplier) { - return instanceSupplier == null ? empty() : new LazyOptional<>(instanceSupplier); - } - - public static LazyOptional fromOptional(final @Nullable Optional regularOptional) { - return ofObject(regularOptional.orElse(null)); - } - - public static LazyOptional ofObject(@Nullable T o) { - return o == null ? empty() : LazyOptional.of(() -> o); - } - - public static LazyOptional empty() { - return EMPTY.cast(); - } - - @SuppressWarnings("unchecked") - public LazyOptional cast() { - return (LazyOptional) this; - } - - private @Nullable T getValue() { - if (!isValid || supplier == null) { - return null; - } - if (resolved == null) { - synchronized (lock) { - if (resolved == null) { - T temp = supplier.get(); - if (temp == null) { - LOGGER.catching(Level.WARN, new NullPointerException("Supplier should not return null value")); - } - resolved = new MutableObject<>(temp); - } - } - } - return resolved.getValue(); - } - - private T getValueUnsafe() { - T ret = getValue(); - if (ret == null) { - throw new IllegalStateException("LazyOptional is empty or otherwise returned null from getValue() unexpectedly"); - } - return ret; - } - - public T getValueUnsafer() { - return orElse(null); - } - - public boolean isPresent() { - return supplier != null && isValid; - } - - public void ifPresent(NonNullConsumer consumer) { - Objects.requireNonNull(consumer); - T val = getValue(); - if (isValid && val != null) - consumer.accept(val); - } - - public LazyOptional lazyMap(NonNullFunction mapper) { - Objects.requireNonNull(mapper); - return isPresent() ? of(() -> mapper.apply(getValueUnsafe())) : empty(); - } - - public Optional map(NonNullFunction mapper) { - Objects.requireNonNull(mapper); - return isPresent() ? Optional.of(mapper.apply(getValueUnsafe())) : Optional.empty(); - } - - public Optional filter(Predicate predicate) { - Objects.requireNonNull(predicate); - final T value = getValue(); - return value != null && predicate.test(value) ? Optional.of(value) : Optional.empty(); - } - - public Optional resolve() { - return isPresent() ? Optional.of(getValueUnsafe()) : Optional.empty(); - } - - public T orElse(T other) { - T val = getValue(); - return val != null ? val : other; - } - - public T orElseGet(NonNullSupplier other) { - T val = getValue(); - return val != null ? val : other.get(); - } - - public T orElseThrow(NonNullSupplier exceptionSupplier) throws X { - T val = getValue(); - if (val != null) - return val; - throw exceptionSupplier.get(); - } - - public void addListener(NonNullConsumer> listener) { - if (isPresent()) { - this.listeners.add(listener); - } else { - listener.accept(this); - } - } - - public void invalidate() { - if (this.isValid) { - this.isValid = false; - this.listeners.forEach(e -> e.accept(this)); - } - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecartAndRailUtil.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecartAndRailUtil.java index d5e1975f0..0bc2d597a 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecartAndRailUtil.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecartAndRailUtil.java @@ -19,7 +19,7 @@ public class MinecartAndRailUtil { // rails - public static final TagKey ACTIVATOR_RAILS = TagKey.create(Registries.BLOCK, new ResourceLocation("c", "rails/activator")); + public static final TagKey ACTIVATOR_RAILS = TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("c", "rails/activator")); public static boolean isActivatorRail(Block rail) { return rail.builtInRegistryHolder().is(ACTIVATOR_RAILS); diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecraftServerUtil.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecraftServerUtil.java index 63b8e4c87..7dc108d32 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecraftServerUtil.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/MinecraftServerUtil.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.MinecraftServerAccessor; import net.minecraft.server.MinecraftServer; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/NBTSerializer.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/NBTSerializer.java deleted file mode 100644 index bc9d5ad35..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/NBTSerializer.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import io.github.fabricators_of_create.porting_lib.core.util.INBTSerializable; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; - -public class NBTSerializer { - public static void deserializeNBT(Object o, Tag nbt) { - ((INBTSerializable) o).deserializeNBT(nbt); - } - - public static Tag serializeNBT(Object o) { - return ((INBTSerializable) o).serializeNBT(); - } - - public static CompoundTag serializeNBTCompound(Object o) { - Tag tag = ((INBTSerializable) o).serializeNBT(); - if (tag instanceof CompoundTag c) - return c; - throw new RuntimeException("Cannot use serializeNBTCompound with a type that does not return a CompoundTag"); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PlayerEntityHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PlayerEntityHelper.java index 087ed19d3..3288dc847 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PlayerEntityHelper.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PlayerEntityHelper.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.util; -import io.github.fabricators_of_create.porting_lib.common.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.PlayerAccessor; import net.minecraft.world.entity.player.Player; diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java index 45b018336..62b0126be 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PortingHooks.java @@ -1,38 +1,22 @@ package io.github.fabricators_of_create.porting_lib.util; -import javax.annotation.Nullable; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.ExperienceOrb; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; - -import net.fabricmc.api.EnvType; -import net.minecraft.server.TickTask; -import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.level.block.LevelEvent; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; -import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; -import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvents; -import io.github.fabricators_of_create.porting_lib.extensions.extensions.BlockItemExtensions; -import net.fabricmc.fabric.api.event.registry.RegistryEntryRemovedCallback; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; -import net.minecraft.server.level.ServerPlayer; +import io.github.fabricators_of_create.porting_lib.event.common.GrindstoneEvent; import net.minecraft.world.Container; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; + +import java.util.function.Function; @SuppressWarnings({"removal", "UnstableApiUsage"}) public class PortingHooks { @@ -43,88 +27,39 @@ public static boolean isCorrectToolForDrops(@NotNull BlockState state, @NotNull return player.hasCorrectToolForDrops(state); } - public static int onBlockBreakEvent(Level world, GameType gameType, ServerPlayer entityPlayer, BlockPos pos) { - // Logic from tryHarvestBlock for pre-canceling the event - boolean preCancelEvent = false; - ItemStack itemstack = entityPlayer.getMainHandItem(); - if (!itemstack.isEmpty() && !itemstack.getItem().canAttackBlock(world.getBlockState(pos), world, pos, entityPlayer)) { - preCancelEvent = true; - } - - if (gameType.isBlockPlacingRestricted()) { - if (gameType == GameType.SPECTATOR) - preCancelEvent = true; - - if (!entityPlayer.mayBuild()) { - if (itemstack.isEmpty() || !itemstack.hasAdventureModeBreakTagForBlock(world.registryAccess().registryOrThrow(Registries.BLOCK), new BlockInWorld(world, pos, false))) - preCancelEvent = true; - } - } - - // Tell client the block is gone immediately then process events - if (world.getBlockEntity(pos) == null) { - entityPlayer.connection.send(new ClientboundBlockUpdatePacket(pos, world.getFluidState(pos).createLegacyBlock())); - } - - // Post the block break event - BlockState state = world.getBlockState(pos); - BlockEvents.BreakEvent event = new BlockEvents.BreakEvent(world, pos, state, entityPlayer); - event.setCanceled(preCancelEvent); - event.sendEvent(); - - // Handle if the event is canceled - if (event.isCanceled()) { - // Let the client know the block still exists - entityPlayer.connection.send(new ClientboundBlockUpdatePacket(world, pos)); - - // Update any tile entity data for this block - BlockEntity blockEntity = world.getBlockEntity(pos); - if (blockEntity != null) { - Packet pkt = blockEntity.getUpdatePacket(); - if (pkt != null) { - entityPlayer.connection.send(pkt); - } - } - } - return event.isCanceled() ? -1 : event.getExpToDrop(); - } - - public static void init() { - EntityEvents.ON_JOIN_WORLD.register((entity, world, loadedFromDisk) -> { - if (entity.getClass().equals(ItemEntity.class)) { - ItemStack stack = ((ItemEntity)entity).getItem(); - Item item = stack.getItem(); - if (item.hasCustomEntity(stack)) { - Entity newEntity = item.createEntity(world, entity, stack); - if (newEntity != null) { - entity.discard(); - var executor = LogicalSidedProvider.WORKQUEUE.get(world.isClientSide ? EnvType.CLIENT : EnvType.SERVER); - executor.tell(new TickTask(0, () -> world.addFreshEntity(newEntity))); - return false; - } - } - } - return true; - }); - RegistryEntryRemovedCallback.event(BuiltInRegistries.ITEM).register((rawId, id, item) -> { - if (item instanceof BlockItemExtensions blockItem) { - blockItem.removeFromBlockToItemMap(Item.BY_BLOCK, item); - } - }); - } - /** * @return -1 to cancel, MIN_VALUE to follow vanilla logic, any other number to modify granted exp */ - public static int onGrindstoneChange(@NotNull ItemStack top, @NotNull ItemStack bottom, Container outputSlot, int xp) { - GrindstoneEvents.OnplaceItem e = new GrindstoneEvents.OnplaceItem(top, bottom, xp); + public static int onGrindstoneChange(ItemStack top, ItemStack bottom, Container outputSlot, int xp) { + GrindstoneEvent.OnPlaceItem e = new GrindstoneEvent.OnPlaceItem(top, bottom, xp); + e.sendEvent(); if (e.isCanceled()) { outputSlot.setItem(0, ItemStack.EMPTY); return -1; } - if (e.getOutput().isEmpty()) return Integer.MIN_VALUE; + if (e.getOutput().isEmpty()) + return Integer.MIN_VALUE; outputSlot.setItem(0, e.getOutput()); return e.getXp(); } + + public static boolean onGrindstoneTake(Container inputSlots, ContainerLevelAccess access, Function xpFunction) { + access.execute((l, p) -> { + int xp = xpFunction.apply(l); + GrindstoneEvent.OnTakeItem e = new GrindstoneEvent.OnTakeItem(inputSlots.getItem(0), inputSlots.getItem(1), xp); + e.sendEvent(); + if (e.isCanceled()) { + return; + } + if (l instanceof ServerLevel) { + ExperienceOrb.award((ServerLevel) l, Vec3.atCenterOf(p), e.getXp()); + } + l.levelEvent(LevelEvent.SOUND_GRINDSTONE_USED, p, 0); + inputSlots.setItem(0, e.getNewTopItem()); + inputSlots.setItem(1, e.getNewBottomItem()); + inputSlots.setChanged(); + }); + return true; + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PotionHelper.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PotionHelper.java deleted file mode 100644 index f2672ac6b..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/PotionHelper.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import java.util.Iterator; - -import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; -import io.github.fabricators_of_create.porting_lib.mixin.accessors.common.accessor.LivingEntityAccessor; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; - -public class PotionHelper { - /*** - * Removes all potion effects that have curativeItem as a curative item for its effect - * @param curativeItem The itemstack we are using to cure potion effects - */ - public static boolean curePotionEffects(LivingEntity livingEntity, ItemStack curativeItem) { - if (livingEntity.level().isClientSide) - return false; - boolean ret = false; - Iterator itr = livingEntity.getActiveEffects().iterator(); - while (itr.hasNext()) { - MobEffectInstance effect = itr.next(); - if (effect.isCurativeItem(curativeItem) && !new MobEffectEvent.Remove(livingEntity, effect).post()) { - ((LivingEntityAccessor)livingEntity).port_lib$onEffectRemoved(effect); - itr.remove(); - ret = true; - livingEntity.effectsDirty = true; - } - } - return ret; - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleFlowableFluid.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleFlowableFluid.java deleted file mode 100644 index 2c2b7fcb1..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleFlowableFluid.java +++ /dev/null @@ -1,200 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import java.util.function.Supplier; - -import javax.annotation.Nullable; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LiquidBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.material.FlowingFluid; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; - -/** - * Use {@link io.github.fabricators_of_create.porting_lib.fluids.BaseFlowingFluid} in the fluid module instead. - */ -@Deprecated(forRemoval = true) -public abstract class SimpleFlowableFluid extends FlowingFluid { - private final Supplier flowing; - private final Supplier still; - @Nullable - private final Supplier bucket; - @Nullable - private final Supplier block; - private final int flowSpeed; - private final int levelDecreasePerBlock; - private final float blastResistance; - private final int tickRate; - - protected SimpleFlowableFluid(Properties properties) { - this.flowing = properties.flowing; - this.still = properties.still; - this.bucket = properties.bucket; - this.block = properties.block; - this.flowSpeed = properties.flowSpeed; - this.levelDecreasePerBlock = properties.levelDecreasePerBlock; - this.blastResistance = properties.blastResistance; - this.tickRate = properties.tickRate; - } - - @Override - public Fluid getFlowing() { - return flowing.get(); - } - - @Override - public Fluid getSource() { - return still.get(); - } - - @Override - protected boolean canConvertToSource(Level level) { - return false; - } - - @Override - protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state) { - BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; - Block.dropResources(state, world, pos, blockEntity); - } - - @Override - protected int getSlopeFindDistance(LevelReader world) { - return flowSpeed; - } - - @Override - protected int getDropOff(LevelReader worldIn) { - return levelDecreasePerBlock; - } - - @Override - public Item getBucket() { - return bucket != null ? bucket.get() : Items.AIR; - } - - @Override - protected boolean canBeReplacedWith(FluidState state, BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) { - return direction == Direction.DOWN && !isSame(fluid); - } - - @Override - public int getTickDelay(LevelReader world) { - return tickRate; - } - - @Override - protected float getExplosionResistance() { - return blastResistance; - } - - @Override - protected BlockState createLegacyBlock(FluidState state) { - if (block != null) { - return block.get().defaultBlockState().setValue(LiquidBlock.LEVEL, getLegacyLevel(state)); - } - return Blocks.AIR.defaultBlockState(); - } - - @Override - public boolean isSame(Fluid fluid) { - return fluid == still.get() || fluid == flowing.get(); - } - - public static class Flowing extends SimpleFlowableFluid { - public Flowing(Properties properties) { - super(properties); - registerDefaultState(getStateDefinition().any().setValue(LEVEL, 7)); - } - - @Override - protected void createFluidStateDefinition(StateDefinition.Builder builder) { - super.createFluidStateDefinition(builder); - builder.add(LEVEL); - } - - @Override - public int getAmount(FluidState state) { - return state.getValue(LEVEL); - } - - @Override - public boolean isSource(FluidState state) { - return false; - } - } - - public static class Still extends SimpleFlowableFluid { - public Still(Properties properties) { - super(properties); - } - - @Override - public int getAmount(FluidState state) { - return 8; - } - - @Override - public boolean isSource(FluidState state) { - return true; - } - } - - public static class Properties { - private Supplier still; - private Supplier flowing; - private Supplier bucket; - private Supplier block; - private int flowSpeed = 4; - private int levelDecreasePerBlock = 1; - private float blastResistance = 1; - private int tickRate = 5; - - public Properties(Supplier still, Supplier flowing) { - this.still = still; - this.flowing = flowing; - } - - public Properties bucket(Supplier bucket) { - this.bucket = bucket; - return this; - } - - public Properties block(Supplier block) { - this.block = block; - return this; - } - - public Properties flowSpeed(int flowSpeed) { - this.flowSpeed = flowSpeed; - return this; - } - - public Properties levelDecreasePerBlock(int levelDecreasePerBlock) { - this.levelDecreasePerBlock = levelDecreasePerBlock; - return this; - } - - public Properties blastResistance(float blastResistance) { - this.blastResistance = blastResistance; - return this; - } - - public Properties tickRate(int tickRate) { - this.tickRate = tickRate; - return this; - } - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/TierSortingRegistry.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/TierSortingRegistry.java deleted file mode 100644 index 024618ade..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/TierSortingRegistry.java +++ /dev/null @@ -1,354 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util; - -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import io.github.fabricators_of_create.porting_lib.core.PortingLib; - -import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.graph.ElementOrder; -import com.google.common.graph.GraphBuilder; -import com.google.common.graph.MutableGraph; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import it.unimi.dsi.fastutil.booleans.BooleanConsumer; -import net.fabricmc.api.EnvType; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; -import net.fabricmc.fabric.api.resource.ResourceManagerHelper; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.ServerGamePacketListenerImpl; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.tags.BlockTags; -import net.minecraft.tags.TagKey; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.world.item.DiggerItem; -import net.minecraft.world.item.Tier; -import net.minecraft.world.item.Tiers; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class TierSortingRegistry { - private static final Logger LOGGER = LogManager.getLogger(); - private static final ResourceLocation ITEM_TIER_ORDERING_JSON = new ResourceLocation("port_lib", "item_tier_ordering.json"); - private static final BiMap tiers = HashBiMap.create(); - private static final Multimap edges = HashMultimap.create(); - private static final Multimap vanillaEdges = HashMultimap.create(); - private static final List sortedTiers = new ArrayList<>(); - private static final List sortedTiersUnmodifiable = Collections.unmodifiableList(sortedTiers); - private static final ResourceLocation CHANNEL_NAME = new ResourceLocation("port_lib:tier_sorting"); - private static final String PROTOCOL_VERSION = "1.0"; - - private static boolean hasCustomTiers = false; - - static { - var wood = new ResourceLocation("wood"); - var stone = new ResourceLocation("stone"); - var iron = new ResourceLocation("iron"); - var diamond = new ResourceLocation("diamond"); - var netherite = new ResourceLocation("netherite"); - var gold = new ResourceLocation("gold"); - processTier(Tiers.WOOD, wood, List.of(), List.of()); - processTier(Tiers.GOLD, gold, List.of(wood), List.of(stone)); - processTier(Tiers.STONE, stone, List.of(wood), List.of(iron)); - processTier(Tiers.IRON, iron, List.of(stone), List.of(diamond)); - processTier(Tiers.DIAMOND, diamond, List.of(iron), List.of(netherite)); - processTier(Tiers.NETHERITE, netherite, List.of(diamond), List.of()); - vanillaEdges.putAll(edges); - } - - /** - * Registers a tier into the tier sorting registry. - * - * @param tier The tier to register - * @param name The name to use internally for dependency resolution - * @param after List of tiers to place this tier after (the tiers in the list will be considered lesser tiers) - * @param before List of tiers to place this tier before (the tiers in the list will be considered better tiers) - */ - public static synchronized Tier registerTier(Tier tier, ResourceLocation name, List after, List before) { - if (tiers.containsKey(name)) - throw new IllegalStateException("Duplicate tier name " + name); - - processTier(tier, name, after, before); - - hasCustomTiers = true; - return tier; - } - - /** - * Returns the list of tiers in the order defined by the dependencies. - * This list will remain valid - * - * @return An unmodifiable list of tiers ordered lesser to greater - */ - public static List getSortedTiers() { - return sortedTiersUnmodifiable; - } - - /** - * Returns the tier associated with a name, if registered into the sorting system. - * - * @param name The name to look up - * @return The tier, or null if not registered - */ - @Nullable - public static Tier byName(ResourceLocation name) { - return tiers.get(name); - } - - /** - * Returns the name associated with a tier, if the tier is registered into the sorting system. - * - * @param tier The tier to look up - * @return The name for the tier, or null if not registered - */ - @Nullable - public static ResourceLocation getName(Tier tier) { - return tiers.inverse().get(tier); - } - - /** - * Queries if a tier should be evaluated using the sorting system, by calling isCorrectTierForDrops - * - * @param tier The tier to query - * @return True if isCorrectTierForDrops should be called for the tier - */ - public static boolean isTierSorted(Tier tier) { - return getName(tier) != null; - } - - /** - * Queries if a tier is high enough to be able to get drops for the given blockstate. - * - * @param tier The tier to look up - * @param state The state to test against - * @return True if the tier is good enough - */ - public static boolean isCorrectTierForDrops(Tier tier, BlockState state) { - if (!isTierSorted(tier)) - return isCorrectTierVanilla(tier, state); - - for (int x = sortedTiers.indexOf(tier) + 1; x < sortedTiers.size(); x++) { - TagKey tag = TagUtil.getTagFromTier(sortedTiers.get(x)); - if (tag != null && state.is(tag)) - return false; - } - return true; - } - - /** - * Helper to query all tiers that are lower than the given tier - * - * @param tier The tier - * @return All the lower tiers - */ - public static List getTiersLowerThan(Tier tier) { - if (!isTierSorted(tier)) return List.of(); - return sortedTiers.stream().takeWhile(t -> t != tier).toList(); - } - - /** - * Fallback for when a tier isn't in the registry - */ - private static boolean isCorrectTierVanilla(Tier tier, BlockState state) { - return tier.getLevel() >= MiningLevelManager.getRequiredMiningLevel(state); - } - - private static void processTier(Tier tier, ResourceLocation name, List afters, List befores) { - tiers.put(name, tier); - for (Object after : afters) { - ResourceLocation other = getTierName(after); - edges.put(other, name); - } - for (Object before : befores) { - ResourceLocation other = getTierName(before); - edges.put(name, other); - } - } - - private static ResourceLocation getTierName(Object entry) { - if (entry instanceof String s) - return new ResourceLocation(s); - if (entry instanceof ResourceLocation rl) - return rl; - if (entry instanceof Tier t) - return Objects.requireNonNull(getName(t), "Can't have sorting dependencies for tiers not registered in the TierSortingRegistry"); - throw new IllegalStateException("Invalid object type passed into the tier dependencies " + entry.getClass()); - } - - static boolean allowVanilla() { - return !hasCustomTiers; - } - - /*package private (not for us >:))*/ - public static void init() { - ServerPlayConnectionEvents.JOIN.register(TierSortingRegistry::playerLoggedIn); - ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(getReloadListener()); - if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) ClientEvents.init(); - } - - /*package private*/ - static IdentifiableResourceReloadListener getReloadListener() { - return new IdentifiableSimplePreparableReloadListener(PortingLib.id("tier_sorting_registry")) { - final Gson gson = (new GsonBuilder()).create(); - - @Nonnull - @Override - protected JsonObject prepare(@Nonnull ResourceManager resourceManager, ProfilerFiller p) { - Optional res = resourceManager.getResource(ITEM_TIER_ORDERING_JSON); - if (res.isEmpty()) - return new JsonObject(); - - try (Reader reader = res.get().openAsReader()) { - return gson.fromJson(reader, JsonObject.class); - } catch (IOException e) { - LOGGER.error("Could not read Tier sorting file " + ITEM_TIER_ORDERING_JSON, e); - return new JsonObject(); - } - } - - @Override - protected void apply(@Nonnull JsonObject data, @Nonnull ResourceManager resourceManager, ProfilerFiller p) { - try { - if (data.size() > 0) { - JsonArray order = GsonHelper.getAsJsonArray(data, "order"); - List customOrder = new ArrayList<>(); - for (JsonElement entry : order) { - ResourceLocation id = new ResourceLocation(entry.getAsString()); - Tier tier = byName(id); - if (tier == null) throw new IllegalStateException("Tier not found with name " + id); - customOrder.add(tier); - } - - List missingTiers = tiers.values().stream().filter(tier -> !customOrder.contains(tier)).toList(); - if (missingTiers.size() > 0) - throw new IllegalStateException("Tiers missing from the ordered list: " + missingTiers.stream().map(tier -> Objects.toString(TierSortingRegistry.getName(tier))).collect(Collectors.joining(", "))); - - setTierOrder(customOrder); - return; - } - } catch (Exception e) { - LOGGER.error("Error parsing Tier sorting file " + ITEM_TIER_ORDERING_JSON, e); - } - - recalculateItemTiers(); - } - }; - } - - @SuppressWarnings("UnstableApiUsage") - private static void recalculateItemTiers() { - final MutableGraph graph = GraphBuilder.directed().nodeOrder(ElementOrder.insertion()).build(); - - for (Tier tier : tiers.values()) { - graph.addNode(tier); - } - edges.forEach((key, value) -> { - if (tiers.containsKey(key) && tiers.containsKey(value)) - graph.putEdge(tiers.get(key), tiers.get(value)); - }); - List tierList = TopologicalSort.topologicalSort(graph, null); - - setTierOrder(tierList); - } - - private static void setTierOrder(List tierList) { - runInServerThreadIfPossible(hasServer -> { - sortedTiers.clear(); - sortedTiers.addAll(tierList); - if (hasServer) syncToAll(); - }); - } - - private static void runInServerThreadIfPossible(BooleanConsumer runnable) { - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - if (server != null) server.execute(() -> runnable.accept(true)); - else runnable.accept(false); - } - - private static void syncToAll() { - for (ServerPlayer serverPlayer : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers()) { - syncToPlayer(serverPlayer); - } - } - - private static void playerLoggedIn(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server) { - syncToPlayer(handler.getPlayer()); - } - - private static void syncToPlayer(ServerPlayer serverPlayer) { - ServerPlayNetworking.send(serverPlayer, CHANNEL_NAME, new SyncPacket(sortedTiers.stream().map(TierSortingRegistry::getName).toList()).encode()); - } - - private static SyncPacket receive(FriendlyByteBuf buffer) { - int count = buffer.readVarInt(); - List list = new ArrayList<>(); - for (int i = 0; i < count; i++) - list.add(buffer.readResourceLocation()); - return new SyncPacket(list); - } - - private static void handle(SyncPacket packet) { - setTierOrder(packet.tiers.stream().map(TierSortingRegistry::byName).toList()); - } - - private record SyncPacket(List tiers) { - private FriendlyByteBuf encode() { - FriendlyByteBuf buffer = PacketByteBufs.create(); - buffer.writeVarInt(tiers.size()); - for (ResourceLocation loc : tiers) - buffer.writeResourceLocation(loc); - return buffer; - } - } - - private static class ClientEvents { - public static void init() { - ClientPlayConnectionEvents.JOIN.register(ClientEvents::clientLogInToServer); - ClientPlayNetworking.registerGlobalReceiver(CHANNEL_NAME, ((client, handler, buf, responseSender) -> { - SyncPacket packet = receive(buf); - handle(packet); - })); - } - - private static void clientLogInToServer(ClientPacketListener handler, PacketSender sender, Minecraft client) { - if (handler.getConnection() == null || !handler.getConnection().isMemoryConnection()) - recalculateItemTiers(); - } - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ClientHooks.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ClientHooks.java index 71f6a9677..b11208792 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ClientHooks.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ClientHooks.java @@ -1,86 +1,33 @@ package io.github.fabricators_of_create.porting_lib.util.client; -import com.google.common.collect.Maps; - import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Either; -import io.github.fabricators_of_create.porting_lib.gui.GuiHooks; +import io.github.fabricators_of_create.porting_lib.event.client.TextureAtlasStitchedEvent; import io.github.fabricators_of_create.porting_lib.item.ArmorTextureItem; -import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.inventory.tooltip.TooltipComponent; -import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterial; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.ApiStatus; -import javax.annotation.Nullable; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - public class ClientHooks { - public static final Map ARMOR_LOCATION_CACHE = Maps.newHashMap(); - - public static String getArmorTexture(Entity entity, ItemStack armor, String _default, EquipmentSlot slot, String type) { - String result = null; + public static ResourceLocation getArmorTexture(Entity entity, ItemStack armor, ArmorMaterial.Layer layer, boolean innerModel, EquipmentSlot slot) { + ResourceLocation result = null; if (armor.getItem() instanceof ArmorTextureItem armorTextureItem) - result = armorTextureItem.getArmorTexture(armor, entity, slot, type); - return result != null ? result : _default; - } - - /** - * More generic version of the above function, it allows for Items to have more control over what texture they provide. - * - * @param entity Entity wearing the armor - * @param stack ItemStack for the armor - * @param slot Slot ID that the item is in - * @param type Subtype, can be null or "overlay" - * @return ResourceLocation pointing at the armor's texture - */ - public static ResourceLocation getArmorResource(net.minecraft.world.entity.Entity entity, ItemStack stack, EquipmentSlot slot, @Nullable String type) { - ArmorItem item = (ArmorItem)stack.getItem(); - String texture = item.getMaterial().getName(); - String domain = "minecraft"; - int idx = texture.indexOf(':'); - if (idx != -1) { - domain = texture.substring(0, idx); - texture = texture.substring(idx + 1); - } - String s1 = String.format(java.util.Locale.ROOT, "%s:textures/models/armor/%s_layer_%d%s.png", domain, texture, slot == EquipmentSlot.LEGS ? 2 : 1, type == null ? "" : String.format(java.util.Locale.ROOT, "_%s", type)); - - s1 = getArmorTexture(entity, stack, s1, slot, type); - ResourceLocation resourcelocation = ARMOR_LOCATION_CACHE.get(s1); - - if (resourcelocation == null) { - resourcelocation = new ResourceLocation(s1); - ARMOR_LOCATION_CACHE.put(s1, resourcelocation); - } - - return resourcelocation; + result = armorTextureItem.getArmorTexture(armor, entity, slot, layer, innerModel); + return result != null ? result : layer.texture(innerModel); } public static void setPartVisibility(HumanoidModel armorModel, EquipmentSlot slot) { armorModel.setAllVisible(false); - switch(slot) { + switch (slot) { case HEAD: armorModel.head.visible = true; armorModel.hat.visible = true; @@ -101,31 +48,20 @@ public static void setPartVisibility(HumanoidModel armorModel, EquipmentSlot } } - /** - * Moved to gui_utils module - */ - @Deprecated(forRemoval = true) - public static void wrapModTooltips(String modid) { - GuiHooks.wrapModTooltips(modid); - } - - /** - * Moved to gui_utils module - */ - @Deprecated(forRemoval = true) - public static List gatherTooltipComponents(ItemStack stack, List textElements, Optional itemComponent, int mouseX, int screenWidth, int screenHeight, Font font) { - return GuiHooks.gatherTooltipComponents(stack, textElements, itemComponent, mouseX, screenWidth, screenHeight, font); - } - @ApiStatus.Internal public static RenderType RENDER_TYPE = null; /** * Sets the current {@link RenderType} to use for rendering a single block in {@link net.minecraft.client.renderer.block.BlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, int, int)}. * It is very important you set this to null after you have rendered your block(s). + * * @param renderType The render type you want to render the block in. Ex: {@link RenderType#translucent()} */ public static void setRenderType(RenderType renderType) { RENDER_TYPE = renderType; } + + public static void onTextureAtlasStitched(TextureAtlas atlas) { + new TextureAtlasStitchedEvent(atlas).sendEvent(); + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ForgeSlider.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ExtendedSlider.java similarity index 66% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ForgeSlider.java rename to modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ExtendedSlider.java index 2aed1eb69..daaf5113c 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ForgeSlider.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ExtendedSlider.java @@ -1,23 +1,30 @@ package io.github.fabricators_of_create.porting_lib.util.client; +import com.mojang.blaze3d.systems.RenderSystem; + +import java.text.DecimalFormat; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; -import org.lwjgl.glfw.GLFW; -import java.text.DecimalFormat; +import org.lwjgl.glfw.GLFW; /** * Slider widget implementation which allows inputting values in a certain range with optional step size. */ -public class ForgeSlider extends AbstractSliderButton { +public class ExtendedSlider extends AbstractSliderButton { protected Component prefix; protected Component suffix; protected double minValue; protected double maxValue; - /** Allows input of discontinuous values with a certain step */ + /** + * Allows input of discontinuous values with a certain step + */ protected double stepSize; protected boolean drawString; @@ -25,20 +32,20 @@ public class ForgeSlider extends AbstractSliderButton { private final DecimalFormat format; /** - * @param x x position of upper left corner - * @param y y position of upper left corner - * @param width Width of the widget - * @param height Height of the widget - * @param prefix {@link Component} displayed before the value string - * @param suffix {@link Component} displayed after the value string - * @param minValue Minimum (left) value of slider - * @param maxValue Maximum (right) value of slider + * @param x x position of upper left corner + * @param y y position of upper left corner + * @param width Width of the widget + * @param height Height of the widget + * @param prefix {@link Component} displayed before the value string + * @param suffix {@link Component} displayed after the value string + * @param minValue Minimum (left) value of slider + * @param maxValue Maximum (right) value of slider * @param currentValue Starting value when widget is first displayed - * @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0. - * @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive). - * @param drawString Should text be displayed on the widget + * @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0. + * @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive). + * @param drawString Should text be displayed on the widget */ - public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString) { + public ExtendedSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString) { super(x, y, width, height, Component.empty(), 0D); this.prefix = prefix; this.suffix = suffix; @@ -72,7 +79,7 @@ public ForgeSlider(int x, int y, int width, int height, Component prefix, Compon /** * Overload with {@code stepSize} set to 1, useful for sliders with whole number values. */ - public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, boolean drawString) { + public ExtendedSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, boolean drawString) { this(x, y, width, height, prefix, suffix, minValue, maxValue, currentValue, 1D, 0, drawString); } @@ -157,7 +164,7 @@ private void setSliderValue(double value) { * If {@code stepSize} is 0, no snapping occurs. */ private double snapToNearest(double value) { - if(stepSize <= 0D) + if (stepSize <= 0D) return Mth.clamp(value, 0D, 1D); value = Mth.lerp(Mth.clamp(value, 0D, 1D), this.minValue, this.maxValue); @@ -183,5 +190,20 @@ protected void updateMessage() { } @Override - protected void applyValue() {} + protected void applyValue() { + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + Minecraft minecraft = Minecraft.getInstance(); + guiGraphics.setColor(1.0F, 1.0F, 1.0F, this.alpha); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + guiGraphics.blitSprite(this.getSprite(), this.getX(), this.getY(), this.getWidth(), this.getHeight()); + guiGraphics.blitSprite(this.getHandleSprite(), this.getX() + (int) (this.value * (double) (this.width - 8)), this.getY(), 8, this.getHeight()); + guiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F); + int i = this.active ? 16777215 : 10526880; + this.renderScrollingString(guiGraphics, minecraft.font, 2, i | Mth.ceil(this.alpha * 255.0F) << 24); + } } diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScreenUtils.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScreenUtils.java deleted file mode 100644 index 54d1260ed..000000000 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScreenUtils.java +++ /dev/null @@ -1,287 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.util.client; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnull; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexFormat; - -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.network.chat.Style; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; - -import org.joml.Matrix4f; - -public class ScreenUtils { - public static final int DEFAULT_BACKGROUND_COLOR = 0xF0100010; - public static final int DEFAULT_BORDER_COLOR_START = 0x505000FF; - public static final int DEFAULT_BORDER_COLOR_END = (DEFAULT_BORDER_COLOR_START & 0xFEFEFE) >> 1 | DEFAULT_BORDER_COLOR_START & 0xFF000000; - public static void drawGradientRect(Matrix4f matrix, int z, int left, int top, int right, int bottom, int startColor, int endColor) { - float startAlpha = (float)(startColor >> 24 & 255) / 255.0F; - float startRed = (float)(startColor >> 16 & 255) / 255.0F; - float startGreen = (float)(startColor >> 8 & 255) / 255.0F; - float startBlue = (float)(startColor & 255) / 255.0F; - float endAlpha = (float)(endColor >> 24 & 255) / 255.0F; - float endRed = (float)(endColor >> 16 & 255) / 255.0F; - float endGreen = (float)(endColor >> 8 & 255) / 255.0F; - float endBlue = (float)(endColor & 255) / 255.0F; - - RenderSystem.enableDepthTest(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - - Tesselator tessellator = Tesselator.getInstance(); - BufferBuilder buffer = tessellator.getBuilder(); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - buffer.vertex(matrix, right, top, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.vertex(matrix, left, top, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.vertex(matrix, left, bottom, z).color( endRed, endGreen, endBlue, endAlpha).endVertex(); - buffer.vertex(matrix, right, bottom, z).color( endRed, endGreen, endBlue, endAlpha).endVertex(); - tessellator.end(); - - RenderSystem.disableBlend(); - } - - public static void drawHoveringText(PoseStack mStack, List textLines, int mouseX, int mouseY, int screenWidth, int screenHeight, int maxTextWidth, int backgroundColor, int borderColorStart, int borderColorEnd, Font font) { - drawHoveringText(ItemStack.EMPTY, mStack, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, backgroundColor, borderColorStart, borderColorEnd, font); - } - - public static void drawHoveringText(@Nonnull final ItemStack stack, PoseStack mStack, List textLines, int mouseX, int mouseY, int screenWidth, int screenHeight, int maxTextWidth, int backgroundColor, int borderColorStart, int borderColorEnd, Font font) { - if (!textLines.isEmpty()) { - //RenderSystem.disableRescaleNormal(); - RenderSystem.disableDepthTest(); - int tooltipTextWidth = 0; - - for (FormattedText textLine : textLines) - { - int textLineWidth = font.width(textLine); - if (textLineWidth > tooltipTextWidth) - tooltipTextWidth = textLineWidth; - } - - boolean needsWrap = false; - - int titleLinesCount = 1; - int tooltipX = mouseX + 12; - if (tooltipX + tooltipTextWidth + 4 > screenWidth) - { - tooltipX = mouseX - 16 - tooltipTextWidth; - if (tooltipX < 4) // if the tooltip doesn't fit on the screen - { - if (mouseX > screenWidth / 2) - tooltipTextWidth = mouseX - 12 - 8; - else - tooltipTextWidth = screenWidth - 16 - mouseX; - needsWrap = true; - } - } - - if (maxTextWidth > 0 && tooltipTextWidth > maxTextWidth) - { - tooltipTextWidth = maxTextWidth; - needsWrap = true; - } - - if (needsWrap) - { - int wrappedTooltipWidth = 0; - List wrappedTextLines = new ArrayList<>(); - for (int i = 0; i < textLines.size(); i++) - { - FormattedText textLine = textLines.get(i); - List wrappedLine = font.getSplitter().splitLines(textLine, tooltipTextWidth, Style.EMPTY); - if (i == 0) - titleLinesCount = wrappedLine.size(); - - for (FormattedText line : wrappedLine) - { - int lineWidth = font.width(line); - if (lineWidth > wrappedTooltipWidth) - wrappedTooltipWidth = lineWidth; - wrappedTextLines.add(line); - } - } - tooltipTextWidth = wrappedTooltipWidth; - textLines = wrappedTextLines; - - if (mouseX > screenWidth / 2) - tooltipX = mouseX - 16 - tooltipTextWidth; - else - tooltipX = mouseX + 12; - } - - int tooltipY = mouseY - 12; - int tooltipHeight = 8; - - if (textLines.size() > 1) - { - tooltipHeight += (textLines.size() - 1) * 10; - if (textLines.size() > titleLinesCount) - tooltipHeight += 2; // gap between title lines and next lines - } - - if (tooltipY < 4) - tooltipY = 4; - else if (tooltipY + tooltipHeight + 4 > screenHeight) - tooltipY = screenHeight - tooltipHeight - 4; - - final int zLevel = 400; - - mStack.pushPose(); - Matrix4f mat = mStack.last().pose(); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - drawGradientRect(mat, zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - drawGradientRect(mat, zLevel, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); - drawGradientRect(mat, zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); - drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd); - - MultiBufferSource.BufferSource renderType = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - mStack.translate(0.0D, 0.0D, zLevel); - - int tooltipTop = tooltipY; - - for (int lineNumber = 0; lineNumber < textLines.size(); ++lineNumber) - { - FormattedText line = textLines.get(lineNumber); - if (line != null) - font.drawInBatch(Language.getInstance().getVisualOrder(line), (float)tooltipX, (float)tooltipY, -1, true, mat, renderType, Font.DisplayMode.NORMAL, 0, 15728880); - - if (lineNumber + 1 == titleLinesCount) - tooltipY += 2; - - tooltipY += 10; - } - - renderType.endBatch(); - mStack.popPose(); - - RenderSystem.enableDepthTest(); - //RenderSystem.enableRescaleNormal(); - } - } - - /** - * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders - * and filler. The provided ResourceLocation object will be bound using - * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). - * - * @param guiGraphics the gui pose stack - * @param res the ResourceLocation object that contains the desired image - * @param x x axis offset - * @param y y axis offset - * @param u bound resource location image x offset - * @param v bound resource location image y offset - * @param width the desired box width - * @param height the desired box height - * @param textureWidth the width of the box texture in the resource location image - * @param textureHeight the height of the box texture in the resource location image - * @param topBorder the size of the box's top border - * @param bottomBorder the size of the box's bottom border - * @param leftBorder the size of the box's left border - * @param rightBorder the size of the box's right border - * @param zLevel the zLevel to draw at - */ - public static void drawContinuousTexturedBox(GuiGraphics guiGraphics, ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, res); - drawContinuousTexturedBox(guiGraphics, x, y, u, v, width, height, textureWidth, textureHeight, topBorder, bottomBorder, leftBorder, rightBorder, zLevel); - } - - /** - * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders - * and filler. It is assumed that the desired texture ResourceLocation object has been bound using - * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). - * - * @param guiGraphics the gui pose stack - * @param x x axis offset - * @param y y axis offset - * @param u bound resource location image x offset - * @param v bound resource location image y offset - * @param width the desired box width - * @param height the desired box height - * @param textureWidth the width of the box texture in the resource location image - * @param textureHeight the height of the box texture in the resource location image - * @param topBorder the size of the box's top border - * @param bottomBorder the size of the box's bottom border - * @param leftBorder the size of the box's left border - * @param rightBorder the size of the box's right border - * @param zLevel the zLevel to draw at - */ - public static void drawContinuousTexturedBox(GuiGraphics guiGraphics, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - - int fillerWidth = textureWidth - leftBorder - rightBorder; - int fillerHeight = textureHeight - topBorder - bottomBorder; - int canvasWidth = width - leftBorder - rightBorder; - int canvasHeight = height - topBorder - bottomBorder; - int xPasses = canvasWidth / fillerWidth; - int remainderWidth = canvasWidth % fillerWidth; - int yPasses = canvasHeight / fillerHeight; - int remainderHeight = canvasHeight % fillerHeight; - - // Draw Border - // Top Left - drawTexturedModalRect(guiGraphics, x, y, u, v, leftBorder, topBorder, zLevel); - // Top Right - drawTexturedModalRect(guiGraphics, x + leftBorder + canvasWidth, y, u + leftBorder + fillerWidth, v, rightBorder, topBorder, zLevel); - // Bottom Left - drawTexturedModalRect(guiGraphics, x, y + topBorder + canvasHeight, u, v + topBorder + fillerHeight, leftBorder, bottomBorder, zLevel); - // Bottom Right - drawTexturedModalRect(guiGraphics, x + leftBorder + canvasWidth, y + topBorder + canvasHeight, u + leftBorder + fillerWidth, v + topBorder + fillerHeight, rightBorder, bottomBorder, zLevel); - - for (int i = 0; i < xPasses + (remainderWidth > 0 ? 1 : 0); i++) { - // Top Border - drawTexturedModalRect(guiGraphics, x + leftBorder + (i * fillerWidth), y, u + leftBorder, v, (i == xPasses ? remainderWidth : fillerWidth), topBorder, zLevel); - // Bottom Border - drawTexturedModalRect(guiGraphics, x + leftBorder + (i * fillerWidth), y + topBorder + canvasHeight, u + leftBorder, v + topBorder + fillerHeight, (i == xPasses ? remainderWidth : fillerWidth), bottomBorder, zLevel); - - // Throw in some filler for good measure - for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) - drawTexturedModalRect(guiGraphics, x + leftBorder + (i * fillerWidth), y + topBorder + (j * fillerHeight), u + leftBorder, v + topBorder, (i == xPasses ? remainderWidth : fillerWidth), (j == yPasses ? remainderHeight : fillerHeight), zLevel); - } - - // Side Borders - for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) { - // Left Border - drawTexturedModalRect(guiGraphics, x, y + topBorder + (j * fillerHeight), u, v + topBorder, leftBorder, (j == yPasses ? remainderHeight : fillerHeight), zLevel); - // Right Border - drawTexturedModalRect(guiGraphics, x + leftBorder + canvasWidth, y + topBorder + (j * fillerHeight), u + leftBorder + fillerWidth, v + topBorder, rightBorder, (j == yPasses ? remainderHeight : fillerHeight), zLevel); - } - } - - public static void drawTexturedModalRect(GuiGraphics guiGraphics, int x, int y, int u, int v, int width, int height, float zLevel) { - final float uScale = 1f / 0x100; - final float vScale = 1f / 0x100; - - Tesselator tessellator = Tesselator.getInstance(); - BufferBuilder wr = tessellator.getBuilder(); - wr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - Matrix4f matrix = guiGraphics.pose().last().pose(); - wr.vertex(matrix, x , y + height, zLevel).uv( u * uScale, ((v + height) * vScale)).endVertex(); - wr.vertex(matrix, x + width, y + height, zLevel).uv((u + width) * uScale, ((v + height) * vScale)).endVertex(); - wr.vertex(matrix, x + width, y , zLevel).uv((u + width) * uScale, ( v * vScale)).endVertex(); - wr.vertex(matrix, x , y , zLevel).uv( u * uScale, ( v * vScale)).endVertex(); - tessellator.end(); - } -} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScrollPanel.java b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScrollPanel.java index 450e9c14b..f9354a072 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScrollPanel.java +++ b/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/util/client/ScrollPanel.java @@ -1,25 +1,22 @@ package io.github.fabricators_of_create.porting_lib.util.client; -import java.util.Collections; -import java.util.List; - +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; - +import java.util.Collections; +import java.util.List; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.GameRenderer; -import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; -import net.minecraft.client.gui.components.events.GuiEventListener; - /** * Abstract scroll panel class. */ @@ -38,18 +35,16 @@ public abstract class ScrollPanel extends AbstractContainerEventHandler implemen private final int barWidth; private final int barLeft; - private final int bgColorFrom; - private final int bgColorTo; private final int barBgColor; private final int barColor; private final int barBorderColor; /** * @param client the minecraft instance this ScrollPanel should use - * @param width the width + * @param width the width * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) + * @param top the offset from the top (y coord) + * @param left the offset from the left (x coord) */ public ScrollPanel(Minecraft client, int width, int height, int top, int left) { this(client, width, height, top, left, 4); @@ -57,10 +52,10 @@ public ScrollPanel(Minecraft client, int width, int height, int top, int left) { /** * @param client the minecraft instance this ScrollPanel should use - * @param width the width + * @param width the width * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) + * @param top the offset from the top (y coord) + * @param left the offset from the left (x coord) * @param border the size of the border */ public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border) { @@ -68,65 +63,37 @@ public ScrollPanel(Minecraft client, int width, int height, int top, int left, i } /** - * @param client the minecraft instance this ScrollPanel should use - * @param width the width - * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) - * @param border the size of the border - * @param barWidth the width of the scroll bar - */ - public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth) { - this(client, width, height, top, left, border, barWidth, 0xC0101010, 0xD0101010); - } - - /** - * @param client the minecraft instance this ScrollPanel should use - * @param width the width - * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) - * @param border the size of the border - * @param barWidth the width of the scroll bar - * @param bgColor the color for the background - */ - public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth, int bgColor) - { - this(client, width, height, top, left, border, barWidth, bgColor, bgColor); - } - - /** - * @param client the minecraft instance this ScrollPanel should use - * @param width the width - * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) - * @param border the size of the border - * @param barWidth the width of the scroll bar + * @param client the minecraft instance this ScrollPanel should use + * @param width the width + * @param height the height + * @param top the offset from the top (y coord) + * @param left the offset from the left (x coord) + * @param border the size of the border + * @param barWidth the width of the scroll bar * @param bgColorFrom the start color for the background gradient - * @param bgColorTo the end color for the background gradient + * @param bgColorTo the end color for the background gradient */ - public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth, int bgColorFrom, int bgColorTo) { - this(client, width, height, top, left, border, barWidth, bgColorFrom, bgColorTo, 0xFF000000, 0xFF808080, 0xFFC0C0C0); + public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth) { + this(client, width, height, top, left, border, barWidth, 0xFF000000, 0xFF808080, 0xFFC0C0C0); } /** * Base constructor * - * @param client the minecraft instance this ScrollPanel should use - * @param width the width - * @param height the height - * @param top the offset from the top (y coord) - * @param left the offset from the left (x coord) - * @param border the size of the border - * @param barWidth the width of the scroll bar - * @param bgColorFrom the start color for the background gradient - * @param bgColorTo the end color for the background gradient - * @param barBgColor the color for the scroll bar background - * @param barColor the color for the scroll bar handle + * @param client the minecraft instance this ScrollPanel should use + * @param width the width + * @param height the height + * @param top the offset from the top (y coord) + * @param left the offset from the left (x coord) + * @param border the size of the border + * @param barWidth the width of the scroll bar + * @param bgColorFrom the start color for the background gradient + * @param bgColorTo the end color for the background gradient + * @param barBgColor the color for the scroll bar background + * @param barColor the color for the scroll bar handle * @param barBorderColor the border color for the scroll bar handle */ - public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth, int bgColorFrom, int bgColorTo, int barBgColor, int barColor, int barBorderColor) { + public ScrollPanel(Minecraft client, int width, int height, int top, int left, int border, int barWidth, int barBgColor, int barColor, int barBorderColor) { this.client = client; this.width = width; this.height = height; @@ -137,8 +104,6 @@ public ScrollPanel(Minecraft client, int width, int height, int top, int left, i this.barLeft = this.left + this.width - barWidth; this.border = border; this.barWidth = barWidth; - this.bgColorFrom = bgColorFrom; - this.bgColorTo = bgColorTo; this.barBgColor = barBgColor; this.barColor = barColor; this.barBorderColor = barBorderColor; @@ -149,22 +114,8 @@ public ScrollPanel(Minecraft client, int width, int height, int top, int left, i /** * Draws the background of the scroll panel. This runs AFTER Scissors are enabled. */ - protected void drawBackground(GuiGraphics matrix, Tesselator tess, float partialTick) { - BufferBuilder worldr = tess.getBuilder(); - - if (this.client.level != null) { - this.drawGradientRect(matrix, this.left, this.top, this.right, this.bottom, bgColorFrom, bgColorTo); - } else {// Draw dark dirt background - RenderSystem.setShader(GameRenderer::getPositionTexColorShader); - RenderSystem.setShaderTexture(0, Screen.BACKGROUND_LOCATION); - final float texScale = 32.0F; - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); - worldr.vertex(this.left, this.bottom, 0.0D).uv(this.left / texScale, (this.bottom + (int)this.scrollDistance) / texScale).color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.right, this.bottom, 0.0D).uv(this.right / texScale, (this.bottom + (int)this.scrollDistance) / texScale).color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.right, this.top, 0.0D).uv(this.right / texScale, (this.top + (int)this.scrollDistance) / texScale).color(0x20, 0x20, 0x20, 0xFF).endVertex(); - worldr.vertex(this.left, this.top, 0.0D).uv(this.left / texScale, (this.top + (int)this.scrollDistance) / texScale).color(0x20, 0x20, 0x20, 0xFF).endVertex(); - tess.end(); - } + protected void drawBackground(GuiGraphics guiGraphics, Tesselator tess, float partialTick) { + Screen.renderMenuBackgroundTexture(guiGraphics, Screen.MENU_BACKGROUND, this.left, this.top, 0f, 0f, this.width, this.height); } /** @@ -173,10 +124,11 @@ protected void drawBackground(GuiGraphics matrix, Tesselator tess, float partial */ protected abstract void drawPanel(GuiGraphics guiGraphics, int entryRight, int relativeY, Tesselator tess, int mouseX, int mouseY); - protected boolean clickPanel(double mouseX, double mouseY, int button) { return false; } + protected boolean clickPanel(double mouseX, double mouseY, int button) { + return false; + } - private int getMaxScroll() - { + private int getMaxScroll() { return this.getContentHeight() - (this.height - this.border); } @@ -197,9 +149,9 @@ private void applyScrollLimits() { } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double scroll, double d) { - if (scroll != 0) { - this.scrollDistance += -scroll * getScrollAmount(); + public boolean mouseScrolled(double p_94686_, double p_94687_, double p_94688_, double p_294830_) { + if (p_294830_ != 0) { + this.scrollDistance += (float) (-p_294830_ * getScrollAmount()); applyScrollLimits(); return true; } @@ -212,8 +164,8 @@ protected int getScrollAmount() { @Override public boolean isMouseOver(double mouseX, double mouseY) { - return mouseX >= this.left && mouseX <= this.left + this.width && - mouseY >= this.top && mouseY <= this.bottom; + return mouseX >= this.left && mouseX < this.right && + mouseY >= this.top && mouseY < this.bottom; } @Override @@ -221,13 +173,13 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { if (super.mouseClicked(mouseX, mouseY, button)) return true; - this.scrolling = button == 0 && mouseX >= barLeft && mouseX < barLeft + barWidth; + this.scrolling = button == 0 && mouseX >= barLeft && mouseX < right && mouseY >= top && mouseY < bottom; if (this.scrolling) { return true; } - int mouseListY = ((int)mouseY) - this.top - this.getContentHeight() + (int)this.scrollDistance - border; - if (mouseX >= left && mouseX <= right && mouseListY < 0) { - return this.clickPanel(mouseX - left, mouseY - this.top + (int)this.scrollDistance - border, button); + int mouseListY = ((int) mouseY) - this.top - this.getContentHeight() + (int) this.scrollDistance - border; + if (mouseX >= left && mouseX < right && mouseListY < 0) { + return this.clickPanel(mouseX - left, mouseY - this.top + (int) this.scrollDistance - border, button); } return false; } @@ -246,8 +198,8 @@ private int getBarHeight() { if (barHeight < 32) barHeight = 32; - if (barHeight > height - border*2) - barHeight = height - border*2; + if (barHeight > height - border * 2) + barHeight = height - border * 2; return barHeight; } @@ -267,15 +219,14 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { Tesselator tess = Tesselator.getInstance(); - BufferBuilder worldr = tess.getBuilder(); double scale = client.getWindow().getGuiScale(); - RenderSystem.enableScissor((int)(left * scale), (int)(client.getWindow().getHeight() - (bottom * scale)), - (int)(width * scale), (int)(height * scale)); + RenderSystem.enableScissor((int) (left * scale), (int) (client.getWindow().getHeight() - (bottom * scale)), + (int) (width * scale), (int) (height * scale)); this.drawBackground(guiGraphics, tess, partialTick); - int baseY = this.top + border - (int)this.scrollDistance; + int baseY = this.top + border - (int) this.scrollDistance; this.drawPanel(guiGraphics, right, baseY, tess, mouseX, mouseY); RenderSystem.disableDepthTest(); @@ -284,47 +235,47 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia if (extraHeight > 0) { int barHeight = getBarHeight(); - int barTop = (int)this.scrollDistance * (height - barHeight) / extraHeight + this.top; + int barTop = (int) this.scrollDistance * (height - barHeight) / extraHeight + this.top; if (barTop < this.top) { barTop = this.top; } int barBgAlpha = this.barBgColor >> 24 & 0xff; - int barBgRed = this.barBgColor >> 16 & 0xff; - int barBgGreen = this.barBgColor >> 8 & 0xff; - int barBgBlue = this.barBgColor & 0xff; + int barBgRed = this.barBgColor >> 16 & 0xff; + int barBgGreen = this.barBgColor >> 8 & 0xff; + int barBgBlue = this.barBgColor & 0xff; RenderSystem.setShader(GameRenderer::getPositionColorShader); - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(barLeft, this.bottom, 0.0D).color(barBgRed, barBgGreen, barBgBlue, barBgAlpha).endVertex(); - worldr.vertex(barLeft + barWidth, this.bottom, 0.0D).color(barBgRed, barBgGreen, barBgBlue, barBgAlpha).endVertex(); - worldr.vertex(barLeft + barWidth, this.top, 0.0D).color(barBgRed, barBgGreen, barBgBlue, barBgAlpha).endVertex(); - worldr.vertex(barLeft, this.top, 0.0D).color(barBgRed, barBgGreen, barBgBlue, barBgAlpha).endVertex(); - tess.end(); + BufferBuilder worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(barLeft, this.bottom, 0.0F).setColor(barBgRed, barBgGreen, barBgBlue, barBgAlpha); + worldr.addVertex(barLeft + barWidth, this.bottom, 0.0F).setColor(barBgRed, barBgGreen, barBgBlue, barBgAlpha); + worldr.addVertex(barLeft + barWidth, this.top, 0.0F).setColor(barBgRed, barBgGreen, barBgBlue, barBgAlpha); + worldr.addVertex(barLeft, this.top, 0.0F).setColor(barBgRed, barBgGreen, barBgBlue, barBgAlpha); + BufferUploader.drawWithShader(worldr.buildOrThrow()); int barAlpha = this.barColor >> 24 & 0xff; - int barRed = this.barColor >> 16 & 0xff; - int barGreen = this.barColor >> 8 & 0xff; - int barBlue = this.barColor & 0xff; + int barRed = this.barColor >> 16 & 0xff; + int barGreen = this.barColor >> 8 & 0xff; + int barBlue = this.barColor & 0xff; - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(barLeft, barTop + barHeight, 0.0D).color(barRed, barGreen, barBlue, barAlpha).endVertex(); - worldr.vertex(barLeft + barWidth, barTop + barHeight, 0.0D).color(barRed, barGreen, barBlue, barAlpha).endVertex(); - worldr.vertex(barLeft + barWidth, barTop, 0.0D).color(barRed, barGreen, barBlue, barAlpha).endVertex(); - worldr.vertex(barLeft, barTop, 0.0D).color(barRed, barGreen, barBlue, barAlpha).endVertex(); - tess.end(); + worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(barLeft, barTop + barHeight, 0.0F).setColor(barRed, barGreen, barBlue, barAlpha); + worldr.addVertex(barLeft + barWidth, barTop + barHeight, 0.0F).setColor(barRed, barGreen, barBlue, barAlpha); + worldr.addVertex(barLeft + barWidth, barTop, 0.0F).setColor(barRed, barGreen, barBlue, barAlpha); + worldr.addVertex(barLeft, barTop, 0.0F).setColor(barRed, barGreen, barBlue, barAlpha); + BufferUploader.drawWithShader(worldr.buildOrThrow()); int barBorderAlpha = this.barBorderColor >> 24 & 0xff; - int barBorderRed = this.barBorderColor >> 16 & 0xff; - int barBorderGreen = this.barBorderColor >> 8 & 0xff; - int barBorderBlue = this.barBorderColor & 0xff; - - worldr.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - worldr.vertex(barLeft, barTop + barHeight - 1, 0.0D).color(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha).endVertex(); - worldr.vertex(barLeft + barWidth - 1, barTop + barHeight - 1, 0.0D).color(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha).endVertex(); - worldr.vertex(barLeft + barWidth - 1, barTop, 0.0D).color(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha).endVertex(); - worldr.vertex(barLeft, barTop, 0.0D).color(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha).endVertex(); - tess.end(); + int barBorderRed = this.barBorderColor >> 16 & 0xff; + int barBorderGreen = this.barBorderColor >> 8 & 0xff; + int barBorderBlue = this.barBorderColor & 0xff; + + worldr = tess.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + worldr.addVertex(barLeft, barTop + barHeight - 1, 0.0F).setColor(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha); + worldr.addVertex(barLeft + barWidth - 1, barTop + barHeight - 1, 0.0F).setColor(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha); + worldr.addVertex(barLeft + barWidth - 1, barTop, 0.0F).setColor(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha); + worldr.addVertex(barLeft, barTop, 0.0F).setColor(barBorderRed, barBorderGreen, barBorderBlue, barBorderAlpha); + BufferUploader.drawWithShader(worldr.buildOrThrow()); } RenderSystem.disableBlend(); @@ -332,7 +283,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia } protected void drawGradientRect(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int color1, int color2) { - ScreenUtils.drawGradientRect(guiGraphics.pose().last().pose(), 0, left, top, right, bottom, color1, color2); + guiGraphics.fillGradient(left, top, right, bottom, color1, color2); } @Override diff --git a/modules/base/src/main/resources/fabric.mod.json b/modules/base/src/main/resources/fabric.mod.json index 0838ac7cb..28c1c0e0a 100644 --- a/modules/base/src/main/resources/fabric.mod.json +++ b/modules/base/src/main/resources/fabric.mod.json @@ -9,7 +9,7 @@ "io.github.fabricators_of_create.porting_lib.PortingLibBase" ], "client": [ - "io.github.fabricators_of_create.porting_lib.PortingLibClient" + "io.github.fabricators_of_create.porting_lib.PortingLibBaseClient" ] }, "custom": { diff --git a/modules/base/src/main/resources/porting_lib_base.accesswidener b/modules/base/src/main/resources/porting_lib_base.accesswidener index eeacb63e8..a0ed5b5f0 100644 --- a/modules/base/src/main/resources/porting_lib_base.accesswidener +++ b/modules/base/src/main/resources/porting_lib_base.accesswidener @@ -14,3 +14,5 @@ transitive-accessible method net/minecraft/commands/synchronization/ArgumentType transitive-accessible field net/minecraft/world/entity/LivingEntity effectsDirty Z accessible field net/minecraft/world/inventory/GrindstoneMenu repairSlots Lnet/minecraft/world/Container; + +accessible field net/minecraft/world/item/SpawnEggItem ENTITY_TYPE_FIELD_CODEC Lcom/mojang/serialization/MapCodec; diff --git a/modules/base/src/main/resources/porting_lib_base.mixins.json b/modules/base/src/main/resources/porting_lib_base.mixins.json index 8829f7435..a70d08851 100644 --- a/modules/base/src/main/resources/porting_lib_base.mixins.json +++ b/modules/base/src/main/resources/porting_lib_base.mixins.json @@ -18,7 +18,6 @@ "common.BlockBehaviour$BlockStateBaseMixin", "common.BlockEntityMixin", "common.BlockGetterMixin", - "common.BlockItemMixin", "common.BlockLightEngineMixin", "common.BlockStateMixin", "common.BoatMixin", @@ -26,10 +25,9 @@ "common.BushBlockMixin", "common.CactusBlockMixin", "common.ChunkMapMixin", - "common.ChunkStatusMixin", "common.ConnectionMixin", + "common.DataFixersMixin", "common.DeadBushBlockMixin", - "common.DiodeBlockMixin", "common.DropExperienceBlockMixin", "common.EnchantmentHelperMixin", "common.EnchantmentMenuMixin", @@ -58,9 +56,7 @@ "common.MainMixin", "common.MapDecorationMixin", "common.MapItemMixin", - "common.MobEffectInstanceMixin", "common.MushroomCowMixin", - "common.SpawnPlacementsMixin", "common.PackRepositoryMixin", "common.PiglinAiMixin", "common.PistonMovingBlockEntityMixin", @@ -80,7 +76,6 @@ "common.SculkSensorBlockMixin", "common.SculkShriekerBlockMixin", "common.SeagrassBlockMixin", - "common.ServerLevelMixin", "common.ServerPacksSourceMixin", "common.ServerPlayerGameModeMixin", "common.ShapedRecipePattern$DataMixin", @@ -88,8 +83,9 @@ "common.ShapelessRecipeMixin", "common.SignalGetterMixin", "common.SnowGolemMixin", + "common.SpawnEggItemMixin", "common.SpawnerBlockMixin", - "common.StartAttackingMixin", + "common.SpawnPlacementsMixin", "common.StemBlockMixin", "common.StructureProcessorMixin", "common.StructureTemplateMixin", @@ -137,6 +133,7 @@ "client.PostChainMixin", "client.RenderTargetMixin", "client.SkullBlockRendererMixin", + "client.TagCollectorMixin", "client.TextureAtlasMixin", "client.frex.EntityBlockRenderContextMixin" ], diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingHandler.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingHandler.java deleted file mode 100644 index 18f4c2694..000000000 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.brewing; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.NonNullList; -import net.minecraft.world.Containers; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -public class BrewingHandler { - public static void doBrew(Level level, BlockPos blockPos, NonNullList inputs, int[] inputIndexes) { - ItemStack itemstack = inputs.get(3); - - BrewingRecipeRegistry.brewPotions(inputs, itemstack, inputIndexes); - if (itemstack.getItem().hasCraftingRemainingItem()) { - ItemStack itemstack1 = itemstack.getItem().getCraftingRemainingItem().getDefaultInstance(); - itemstack.shrink(1); - if (itemstack.isEmpty()) { - itemstack = itemstack1; - } else { - Containers.dropItemStack(level, blockPos.getX(), blockPos.getY(), blockPos.getZ(), itemstack1); - } - } - else itemstack.shrink(1); - - inputs.set(3, itemstack); - level.levelEvent(1035, blockPos, 0); - } -} diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipe.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipe.java index 693521b33..40db89625 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipe.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipe.java @@ -3,12 +3,10 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import javax.annotation.Nonnull; - public class BrewingRecipe implements IBrewingRecipe { - @Nonnull private final Ingredient input; - @Nonnull private final Ingredient ingredient; - @Nonnull private final ItemStack output; + private final Ingredient input; + private final Ingredient ingredient; + private final ItemStack output; public BrewingRecipe(Ingredient input, Ingredient ingredient, ItemStack output) { this.input = input; @@ -17,7 +15,7 @@ public BrewingRecipe(Ingredient input, Ingredient ingredient, ItemStack output) } @Override - public boolean isInput(@Nonnull ItemStack stack) { + public boolean isInput(ItemStack stack) { return this.input.test(stack); } diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipeRegistry.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipeRegistry.java index afa506d91..78256e987 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipeRegistry.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/BrewingRecipeRegistry.java @@ -1,51 +1,22 @@ package io.github.fabricators_of_create.porting_lib.brewing; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.core.NonNullList; - -public class BrewingRecipeRegistry { - - private static List recipes = new ArrayList(); - - static { -// addRecipe(new VanillaBrewingRecipe()); Let vanilla handle vanilla :) - } - - /** - * Adds a recipe to the registry. Due to the nature of the brewing stand - * inputs that stack (a.k.a max stack size > 1) are not allowed. - * - * @param input - * The Ingredient that goes in same slots as the water bottles - * would. - * @param ingredient - * The Ingredient that goes in the same slot as nether wart would. - * @param output - * The ItemStack that will replace the input once the brewing is - * done. - * @return true if the recipe was added. - */ - public static boolean addRecipe(Ingredient input, Ingredient ingredient, ItemStack output) { - return addRecipe(new BrewingRecipe(input, ingredient, output)); - } - - /** - * Adds a recipe to the registry. Due to the nature of the brewing stand - * inputs that stack (a.k.a max stack size > 1) are not allowed. - */ - public static boolean addRecipe(IBrewingRecipe recipe) { - return recipes.add(recipe); - } - +import net.minecraft.world.item.alchemy.PotionBrewing; +import org.jetbrains.annotations.ApiStatus; + +/** + * Starting from 1.20.5 this is used to hold {@link IBrewingRecipe}s inside of {@link PotionBrewing}. + * For queries, use the vanilla {@link PotionBrewing}. + * For registration, use {@link RegisterBrewingRecipesEvent}. + */ +@ApiStatus.Internal +public record BrewingRecipeRegistry(List recipes) { /** * Returns the output ItemStack obtained by brewing the passed input and * ingredient. */ - public static ItemStack getOutput(ItemStack input, ItemStack ingredient) { + public ItemStack getOutput(ItemStack input, ItemStack ingredient) { if (input.isEmpty() || input.getCount() != 1) return ItemStack.EMPTY; if (ingredient.isEmpty()) return ItemStack.EMPTY; @@ -61,45 +32,15 @@ public static ItemStack getOutput(ItemStack input, ItemStack ingredient) { /** * Returns true if the passed input and ingredient have an output */ - public static boolean hasOutput(ItemStack input, ItemStack ingredient) { + public boolean hasOutput(ItemStack input, ItemStack ingredient) { return !getOutput(input, ingredient).isEmpty(); } - /** - * Used by the brewing stand to determine if its contents can be brewed. - * Extra parameters exist to allow modders to create bigger brewing stands - * without much hassle - */ - public static boolean canBrew(NonNullList inputs, ItemStack ingredient, int[] inputIndexes) { - if (ingredient.isEmpty()) return false; - - for (int i : inputIndexes) { - if (hasOutput(inputs.get(i), ingredient)) { - return true; - } - } - - return false; - } - - /** - * Used by the brewing stand to brew its inventory Extra parameters exist to - * allow modders to create bigger brewing stands without much hassle - */ - public static void brewPotions(NonNullList inputs, ItemStack ingredient, int[] inputIndexes) { - for (int i : inputIndexes) { - ItemStack output = getOutput(inputs.get(i), ingredient); - if (!output.isEmpty()) { - inputs.set(i, output); - } - } - } - /** * Returns true if the passed ItemStack is a valid ingredient for any of the * recipes in the registry. */ - public static boolean isValidIngredient(ItemStack stack) { + public boolean isValidIngredient(ItemStack stack) { if (stack.isEmpty()) return false; for (IBrewingRecipe recipe : recipes) { @@ -114,7 +55,7 @@ public static boolean isValidIngredient(ItemStack stack) { * Returns true if the passed ItemStack is a valid input for any of the * recipes in the registry. */ - public static boolean isValidInput(ItemStack stack) { + public boolean isValidInput(ItemStack stack) { for (IBrewingRecipe recipe : recipes) { if (recipe.isInput(stack)) { return true; @@ -122,11 +63,4 @@ public static boolean isValidInput(ItemStack stack) { } return false; } - - /** - * Returns an unmodifiable list containing all the recipes in the registry - */ - public static List getRecipes() { - return Collections.unmodifiableList(recipes); - } } diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/IBrewingRecipe.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/IBrewingRecipe.java index ad6eac7b4..bf2671fbd 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/IBrewingRecipe.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/IBrewingRecipe.java @@ -1,9 +1,14 @@ package io.github.fabricators_of_create.porting_lib.brewing; +import io.github.fabricators_of_create.porting_lib.brewing.ext.PotionBrewingBuilderExt; import net.minecraft.world.item.ItemStack; +/** + * Interface for more flexible brewing recipes. + * + *

Register using {@link RegisterBrewingRecipesEvent} and {@link PotionBrewingBuilderExt#addRecipe(IBrewingRecipe)}. + */ public interface IBrewingRecipe { - /** * Returns true is the passed ItemStack is an input for this recipe. "Input" * being the item that goes in one of the three bottom slots of the brewing diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/RegisterBrewingRecipesEvent.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/RegisterBrewingRecipesEvent.java new file mode 100644 index 000000000..00bd5ee61 --- /dev/null +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/RegisterBrewingRecipesEvent.java @@ -0,0 +1,35 @@ +package io.github.fabricators_of_create.porting_lib.brewing; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.item.alchemy.PotionBrewing; + +import org.jetbrains.annotations.ApiStatus; + +public class RegisterBrewingRecipesEvent extends BaseEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onRegisterBrewingRecipes(event); + }); + + private final PotionBrewing.Builder builder; + + @ApiStatus.Internal + public RegisterBrewingRecipesEvent(PotionBrewing.Builder builder) { + this.builder = builder; + } + + public PotionBrewing.Builder getBuilder() { + return builder; + } + + @Override + public void sendEvent() { + EVENT.invoker().onRegisterBrewingRecipes(this); + } + + public interface Callback { + void onRegisterBrewingRecipes(RegisterBrewingRecipesEvent event); + } +} diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/VanillaBrewingRecipe.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/VanillaBrewingRecipe.java deleted file mode 100644 index 459ccd280..000000000 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/VanillaBrewingRecipe.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.brewing; - -import net.minecraft.world.item.Items; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.alchemy.PotionBrewing; - -/** - * Used in BrewingRecipeRegistry to maintain the vanilla behaviour. - * - * Most of the code was simply adapted from {@link net.minecraft.world.level.block.entity.BrewingStandBlockEntity} - */ -public class VanillaBrewingRecipe implements IBrewingRecipe { - - /** - * Code adapted from TileEntityBrewingStand.isItemValidForSlot(int index, ItemStack stack) - */ - @Override - public boolean isInput(ItemStack stack) { - Item item = stack.getItem(); - return item == Items.POTION || item == Items.SPLASH_POTION || item == Items.LINGERING_POTION || item == Items.GLASS_BOTTLE; - } - - /** - * Code adapted from TileEntityBrewingStand.isItemValidForSlot(int index, ItemStack stack) - */ - @Override - public boolean isIngredient(ItemStack stack) { - return PotionBrewing.isIngredient(stack); - } - - /** - * Code copied from TileEntityBrewingStand.brewPotions() - * It brews the potion by doing the bit-shifting magic and then checking if the new PotionEffect list is different to the old one, - * or if the new potion is a splash potion when the old one wasn't. - */ - @Override - public ItemStack getOutput(ItemStack input, ItemStack ingredient) { - if (!input.isEmpty() && !ingredient.isEmpty() && isIngredient(ingredient)) { - ItemStack result = PotionBrewing.mix(ingredient, input); - if (result != input) { - return result; - } - return ItemStack.EMPTY; - } - - return ItemStack.EMPTY; - } -} diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingBuilderExt.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingBuilderExt.java new file mode 100644 index 000000000..2b342a8a9 --- /dev/null +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingBuilderExt.java @@ -0,0 +1,26 @@ +package io.github.fabricators_of_create.porting_lib.brewing.ext; + +import io.github.fabricators_of_create.porting_lib.brewing.IBrewingRecipe; +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; + +public interface PotionBrewingBuilderExt { + /** + * Adds a new simple brewing recipe. + * + * @param input the ingredient that goes in the same slot as water bottles would + * @param ingredient the ingredient that goes in the same slot as nether wart would + * @param output the item stack that will replace the input once brewing is done + */ + default void addRecipe(Ingredient input, Ingredient ingredient, ItemStack output) { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support addRecipe(Ingredient, Ingredient, ItemStack)"); + } + + /** + * Adds a new brewing recipe with custom logic. + */ + default void addRecipe(IBrewingRecipe recipe) { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support addRecipe(IBrewingRecipe)"); + } +} diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingExt.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingExt.java new file mode 100644 index 000000000..de44c574f --- /dev/null +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingExt.java @@ -0,0 +1,33 @@ +package io.github.fabricators_of_create.porting_lib.brewing.ext; + +import io.github.fabricators_of_create.porting_lib.brewing.BrewingRecipeRegistry; +import io.github.fabricators_of_create.porting_lib.brewing.IBrewingRecipe; +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import net.minecraft.world.item.ItemStack; + +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +public interface PotionBrewingExt { + /** + * Checks if an item stack is a valid input for brewing, + * for use in the lower 3 slots where water bottles would normally go. + */ + default boolean isInput(ItemStack stack) { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support isInput(ItemStack)"); + } + + /** + * Retrieves recipes that use the more general interface. + * This does NOT include the container and potion mixes. + */ + default List getRecipes() { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support getRecipes()"); + } + + @ApiStatus.Internal + default void setBrewingRegistry(BrewingRecipeRegistry registry) { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support setBrewingRegistry(BrewingRecipeRegistry)"); + } +} diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandBlockEntityMixin.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandBlockEntityMixin.java index 99532b778..4758364ff 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandBlockEntityMixin.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandBlockEntityMixin.java @@ -1,6 +1,5 @@ package io.github.fabricators_of_create.porting_lib.brewing.mixin; -import io.github.fabricators_of_create.porting_lib.brewing.BrewingHandler; import io.github.fabricators_of_create.porting_lib.brewing.BrewingRecipeRegistry; import net.minecraft.core.BlockPos; @@ -20,42 +19,42 @@ @Mixin(BrewingStandBlockEntity.class) public abstract class BrewingStandBlockEntityMixin { - @Shadow - @Final - private static int[] SLOTS_FOR_SIDES; - - @Shadow - public abstract ItemStack getItem(int i); - - @Inject(method = "isBrewable", at = @At("HEAD"), cancellable = true) - private static void port_lib$customBrew(NonNullList inputs, CallbackInfoReturnable cir) { - ItemStack itemStack = inputs.get(3); - if (!itemStack.isEmpty()) { - // Leave vanilla brewing recipes alone so we don't fuck with other mods - boolean canBrew = BrewingRecipeRegistry.canBrew(inputs, itemStack, SLOTS_FOR_SIDES); - if (canBrew) - cir.setReturnValue(true); - } - } - - @Inject(method = "doBrew", at = @At("HEAD"), cancellable = true) - private static void port_lib$customBrewLogic(Level level, BlockPos blockPos, NonNullList inputs, CallbackInfo ci) { - // Check if we are doing a modded brew - if (BrewingRecipeRegistry.canBrew(inputs, inputs.get(3), SLOTS_FOR_SIDES)) { - BrewingHandler.doBrew(level, blockPos, inputs, SLOTS_FOR_SIDES); - ci.cancel(); - } - } - - @Inject(method = "canPlaceItem", at = @At("HEAD"), cancellable = true) - public void port_lib$validBrewItem(int i, ItemStack itemStack, CallbackInfoReturnable cir) { - if (i == 3) { - if (BrewingRecipeRegistry.isValidIngredient(itemStack)) - cir.setReturnValue(true); - else if (i != 4) { - if (BrewingRecipeRegistry.isValidInput(itemStack) && this.getItem(i).isEmpty()) - cir.setReturnValue(true); - } - } - } +// @Shadow +// @Final +// private static int[] SLOTS_FOR_SIDES; +// +// @Shadow +// public abstract ItemStack getItem(int i); +// +// @Inject(method = "isBrewable", at = @At("HEAD"), cancellable = true) +// private static void port_lib$customBrew(NonNullList inputs, CallbackInfoReturnable cir) { +// ItemStack itemStack = inputs.get(3); +// if (!itemStack.isEmpty()) { +// // Leave vanilla brewing recipes alone so we don't fuck with other mods +// boolean canBrew = BrewingRecipeRegistry.canBrew(inputs, itemStack, SLOTS_FOR_SIDES); +// if (canBrew) +// cir.setReturnValue(true); +// } +// } +// +// @Inject(method = "doBrew", at = @At("HEAD"), cancellable = true) +// private static void port_lib$customBrewLogic(Level level, BlockPos blockPos, NonNullList inputs, CallbackInfo ci) { +// // Check if we are doing a modded brew +// if (BrewingRecipeRegistry.canBrew(inputs, inputs.get(3), SLOTS_FOR_SIDES)) { +// BrewingHandler.doBrew(level, blockPos, inputs, SLOTS_FOR_SIDES); +// ci.cancel(); +// } +// } +// +// @Inject(method = "canPlaceItem", at = @At("HEAD"), cancellable = true) +// public void port_lib$validBrewItem(int i, ItemStack itemStack, CallbackInfoReturnable cir) { +// if (i == 3) { +// if (BrewingRecipeRegistry.isValidIngredient(itemStack)) +// cir.setReturnValue(true); +// else if (i != 4) { +// if (BrewingRecipeRegistry.isValidInput(itemStack) && this.getItem(i).isEmpty()) +// cir.setReturnValue(true); +// } +// } +// } } diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$IngredientsSlotMixin.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$IngredientsSlotMixin.java index 1cc310819..9fab4160f 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$IngredientsSlotMixin.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$IngredientsSlotMixin.java @@ -11,9 +11,9 @@ @Mixin(targets = "net.minecraft.world.inventory.BrewingStandMenu$IngredientsSlot") public class BrewingStandMenu$IngredientsSlotMixin { - @Inject(method = "mayPlace", at = @At("HEAD"), cancellable = true) - public void port_lib$canPlace(ItemStack itemStack, CallbackInfoReturnable cir) { - if (BrewingRecipeRegistry.isValidIngredient(itemStack)) - cir.setReturnValue(true); - } +// @Inject(method = "mayPlace", at = @At("HEAD"), cancellable = true) +// public void port_lib$canPlace(ItemStack itemStack, CallbackInfoReturnable cir) { +// if (BrewingRecipeRegistry.isValidIngredient(itemStack)) +// cir.setReturnValue(true); +// } } diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$PotionSlotMixin.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$PotionSlotMixin.java index 1e7a3ebd0..e53b5bf91 100644 --- a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$PotionSlotMixin.java +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/BrewingStandMenu$PotionSlotMixin.java @@ -10,9 +10,9 @@ @Mixin(targets = "net.minecraft.world.inventory.BrewingStandMenu$PotionSlot") public class BrewingStandMenu$PotionSlotMixin { - @Inject(method = "mayPlaceItem", at = @At("HEAD"), cancellable = true) - private static void port_lib$isValidInput(ItemStack itemStack, CallbackInfoReturnable cir) { - if (BrewingRecipeRegistry.isValidInput(itemStack)) - cir.setReturnValue(true); - } +// @Inject(method = "mayPlaceItem", at = @At("HEAD"), cancellable = true) +// private static void port_lib$isValidInput(ItemStack itemStack, CallbackInfoReturnable cir) { +// if (BrewingRecipeRegistry.isValidInput(itemStack)) +// cir.setReturnValue(true); +// } } diff --git a/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/PotionBrewingMixin.java b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/PotionBrewingMixin.java new file mode 100644 index 000000000..89005776f --- /dev/null +++ b/modules/brewing/src/main/java/io/github/fabricators_of_create/porting_lib/brewing/mixin/PotionBrewingMixin.java @@ -0,0 +1,107 @@ +package io.github.fabricators_of_create.porting_lib.brewing.mixin; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + +import io.github.fabricators_of_create.porting_lib.brewing.BrewingRecipe; +import io.github.fabricators_of_create.porting_lib.brewing.BrewingRecipeRegistry; +import io.github.fabricators_of_create.porting_lib.brewing.IBrewingRecipe; +import io.github.fabricators_of_create.porting_lib.brewing.RegisterBrewingRecipesEvent; +import io.github.fabricators_of_create.porting_lib.brewing.ext.PotionBrewingBuilderExt; +import io.github.fabricators_of_create.porting_lib.brewing.ext.PotionBrewingExt; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionBrewing; + +import net.minecraft.world.item.crafting.Ingredient; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.ArrayList; +import java.util.List; + +@Mixin(PotionBrewing.class) +public abstract class PotionBrewingMixin implements PotionBrewingExt { + @Shadow + protected abstract boolean isContainer(ItemStack itemStack); + + private BrewingRecipeRegistry porting_lib$registry; + + @Inject(method = "", at = @At("TAIL")) + private void createEmptyRegistry(final CallbackInfo ci) { + this.porting_lib$registry = new BrewingRecipeRegistry(List.of()); // Create an empty builder in case a mod doesn't use the builder + } + + @Override + public boolean isInput(ItemStack stack) { + return this.porting_lib$registry.isValidInput(stack) || isContainer(stack); + } + + @Override + public List getRecipes() { + return porting_lib$registry.recipes(); + } + + @Override + public void setBrewingRegistry(BrewingRecipeRegistry registry) { + this.porting_lib$registry = registry; + } + + @Inject(method = "hasMix", at = @At("HEAD"), cancellable = true) + private void checkMixRegistry(ItemStack container, ItemStack mix, CallbackInfoReturnable cir) { + if (porting_lib$registry.hasOutput(container, mix)) cir.setReturnValue(true); + } + + @Inject(method = "mix", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;getOrDefault(Lnet/minecraft/core/component/DataComponentType;Ljava/lang/Object;)Ljava/lang/Object;" + ), cancellable = true) + private void doMix(ItemStack itemStack, ItemStack itemStack2, CallbackInfoReturnable cir) { + var customMix = porting_lib$registry.getOutput(itemStack2, itemStack); // Parameters are swapped compared to what vanilla passes! + if (!customMix.isEmpty()) cir.setReturnValue(customMix); + } + + @Inject(method = "bootstrap", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/alchemy/PotionBrewing;addVanillaMixes(Lnet/minecraft/world/item/alchemy/PotionBrewing$Builder;)V", + shift = At.Shift.AFTER + ), locals = LocalCapture.CAPTURE_FAILHARD) + private static void fireRegisterEvent(FeatureFlagSet featureFlagSet, CallbackInfoReturnable cir, PotionBrewing.Builder builder) { + new RegisterBrewingRecipesEvent(builder).sendEvent(); + } + + @Inject(method = "isIngredient", at = @At("HEAD"), cancellable = true) + private void checkRegistryForValidIngredient(ItemStack itemStack, CallbackInfoReturnable cir) { + if (this.porting_lib$registry.isValidIngredient(itemStack)) + cir.setReturnValue(true); + } + + @Mixin(value = PotionBrewing.Builder.class, priority = 300) + public static class BuilderMixin implements PotionBrewingBuilderExt { + private final List porting_lib$recipes = new ArrayList<>(); + + @Override + public void addRecipe(Ingredient input, Ingredient ingredient, ItemStack output) { + addRecipe(new BrewingRecipe(input, ingredient, output)); + } + + @Override + public void addRecipe(IBrewingRecipe recipe) { + this.porting_lib$recipes.add(recipe); + } + + @ModifyReturnValue(method = "build", at = @At("RETURN")) + private PotionBrewing addCustomRecipes(PotionBrewing original) { + original.setBrewingRegistry(new BrewingRecipeRegistry(porting_lib$recipes)); + return original; + } + } +} diff --git a/modules/brewing/src/main/resources/fabric.mod.json b/modules/brewing/src/main/resources/fabric.mod.json index 2d23787e3..9892dd625 100644 --- a/modules/brewing/src/main/resources/fabric.mod.json +++ b/modules/brewing/src/main/resources/fabric.mod.json @@ -3,5 +3,11 @@ "id": "porting_lib_brewing", "version": "${version}", "name": "Porting Lib Brewing", - "description": "Small library for adding brewing recipes" + "description": "Small library for adding brewing recipes", + "custom": { + "loom:injected_interfaces": { + "net/minecraft/class_1845": ["io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingExt"], + "net/minecraft/class_1845/class_9665": ["io/github/fabricators_of_create/porting_lib/brewing/ext/PotionBrewingBuilderExt"] + } + } } diff --git a/modules/brewing/src/main/resources/porting_lib_brewing.accesswidener b/modules/brewing/src/main/resources/porting_lib_brewing.accesswidener new file mode 100644 index 000000000..c0f15c58c --- /dev/null +++ b/modules/brewing/src/main/resources/porting_lib_brewing.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named + +transitive-accessible class net/minecraft/world/item/alchemy/PotionBrewing$Mix diff --git a/modules/brewing/src/main/resources/porting_lib_brewing.mixins.json b/modules/brewing/src/main/resources/porting_lib_brewing.mixins.json index ed0c9ef00..fc9627c38 100644 --- a/modules/brewing/src/main/resources/porting_lib_brewing.mixins.json +++ b/modules/brewing/src/main/resources/porting_lib_brewing.mixins.json @@ -11,6 +11,8 @@ "mixins": [ "BrewingStandBlockEntityMixin", "BrewingStandMenu$IngredientsSlotMixin", - "BrewingStandMenu$PotionSlotMixin" + "BrewingStandMenu$PotionSlotMixin", + "PotionBrewingMixin", + "PotionBrewingMixin$BuilderMixin" ] } diff --git a/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/PortingLibChunkManager.java b/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/PortingLibChunkManager.java index 26183231e..9952ff391 100644 --- a/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/PortingLibChunkManager.java +++ b/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/PortingLibChunkManager.java @@ -209,7 +209,7 @@ private static > void reinstatePersistentChunks( public static void writeForgeForcedChunks(CompoundTag nbt, TicketTracker blockForcedChunks, TicketTracker entityForcedChunks) { if (!blockForcedChunks.isEmpty() || !entityForcedChunks.isEmpty()) { Map> forcedEntries = new HashMap<>(); - writeForcedChunkOwners(forcedEntries, blockForcedChunks, "Blocks", Tag.TAG_COMPOUND, (pos, forcedBlocks) -> forcedBlocks.add(NbtUtils.writeBlockPos(pos))); + writeForcedChunkOwners(forcedEntries, blockForcedChunks, "Blocks", Tag.TAG_COMPOUND, (pos, forcedBlocks) -> forcedBlocks.add(writeBlockPos(pos))); writeForcedChunkOwners(forcedEntries, entityForcedChunks, "Entities", Tag.TAG_INT_ARRAY, (uuid, forcedEntities) -> forcedEntities.add(NbtUtils.createUUID(uuid))); ListTag forcedChunks = new ListTag(); for (Map.Entry> entry : forcedEntries.entrySet()) { @@ -282,10 +282,22 @@ public static void readForgeForcedChunks(CompoundTag nbt, TicketTracker, LongSet> blockForcedChunks) { ListTag forcedBlocks = modEntry.getList(key, Tag.TAG_COMPOUND); for (int k = 0; k < forcedBlocks.size(); k++) { - blockForcedChunks.computeIfAbsent(new TicketOwner<>(modId, NbtUtils.readBlockPos(forcedBlocks.getCompound(k))), owner -> new LongOpenHashSet()).add(chunkPos); + blockForcedChunks.computeIfAbsent(new TicketOwner<>(modId, readBlockPos(forcedBlocks.getCompound(k))), owner -> new LongOpenHashSet()).add(chunkPos); } } + private static BlockPos readBlockPos(CompoundTag compoundtag) { + return new BlockPos(compoundtag.getInt("X"), compoundtag.getInt("Y"), compoundtag.getInt("Z")); + } + + public static CompoundTag writeBlockPos(BlockPos blockpos) { + CompoundTag compoundtag = new CompoundTag(); + compoundtag.putInt("X", blockpos.getX()); + compoundtag.putInt("Y", blockpos.getY()); + compoundtag.putInt("Z", blockpos.getZ()); + return compoundtag; + } + /** * Reads the forge entity forced chunks. */ diff --git a/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/mixin/MinecraftServerMixin.java b/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/mixin/MinecraftServerMixin.java index 526e71114..bef954470 100644 --- a/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/mixin/MinecraftServerMixin.java +++ b/modules/chunk_loading/src/main/java/io/github/fabricators_of_create/porting_lib/chunk/loading/mixin/MinecraftServerMixin.java @@ -14,7 +14,7 @@ @Mixin(MinecraftServer.class) public class MinecraftServerMixin { @ModifyExpressionValue(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/longs/LongIterator;hasNext()Z")) - private boolean reinstatePersistentChunks(boolean original, @Local(index = 6) ServerLevel serverLevel2, @Local(index = 7) ForcedChunksSavedData forcedChunksSavedData) { + private boolean reinstatePersistentChunks(boolean original, @Local(index = 8) ServerLevel serverLevel2, @Local(index = 9) ForcedChunksSavedData forcedChunksSavedData) { if (!original) // a bit of a hack honestly but avoids us having to make a custom Injection Point PortingLibChunkManager.reinstatePersistentChunks(serverLevel2, forcedChunksSavedData); return original; diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/PortingLibCommon.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/PortingLibCommon.java new file mode 100644 index 000000000..65a23a824 --- /dev/null +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/PortingLibCommon.java @@ -0,0 +1,11 @@ +package io.github.fabricators_of_create.porting_lib.common; + +import io.github.fabricators_of_create.porting_lib.common.util.TrueCondition; +import net.fabricmc.api.ModInitializer; + +public class PortingLibCommon implements ModInitializer { + @Override + public void onInitialize() { + TrueCondition.init(); + } +} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/ext/LanguageManagerExt.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/ext/LanguageManagerExt.java new file mode 100644 index 000000000..39a907b51 --- /dev/null +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/ext/LanguageManagerExt.java @@ -0,0 +1,14 @@ +package io.github.fabricators_of_create.porting_lib.common.ext; + +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +import java.util.Locale; + +@Environment(EnvType.CLIENT) +public interface LanguageManagerExt { + default Locale getJavaLocale() { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support getJavaLocale()"); + } +} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/extensions/LanguageManagerExtensions.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/extensions/LanguageManagerExtensions.java deleted file mode 100644 index 331c501b5..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/extensions/LanguageManagerExtensions.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.extensions; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; - -import java.util.Locale; - -@Environment(EnvType.CLIENT) -public interface LanguageManagerExtensions { - @Deprecated(forRemoval = true) - default Locale getJavaLocale(String code) { - throw new RuntimeException("this should be overridden via mixin. what?"); - } - - default Locale getSelectedJavaLocale() { - throw new RuntimeException("mixin not implemented"); - } -} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/LanguageManagerMixin.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/LanguageManagerMixin.java index 9606d2d44..e9092d5ce 100644 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/LanguageManagerMixin.java +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/LanguageManagerMixin.java @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; -import io.github.fabricators_of_create.porting_lib.common.extensions.LanguageManagerExtensions; +import io.github.fabricators_of_create.porting_lib.common.ext.LanguageManagerExt; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -19,7 +19,7 @@ @Environment(EnvType.CLIENT) @Mixin(LanguageManager.class) -public abstract class LanguageManagerMixin implements LanguageManagerExtensions { +public abstract class LanguageManagerMixin implements LanguageManagerExt { @Shadow public abstract String getSelected(); @@ -28,17 +28,12 @@ public abstract class LanguageManagerMixin implements LanguageManagerExtensions @Inject(method = { "setSelected", "" }, at = @At("TAIL")) private void updateLocale(CallbackInfo ci) { - String[] split = this.getSelected().split("_", 2); - this.javaLocale = split.length == 1 ? new Locale(split[0]) : new Locale(split[0], split[1]); + String[] langSplit = this.getSelected().split("_", 2); + this.javaLocale = langSplit.length == 1 ? new Locale(langSplit[0]) : new Locale(langSplit[0], langSplit[1]); } @Override - public Locale getJavaLocale(String code) { - return Locale.ROOT; - } - - @Override - public Locale getSelectedJavaLocale() { + public Locale getJavaLocale() { return this.javaLocale; } } diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/accessor/MinecraftAccessor.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/accessor/MinecraftAccessor.java deleted file mode 100644 index a2fefb696..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/mixin/client/accessor/MinecraftAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.mixin.client.accessor; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; - -@Environment(EnvType.CLIENT) -@Mixin(Minecraft.class) -public interface MinecraftAccessor { - @Accessor("pausePartialTick") - float port_lib$pausePartialTick(); -} diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/EnvExecutor.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/EnvExecutor.java similarity index 93% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/EnvExecutor.java rename to modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/EnvExecutor.java index ff90163e5..ddb74c25e 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/EnvExecutor.java +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/EnvExecutor.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.common.util; import java.util.concurrent.Callable; import java.util.function.Supplier; diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/FriendlyByteBufUtil.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/FriendlyByteBufUtil.java new file mode 100644 index 000000000..92f67efdd --- /dev/null +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/FriendlyByteBufUtil.java @@ -0,0 +1,33 @@ +package io.github.fabricators_of_create.porting_lib.common.util; + +import io.netty.buffer.Unpooled; +import java.util.function.Consumer; +import net.minecraft.core.RegistryAccess; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; + +/** + * Utility class for working with {@link FriendlyByteBuf}s. + */ +public class FriendlyByteBufUtil { + private FriendlyByteBufUtil() { + throw new IllegalStateException("Tried to create utility class!"); + } + + /** + * Writes custom data to a {@link RegistryFriendlyByteBuf}, then returns the written data as a byte array. + * + * @param dataWriter The data writer. + * @param registryAccess The registry access used by registry dependent writers on the buffer + * @return The written data. + */ + public static byte[] writeCustomData(Consumer dataWriter, RegistryAccess registryAccess) { + final RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), registryAccess); + try { + dataWriter.accept(buf); + return buf.array(); + } finally { + buf.release(); + } + } +} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MinecraftClientUtil.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MinecraftClientUtil.java deleted file mode 100644 index 88c995fb5..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MinecraftClientUtil.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.util; - -import java.util.Locale; - -import io.github.fabricators_of_create.porting_lib.common.mixin.client.accessor.MinecraftAccessor; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.language.LanguageManager; - -@Environment(EnvType.CLIENT) -public final class MinecraftClientUtil { - public static float getRenderPartialTicksPaused(Minecraft minecraft) { - return get(minecraft).port_lib$pausePartialTick(); - } - - public static Locale getLocale() { - LanguageManager manager = Minecraft.getInstance().getLanguageManager(); - return manager.getJavaLocale(manager.getSelected()); - } - - private static MinecraftAccessor get(Minecraft minecraft) { - return MixinHelper.cast(minecraft); - } - - private MinecraftClientUtil() {} -} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullConsumer.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullConsumer.java deleted file mode 100644 index 2ce3a1ac5..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullConsumer.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.util; - -import java.util.Objects; -import java.util.function.Consumer; - -@FunctionalInterface -public interface NonNullConsumer extends Consumer { - default NonNullConsumer andThen(NonNullConsumer after) { - Objects.requireNonNull(after); - return (T t) -> { accept(t); after.accept(t); }; - } - - static NonNullConsumer noop() { - return t -> {}; - } -} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullFunction.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullFunction.java deleted file mode 100644 index 9b99963d4..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullFunction.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.util; - -import java.util.Objects; -import java.util.function.Function; - -@FunctionalInterface -public interface NonNullFunction extends Function { - default NonNullFunction andThen(NonNullFunction after) { - Objects.requireNonNull(after); - return t -> after.apply(apply(t)); - } -} diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullSupplier.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullSupplier.java deleted file mode 100644 index c74742e8f..000000000 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/NonNullSupplier.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.common.util; - -import java.util.Objects; -import java.util.function.Supplier; - -@FunctionalInterface -public interface NonNullSupplier extends Supplier { - - static NonNullSupplier of(Supplier sup) { - return of(sup, () -> "Unexpected null value from supplier"); - } - - static NonNullSupplier of(Supplier sup, NonNullSupplier errorMsg) { - return () -> { - T res = sup.get(); - Objects.requireNonNull(res, errorMsg); - return res; - }; - } -} diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleRecipeType.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleRecipeType.java similarity index 83% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleRecipeType.java rename to modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleRecipeType.java index edfcd424c..59d306546 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleRecipeType.java +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleRecipeType.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.common.util; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.Recipe; diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleTier.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleTier.java similarity index 96% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleTier.java rename to modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleTier.java index 69e02ac76..30e03db69 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/SimpleTier.java +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/SimpleTier.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.common.util; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Tier; diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/TrueCondition.java b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/TrueCondition.java similarity index 95% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/TrueCondition.java rename to modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/TrueCondition.java index d596cefc3..798653e5f 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/TrueCondition.java +++ b/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/TrueCondition.java @@ -1,5 +1,5 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.common.util; import com.mojang.serialization.Decoder; import com.mojang.serialization.Encoder; diff --git a/modules/common/src/main/resources/fabric.mod.json b/modules/common/src/main/resources/fabric.mod.json index 37db9f242..0d1f5c7d5 100644 --- a/modules/common/src/main/resources/fabric.mod.json +++ b/modules/common/src/main/resources/fabric.mod.json @@ -4,9 +4,14 @@ "version": "${version}", "name": "Porting Lib Common", "description": "Miscellaneous utilities for other Porting Lib modules.", + "entrypoints": { + "main": [ + "io.github.fabricators_of_create.porting_lib.common.PortingLibCommon" + ] + }, "custom": { "loom:injected_interfaces": { - "net/minecraft/class_1076": ["io/github/fabricators_of_create/porting_lib/common/extensions/LanguageManagerExtensions"], + "net/minecraft/class_1076": ["io/github/fabricators_of_create/porting_lib/common/ext/LanguageManagerExt"], "net/minecraft/class_2211": ["io/github/fabricators_of_create/porting_lib/common/util/IPlantable"], "net/minecraft/class_2266": ["io/github/fabricators_of_create/porting_lib/common/util/IPlantable"], "net/minecraft/class_2523": ["io/github/fabricators_of_create/porting_lib/common/util/IPlantable"], diff --git a/modules/utility/src/main/resources/porting_lib_utility.accesswidener b/modules/common/src/main/resources/porting_lib_common.accesswidener similarity index 100% rename from modules/utility/src/main/resources/porting_lib_utility.accesswidener rename to modules/common/src/main/resources/porting_lib_common.accesswidener diff --git a/modules/common/src/main/resources/porting_lib_common.mixins.json b/modules/common/src/main/resources/porting_lib_common.mixins.json index 33024e29c..8daf0ff54 100644 --- a/modules/common/src/main/resources/porting_lib_common.mixins.json +++ b/modules/common/src/main/resources/porting_lib_common.mixins.json @@ -5,8 +5,7 @@ "package": "io.github.fabricators_of_create.porting_lib.common.mixin", "compatibilityLevel": "JAVA_17", "client": [ - "client.LanguageManagerMixin", - "client.accessor.MinecraftAccessor" + "client.LanguageManagerMixin" ], "injectors": { "defaultRequire": 1, diff --git a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/PortingLib.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/PortingLib.java index 4d34efb52..1578215c1 100644 --- a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/PortingLib.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/PortingLib.java @@ -20,4 +20,8 @@ public class PortingLib { public static ResourceLocation id(String path) { return ResourceLocation.fromNamespaceAndPath(ID, path); } + + public static RuntimeException createMixinException(String extension) { + return new UnsupportedOperationException("Implementation does not support extension: " + extension); + } } diff --git a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/client/PortingLibClient.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/client/PortingLibClient.java new file mode 100644 index 000000000..f568140ce --- /dev/null +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/client/PortingLibClient.java @@ -0,0 +1,12 @@ +package io.github.fabricators_of_create.porting_lib.core.client; + +import io.github.fabricators_of_create.porting_lib.core.util.LogicalSidedProvider; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; + +public class PortingLibClient implements ClientModInitializer { + @Override + public void onInitializeClient() { + ClientLifecycleEvents.CLIENT_STARTED.register(client -> LogicalSidedProvider.setClient(() -> client)); + } +} diff --git a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/BaseEvent.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/BaseEvent.java index fe81cbe08..9d42fbbef 100644 --- a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/BaseEvent.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/BaseEvent.java @@ -1,54 +1,20 @@ package io.github.fabricators_of_create.porting_lib.core.event; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; - -import java.util.function.Consumer; - /** - * The base of an event that may be cancelled. + * Base Event class that all other events are derived from. + *
+ * Note on abstract events + *

+ * This is useful for classes that extend {@link BaseEvent} with more data and methods, + * but should never be listened to directly. + *

+ * For example, an event with {@code Pre} and {@code Post} subclasses might want to + * be declared as {@code abstract} to prevent user accidentally listening to both. + *

+ * All the parents of abstract event classes until {@link BaseEvent} must also be abstract. */ public abstract class BaseEvent { - public enum Result { - DENY, - DEFAULT, - ALLOW - } - - private Result result = Result.DEFAULT; - private boolean canceled; - - /** - * Returns the value set as the result of this event - */ - public Result getResult() { - return result; - } - - /** - * Sets the result value for this event, not all events can have a result set, and any attempt to - * set a result for an event that isn't expecting it will result in a IllegalArgumentException. - * - * The functionality of setting the result is defined on a per-event basis. - * - * @param value The new result - */ - public void setResult(Result value) { - result = value; - } - - public void setCanceled(boolean cancelled) { - this.canceled = cancelled; - } - - public boolean isCanceled() { - return canceled; - } + boolean isCanceled; public abstract void sendEvent(); - - public boolean post() { - sendEvent(); - return isCanceled(); - } } diff --git a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/CancellableEvent.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/CancellableEvent.java new file mode 100644 index 000000000..843640e9b --- /dev/null +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/event/CancellableEvent.java @@ -0,0 +1,44 @@ +package io.github.fabricators_of_create.porting_lib.core.event; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.MustBeInvokedByOverriders; + +/** + * Interface for events that can be canceled. + * Listeners registered to the event bus will not receive {@link #isCanceled() canceled} events, + * unless they were registered with {@code receiveCanceled = true}. + */ +public interface CancellableEvent { + /** + * Sets the cancel state of this event. + * + *

This will prevent other listeners from receiving this event unless they were registered with + * {@code receiveCanceled = true}. + * Further effects of setting the cancel state are defined on a per-event basis. + * + *

This method may be overridden to react to cancellation of the event, + * however a super call must always be made as follows: + * {@code ICancellableEvent.super.setCanceled(canceled);} + */ + @MustBeInvokedByOverriders + default void setCanceled(boolean canceled) { + ((BaseEvent) this).isCanceled = canceled; + } + + /** + * {@return the canceled state of this event} + */ + @ApiStatus.NonExtendable + default boolean isCanceled() { + return ((BaseEvent) this).isCanceled; + } + + /** + * Sends the event and returns wether the event was canceled or not. + * @return Returns if the event was canceled. + */ + default boolean post() { + ((BaseEvent) this).sendEvent(); + return isCanceled(); + } +} diff --git a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/INBTSerializable.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/INBTSerializable.java index e1d1bd7ed..fe519f782 100644 --- a/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/INBTSerializable.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/INBTSerializable.java @@ -1,14 +1,17 @@ package io.github.fabricators_of_create.porting_lib.core.util; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.Tag; -// can't inject this because generics +import org.jetbrains.annotations.UnknownNullability; + +/** + * An interface designed to unify various things in the Minecraft + * code base that can be serialized to and from a NBT tag. + */ public interface INBTSerializable { - default T serializeNBT() { - throw new RuntimeException("override serializeNBT!"); - } + @UnknownNullability + T serializeNBT(HolderLookup.Provider provider); - default void deserializeNBT(T nbt) { - throw new RuntimeException("override deserializeNBT!"); - } + void deserializeNBT(HolderLookup.Provider provider, T nbt); } diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/LogicalSidedProvider.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/LogicalSidedProvider.java similarity index 95% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/LogicalSidedProvider.java rename to modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/LogicalSidedProvider.java index 3ef1a443a..0d103b173 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/LogicalSidedProvider.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/LogicalSidedProvider.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.core.util; import java.util.Optional; import java.util.function.Function; diff --git a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MixinHelper.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/MixinHelper.java similarity index 88% rename from modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MixinHelper.java rename to modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/MixinHelper.java index 82f92c9db..b273bc3ff 100644 --- a/modules/common/src/main/java/io/github/fabricators_of_create/porting_lib/common/util/MixinHelper.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/MixinHelper.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.common.util; +package io.github.fabricators_of_create.porting_lib.core.util; import org.jetbrains.annotations.Contract; diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/ServerLifecycleHooks.java b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/ServerLifecycleHooks.java similarity index 87% rename from modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/ServerLifecycleHooks.java rename to modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/ServerLifecycleHooks.java index 3db93f03b..603e98618 100644 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/util/ServerLifecycleHooks.java +++ b/modules/core/src/main/java/io/github/fabricators_of_create/porting_lib/core/util/ServerLifecycleHooks.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.util; +package io.github.fabricators_of_create.porting_lib.core.util; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.server.MinecraftServer; diff --git a/modules/core/src/main/resources/fabric.mod.json b/modules/core/src/main/resources/fabric.mod.json index 3874a195c..32948925b 100644 --- a/modules/core/src/main/resources/fabric.mod.json +++ b/modules/core/src/main/resources/fabric.mod.json @@ -3,5 +3,13 @@ "id": "porting_lib_core", "version": "${version}", "name": "Porting Lib Core", - "description": "Core functionality used across other modules." + "description": "Core functionality used across other modules.", + "entrypoints": { + "main": [ + "io.github.fabricators_of_create.porting_lib.core.util.ServerLifecycleHooks::init" + ], + "client": [ + "io.github.fabricators_of_create.porting_lib.core.client.PortingLibClient" + ] + } } diff --git a/modules/data/build.gradle b/modules/data/build.gradle index 628ada998..5a8dde8cc 100644 --- a/modules/data/build.gradle +++ b/modules/data/build.gradle @@ -1 +1 @@ -portingLib.addModuleDependency("utility") +portingLib.addModuleDependency("common") diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCure.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCure.java new file mode 100644 index 000000000..174c2f9e5 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCure.java @@ -0,0 +1,65 @@ +package io.github.fabricators_of_create.porting_lib.entity; + +import com.mojang.serialization.Codec; + +import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; +import io.netty.buffer.ByteBuf; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.LivingEntity; + +/** + * Defines a cure that is used to remove {@link MobEffect}s from a {@link LivingEntity}. + *

Cures can be added to or removed from your own effects via {@link MobEffect#fillEffectCures(Set, MobEffectInstance)} + * or any effect by modifying the set of cures on the {@link MobEffectInstance} in {@link MobEffectEvent.Added} + */ +public final class EffectCure { + private static final Map CURES = new ConcurrentHashMap<>(); + + public static Codec CODEC = Codec.STRING.xmap(EffectCure::get, EffectCure::name); + public static final StreamCodec STREAM_CODEC = ByteBufCodecs.STRING_UTF8.map(EffectCure::get, EffectCure::name); + + /** + * {@return all registered cures} + * This collection can be kept around, and will update itself in response to changes to the map. + * See {@link ConcurrentHashMap#values()} for details. + */ + public static Collection getAllCures() { + return Collections.unmodifiableCollection(CURES.values()); + } + + /** + * Gets or creates a new EffectCure for the given name. + */ + public static EffectCure get(String name) { + return CURES.computeIfAbsent(name, EffectCure::new); + } + + /** + * {@return the name of this cure} + */ + public String name() { + return name; + } + + @Override + public String toString() { + return "EffectCure[" + name + "]"; + } + + private final String name; + + /** + * Use {@link #get(String)} to get or create an EffectCure + */ + private EffectCure(String name) { + this.name = name; + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCures.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCures.java new file mode 100644 index 000000000..177cd95a0 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EffectCures.java @@ -0,0 +1,20 @@ +package io.github.fabricators_of_create.porting_lib.entity; + +import java.util.Set; + +public class EffectCures { + /** + * Cure used when a milk bucket is consumed. Cures any effect by default. + */ + public static final EffectCure MILK = EffectCure.get("milk"); + /** + * Cure used when a honey bottle is consumed. Only cures poison by default. + */ + public static final EffectCure HONEY = EffectCure.get("honey"); + /** + * Cure used when a totem of undying protects the player from death. Cures any effect by default. + */ + public static final EffectCure PROTECTED_BY_TOTEM = EffectCure.get("protected_by_totem"); + + public static final Set DEFAULT_CURES = Set.of(MILK, PROTECTED_BY_TOTEM); +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EntityHooks.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EntityHooks.java new file mode 100644 index 000000000..ff74f195a --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/EntityHooks.java @@ -0,0 +1,441 @@ +package io.github.fabricators_of_create.porting_lib.entity; + +import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityMountEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityStruckByLightningEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDeathEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingAttackEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDropsEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingEntityUseItemEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingExperienceDropEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingKnockBackEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.ShieldBlockEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.AttackEntityEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.CriticalHitEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerDestroyItemEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerInteractEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingChangeTargetEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDamageEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingFallEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingHurtEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingUseTotemEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.tick.EntityTickEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.tick.PlayerTickEvent; +import io.github.fabricators_of_create.porting_lib.entity.mixin.accessor.PlayerDataStorageAccessor; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.LightningBolt; +import net.minecraft.world.entity.LivingEntity; + +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; + +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.entity.projectile.ThrownEnderpearl; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.PlayerDataStorage; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +import net.minecraft.world.phys.Vec3; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.List; + +public final class EntityHooks { +// public static boolean doPlayerHarvestCheck(Player player, BlockState state, BlockGetter level, BlockPos pos) { +// // Call deprecated hasCorrectToolForDrops overload for a fallback value, in turn the non-deprecated overload calls this method +// boolean vanillaValue = player.hasCorrectToolForDrops(state); +// PlayerEvent.HarvestCheck event = new PlayerEvent.HarvestCheck(player, state, level, pos, vanillaValue); +// event.sendEvent(); +// return event.canHarvest(); +// } + + public static float getBreakSpeed(Player player, BlockState state, float original, BlockPos pos) { + PlayerEvent.BreakSpeed event = new PlayerEvent.BreakSpeed(player, state, original, pos); + event.sendEvent(); + return (event.isCanceled() ? -1 : event.getNewSpeed()); + } + + public static void onPlayerDestroyItem(Player player, ItemStack stack, @Nullable InteractionHand hand) { + new PlayerDestroyItemEvent(player, stack, hand).sendEvent(); + } + + public static int getExperienceDrop(LivingEntity entity, Player attackingPlayer, int originalExperience) { + LivingExperienceDropEvent event = new LivingExperienceDropEvent(entity, attackingPlayer, originalExperience); + event.sendEvent(); + if (event.isCanceled()) { + return 0; + } + return event.getDroppedExperience(); + } + + public static boolean canMountEntity(Entity entityMounting, Entity entityBeingMounted, boolean isMounting) { + EntityMountEvent event = new EntityMountEvent(entityMounting, entityBeingMounted, entityMounting.level(), isMounting); + event.sendEvent(); + + if (event.isCanceled()) { + entityMounting.absMoveTo(entityMounting.getX(), entityMounting.getY(), entityMounting.getZ(), entityMounting.yRotO, entityMounting.xRotO); + return false; + } else + return true; + } + + public static LivingChangeTargetEvent onLivingChangeTarget(LivingEntity entity, LivingEntity originalTarget, LivingChangeTargetEvent.ILivingTargetType targetType) { + LivingChangeTargetEvent event = new LivingChangeTargetEvent(entity, originalTarget, targetType); + event.sendEvent(); + + return event; + } + + public static boolean onLivingAttack(LivingEntity entity, DamageSource src, float amount) { + return entity instanceof Player || !new LivingAttackEvent(entity, src, amount).post(); + } + + public static boolean onPlayerAttack(LivingEntity entity, DamageSource src, float amount) { + return !new LivingAttackEvent(entity, src, amount).post(); + } + + public static LivingKnockBackEvent onLivingKnockBack(LivingEntity target, float strength, double ratioX, double ratioZ) { + LivingKnockBackEvent event = new LivingKnockBackEvent(target, strength, ratioX, ratioZ); + event.sendEvent(); + return event; + } + + public static boolean onLivingUseTotem(LivingEntity entity, DamageSource damageSource, ItemStack totem, InteractionHand hand) { + LivingUseTotemEvent event = new LivingUseTotemEvent(entity, damageSource, totem, hand); + event.sendEvent(); + return !event.isCanceled(); + } + + public static float onLivingHurt(LivingEntity entity, DamageSource src, float amount) { + LivingHurtEvent event = new LivingHurtEvent(entity, src, amount); + event.sendEvent(); + return (event.isCanceled() ? 0 : event.getAmount()); + } + +// public static float onLivingDamage(LivingEntity entity, DamageSource src, float amount) { +// LivingDamageEvent event = new LivingDamageEvent(entity, src, amount); +// event.sendEvent(); +// return (event.isCanceled() ? 0 : event.getAmount()); +// } + + public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { + var event = new LivingDeathEvent(entity, src); + event.sendEvent(); + return event.isCanceled(); + } + + public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, boolean recentlyHit) { + return new LivingDropsEvent(entity, source, drops, recentlyHit).post(); + } + + @Nullable + public static float[] onLivingFall(LivingEntity entity, float distance, float damageMultiplier) { + LivingFallEvent event = new LivingFallEvent(entity, distance, damageMultiplier); + event.sendEvent(); + return event.isCanceled() ? null : new float[] { event.getDistance(), event.getDamageMultiplier() }; + } + + public static double getEntityVisibilityMultiplier(LivingEntity entity, Entity lookingEntity, double originalMultiplier) { + LivingEvent.LivingVisibilityEvent event = new LivingEvent.LivingVisibilityEvent(entity, lookingEntity, originalMultiplier); + event.sendEvent(); + return Math.max(0, event.getVisibilityModifier()); + } + + public static void onLivingJump(LivingEntity entity) { + new LivingEvent.LivingJumpEvent(entity).sendEvent(); + } + + public static boolean onPlayerAttackTarget(Player player, Entity target) { + var event = new AttackEntityEvent(player, target); + event.sendEvent(); + if (event.isCanceled()) + return false; + ItemStack stack = player.getMainHandItem(); + return stack.isEmpty() || !stack.getItem().onLeftClickEntity(stack, player, target); + } + + @Nullable + public static InteractionResult onInteractEntityAt(Player player, Entity entity, HitResult ray, InteractionHand hand) { + Vec3 vec3d = ray.getLocation().subtract(entity.position()); + return onInteractEntityAt(player, entity, vec3d, hand); + } + + @Nullable + public static InteractionResult onInteractEntityAt(Player player, Entity entity, Vec3 vec3d, InteractionHand hand) { + PlayerInteractEvent.EntityInteractSpecific evt = new PlayerInteractEvent.EntityInteractSpecific(player, hand, entity, vec3d); + evt.sendEvent(); + return evt.isCanceled() ? evt.getCancellationResult() : null; + } + + @Nullable + public static InteractionResult onInteractEntity(Player player, Entity entity, InteractionHand hand) { + PlayerInteractEvent.EntityInteract evt = new PlayerInteractEvent.EntityInteract(player, hand, entity); + evt.sendEvent(); + return evt.isCanceled() ? evt.getCancellationResult() : null; + } + + @Nullable + public static InteractionResult onItemRightClick(Player player, InteractionHand hand) { + PlayerInteractEvent.RightClickItem evt = new PlayerInteractEvent.RightClickItem(player, hand); + evt.sendEvent(); + return evt.isCanceled() ? evt.getCancellationResult() : null; + } + + public static PlayerInteractEvent.LeftClickBlock onLeftClickBlock(Player player, BlockPos pos, Direction face, ServerboundPlayerActionPacket.Action action) { + PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.convert(action)); + evt.sendEvent(); + return evt; + } + + public static PlayerInteractEvent.LeftClickBlock onClientMineHold(Player player, BlockPos pos, Direction face) { + PlayerInteractEvent.LeftClickBlock evt = new PlayerInteractEvent.LeftClickBlock(player, pos, face, PlayerInteractEvent.LeftClickBlock.Action.CLIENT_HOLD); + evt.sendEvent(); + return evt; + } + + public static PlayerInteractEvent.RightClickBlock onRightClickBlock(Player player, InteractionHand hand, BlockPos pos, BlockHitResult hitVec) { + PlayerInteractEvent.RightClickBlock evt = new PlayerInteractEvent.RightClickBlock(player, hand, pos, hitVec); + evt.sendEvent(); + return evt; + } + + public static void onEmptyClick(Player player, InteractionHand hand) { + new PlayerInteractEvent.RightClickEmpty(player, hand).sendEvent(); + } + + public static void onEmptyLeftClick(Player player) { + new PlayerInteractEvent.LeftClickEmpty(player).sendEvent(); + } + + public static EntityEvent.Size getEntitySizeForge(Entity entity, Pose pose, EntityDimensions size, float eyeHeight) { + EntityEvent.Size evt = new EntityEvent.Size(entity, pose, size, eyeHeight); + evt.sendEvent(); + return evt; + } + + public static EntityEvent.Size getEntitySizeForge(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float newEyeHeight) { + EntityEvent.Size evt = new EntityEvent.Size(entity, pose, oldSize, newSize, entity.getEyeHeight(), newEyeHeight); + evt.sendEvent(); + return evt; + } + + public static EntityTeleportEvent.TeleportCommand onEntityTeleportCommand(Entity entity, double targetX, double targetY, double targetZ) { + EntityTeleportEvent.TeleportCommand event = new EntityTeleportEvent.TeleportCommand(entity, targetX, targetY, targetZ); + event.sendEvent(); + return event; + } + + public static EntityTeleportEvent.SpreadPlayersCommand onEntityTeleportSpreadPlayersCommand(Entity entity, double targetX, double targetY, double targetZ) { + EntityTeleportEvent.SpreadPlayersCommand event = new EntityTeleportEvent.SpreadPlayersCommand(entity, targetX, targetY, targetZ); + event.sendEvent(); + return event; + } + + public static EntityTeleportEvent.EnderEntity onEnderTeleport(LivingEntity entity, double targetX, double targetY, double targetZ) { // TODO: implement on shulker + EntityTeleportEvent.EnderEntity event = new EntityTeleportEvent.EnderEntity(entity, targetX, targetY, targetZ); + event.sendEvent(); + return event; + } + + @ApiStatus.Internal + public static EntityTeleportEvent.EnderPearl onEnderPearlLand(ServerPlayer entity, double targetX, double targetY, double targetZ, ThrownEnderpearl pearlEntity, float attackDamage, HitResult hitResult) { + EntityTeleportEvent.EnderPearl event = new EntityTeleportEvent.EnderPearl(entity, targetX, targetY, targetZ, pearlEntity, attackDamage, hitResult); + event.sendEvent(); + return event; + } + + public static EntityTeleportEvent.ChorusFruit onChorusFruitTeleport(LivingEntity entity, double targetX, double targetY, double targetZ) { + EntityTeleportEvent.ChorusFruit event = new EntityTeleportEvent.ChorusFruit(entity, targetX, targetY, targetZ); + event.sendEvent(); + return event; + } + + public static void firePlayerLoggedIn(Player player) { + new PlayerEvent.PlayerLoggedInEvent(player).sendEvent(); + } + + public static void firePlayerLoggedOut(Player player) { + new PlayerEvent.PlayerLoggedOutEvent(player).sendEvent(); + } + + public static boolean onEntityStruckByLightning(Entity entity, LightningBolt bolt) { + EntityStruckByLightningEvent event = new EntityStruckByLightningEvent(entity, bolt); + event.sendEvent(); + return event.isCanceled(); + } + + public static int onItemUseStart(LivingEntity entity, ItemStack item, int duration) { + var event = new LivingEntityUseItemEvent.Start(entity, item, duration); + return event.post() ? -1 : event.getDuration(); + } + + public static int onItemUseTick(LivingEntity entity, ItemStack item, int duration) { + var event = new LivingEntityUseItemEvent.Tick(entity, item, duration); + return event.post() ? -1 : event.getDuration(); + } + + public static boolean onUseItemStop(LivingEntity entity, ItemStack item, int duration) { + return new LivingEntityUseItemEvent.Stop(entity, item, duration).post(); + } + + public static ItemStack onItemUseFinish(LivingEntity entity, ItemStack item, int duration, ItemStack result) { + LivingEntityUseItemEvent.Finish event = new LivingEntityUseItemEvent.Finish(entity, item, duration, result); + event.sendEvent(); + return event.getResultStack(); + } + + public static void onStartEntityTracking(Entity entity, Player player) { + new PlayerEvent.StartTracking(player, entity).sendEvent(); + } + + public static void onStopEntityTracking(Entity entity, Player player) { + new PlayerEvent.StopTracking(player, entity).sendEvent(); + } + + public static void firePlayerLoadingEvent(Player player, File playerDirectory, String uuidString) { + new PlayerEvent.LoadFromFile(player, playerDirectory, uuidString).sendEvent(); + } + + public static void firePlayerSavingEvent(Player player, File playerDirectory, String uuidString) { + new PlayerEvent.SaveToFile(player, playerDirectory, uuidString).sendEvent(); + } + + public static void firePlayerLoadingEvent(Player player, PlayerDataStorage playerFileData, String uuidString) { + new PlayerEvent.LoadFromFile(player, ((PlayerDataStorageAccessor) playerFileData).getPlayerDir(), uuidString).sendEvent(); + } + + public static boolean onProjectileImpact(Projectile projectile, HitResult ray) { + ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, ray); + event.sendEvent(); + return event.isCanceled(); + } + + public static void firePlayerCraftingEvent(Player player, ItemStack crafted, Container craftMatrix) { + new PlayerEvent.ItemCraftedEvent(player, crafted, craftMatrix).sendEvent(); + } + + public static void firePlayerSmeltedEvent(Player player, ItemStack smelted) { + new PlayerEvent.ItemSmeltedEvent(player, smelted).sendEvent(); + } + + /** + * Fires {@link EntityTickEvent.Pre}. Called from the head of {@link LivingEntity#tick()}. + * + * @param entity The entity being ticked + * @return The event + */ + public static EntityTickEvent.Pre fireEntityTickPre(Entity entity) { + EntityTickEvent.Pre event = new EntityTickEvent.Pre(entity); + event.sendEvent(); + return event; + } + + /** + * Fires {@link EntityTickEvent.Post}. Called from the tail of {@link LivingEntity#tick()}. + * + * @param entity The entity being ticked + */ + public static void fireEntityTickPost(Entity entity) { + new EntityTickEvent.Post(entity).sendEvent(); + } + + /** + * Fires {@link PlayerTickEvent.Pre}. Called from the head of {@link Player#tick()}. + * + * @param player The player being ticked + */ + public static void firePlayerTickPre(Player player) { + new PlayerTickEvent.Pre(player).sendEvent(); + } + + /** + * Fires {@link PlayerTickEvent.Post}. Called from the tail of {@link Player#tick()}. + * + * @param player The player being ticked + */ + public static void firePlayerTickPost(Player player) { + new PlayerTickEvent.Post(player).sendEvent(); + } + + /** + * Fires the {@link CriticalHitEvent} and returns the resulting event. + * + * @param player The attacking player + * @param target The attack target + * @param vanillaCritical If the attack would have been a critical hit by vanilla's rules in {@link Player#attack(Entity)}. + * @param damageModifier The base damage modifier. Vanilla critical hits have a damage modifier of 1.5. + */ + public static CriticalHitEvent fireCriticalHit(Player player, Entity target, boolean vanillaCritical, float damageModifier) { + CriticalHitEvent event = new CriticalHitEvent(player, target, damageModifier, vanillaCritical); + event.sendEvent(); + return event; + } + + public static void onEntityEnterSection(Entity entity, long packedOldPos, long packedNewPos) { + new EntityEvent.EnteringSection(entity, packedOldPos, packedNewPos).sendEvent(); + } + + public static ShieldBlockEvent onShieldBlock(LivingEntity blocker, DamageSource source, float blocked) { + ShieldBlockEvent e = new ShieldBlockEvent(blocker, source, blocked); + e.sendEvent(); + return e; + } + + public static boolean onEffectRemoved(LivingEntity entity, Holder effect, @Nullable EffectCure cure) { + var event = new MobEffectEvent.Remove(entity, effect, cure); + event.sendEvent(); + return event.isCanceled(); + } + + public static boolean onEffectRemoved(LivingEntity entity, MobEffectInstance effectInstance, @Nullable EffectCure cure) { + var event = new MobEffectEvent.Remove(entity, effectInstance, cure); + event.sendEvent(); + return event.isCanceled(); + } + + /** + * Checks if a mob effect can be applied to an entity by firing {@link MobEffectEvent.Applicable}. + * + * @param entity The target entity the mob effect is being applied to. + * @param effect The mob effect being applied. + * @return True if the mob effect can be applied, otherwise false. + */ + public static boolean canMobEffectBeApplied(LivingEntity entity, MobEffectInstance effect) { + var event = new MobEffectEvent.Applicable(entity, effect); + event.sendEvent(); + return event.getApplicationResult(); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityAdditionalSpawnData.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityAdditionalSpawnData.java deleted file mode 100644 index a234b826a..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityAdditionalSpawnData.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity; - -import io.github.fabricators_of_create.porting_lib.core.PortingLib; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; - -/** - * An interface to implement onto Entities to have custom data synced on spawn. - * To use, implement the required methods, and have your getAddEntityPacket return createExtraDataSpawnPacket(this). - */ -public interface IEntityAdditionalSpawnData { - ResourceLocation EXTRA_DATA_PACKET = PortingLib.id("extra_entity_spawn_data"); - - /** - * Called by the client when it receives a Entity spawn packet. - * Data should be read out of the stream in the same way as it was written. - * - * @param buf The packet data stream - */ - void readSpawnData(FriendlyByteBuf buf); - - /** - * Called by the server when constructing the spawn packet. - * Data should be added to the provided stream. - * - * @param buf The packet data stream - */ - void writeSpawnData(FriendlyByteBuf buf); -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityWithComplexSpawn.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityWithComplexSpawn.java new file mode 100644 index 000000000..1e14e98db --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/IEntityWithComplexSpawn.java @@ -0,0 +1,25 @@ +package io.github.fabricators_of_create.porting_lib.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; + +/** + * An interface for Entities that need extra information to be communicated + * between the server and client when they are spawned. + */ +public interface IEntityWithComplexSpawn { + /** + * Called by the server when constructing the spawn packet. + * Data should be added to the provided stream. + * + * @param buffer The packet data stream + */ + void writeSpawnData(RegistryFriendlyByteBuf buffer); + + /** + * Called by the client when it receives a Entity spawn packet. + * Data should be read out of the stream in the same way as it was written. + * + * @param additionalData The packet data stream + */ + void readSpawnData(RegistryFriendlyByteBuf additionalData); +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ITeleporter.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ITeleporter.java deleted file mode 100644 index d0cd531d9..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ITeleporter.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity; - -import java.util.Objects; -import java.util.function.Function; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.portal.PortalForcer; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.phys.Vec3; - -/** - * Interface for handling the placement of entities during dimension change. - *

- * An implementation of this interface can be used to place the entity - * in a safe location, or generate a return portal, for instance. - *

- * See the {@link PortalForcer} class, which has - * been patched to implement this interface, for a vanilla example. - */ -public interface ITeleporter { - /** - * Called to handle placing the entity in the new world. - *

- * The initial position of the entity will be its - * position in the origin world, multiplied horizontally - * by the computed cross-dimensional movement factor. - *

- * Note that the supplied entity has not yet been spawned - * in the destination world at the time. - * - * @param entity the entity to be placed - * @param currentWorld the entity's origin - * @param destWorld the entity's destination - * @param yaw the suggested yaw value to apply - * @param repositionEntity a function to reposition the entity, which returns the new entity in the new dimension. This is the vanilla implementation of the dimension travel logic. If the supplied boolean is true, it is attempted to spawn a new portal. - * - * @return the entity in the new World. Vanilla creates for most {@link Entity}s a new instance and copy the data. But you are not allowed to create a new instance for {@link Player}s! Move the player and update its state, see {@link ServerPlayer#changeDimension(ServerLevel, ITeleporter)} - */ - default Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, Function repositionEntity) { - return repositionEntity.apply(true); - } - - /** - * Gets the PortalInfo. defaultPortalInfo references the - * vanilla code and should not be used for your purposes. - * Override this method to handle your own logic. - *

- * Return {@code null} to prevent teleporting. - * - * @param entity The entity teleporting before the teleport - * @param destWorld The world the entity is teleporting to - * @param defaultPortalInfo A reference to the vanilla method for getting portal info. You should implement your own logic instead of using this - * - * @return The location, rotation, and motion of the entity in the destWorld after the teleport - */ - @Nullable - default PortalInfo getPortalInfo(Entity entity, ServerLevel destWorld, Function defaultPortalInfo) { - return this.isVanilla() ? defaultPortalInfo.apply(destWorld) : new PortalInfo(entity.position(), Vec3.ZERO, entity.getYRot(), entity.getXRot()); - } - - /** - * Is this teleporter the vanilla instance. - */ - default boolean isVanilla() { - // Ignore the warning, this is fine at runtime - return Objects.equals(this.getClass(), PortalForcer.class); - } - - /** - * Called when vanilla wants to play the portal sound after teleporting. Return true to play the vanilla sound. - * @param player the player - * @param sourceWorld the source world - * @param destWorld the target world - * @return true to play the vanilla sound - */ - default boolean playTeleportSound(ServerPlayer player, ServerLevel sourceWorld, ServerLevel destWorld) { - return true; - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PartEntity.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PartEntity.java index 183518adc..f8e20baf6 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PartEntity.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PartEntity.java @@ -1,6 +1,7 @@ package io.github.fabricators_of_create.porting_lib.entity; import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.server.level.ServerEntity; import net.minecraft.world.entity.Entity; import net.minecraft.network.protocol.Packet; @@ -24,7 +25,7 @@ public T getParent() { } @Override - public Packet getAddEntityPacket() { + public Packet getAddEntityPacket(ServerEntity entity) { throw new UnsupportedOperationException(); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PortingLibEntity.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PortingLibEntity.java index d8bfb7d9f..99f6d078c 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PortingLibEntity.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/PortingLibEntity.java @@ -2,27 +2,23 @@ import com.mojang.logging.LogUtils; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; +import io.github.fabricators_of_create.porting_lib.core.util.LogicalSidedProvider; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityJoinLevelEvent; +import io.github.fabricators_of_create.porting_lib.entity.network.AdvancedAddEntityPayload; +import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; - -import net.minecraft.network.protocol.game.ClientboundBundlePacket; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.minecraft.server.TickTask; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.ApiStatus; import org.slf4j.Logger; -import java.util.List; - public class PortingLibEntity implements ModInitializer { public static final Logger LOGGER = LogUtils.getLogger(); @@ -48,33 +44,24 @@ public void onInitialize() { } } }); - ServerEntityEvents.EQUIPMENT_CHANGE.register((livingEntity, equipmentSlot, previousStack, currentStack) -> { - LivingEntityEvents.EQUIPMENT_CHANGE.invoker().onEquipmentChange(livingEntity, equipmentSlot, previousStack, currentStack); - }); - LivingEntityEvents.LivingJumpEvent.JUMP.register(event -> { - LivingEntityEvents.JUMP.invoker().onLivingEntityJump(event.getEntity()); - }); - LivingEntityEvents.LivingVisibilityEvent.VISIBILITY.register(event -> { - LivingEntityEvents.VISIBILITY.invoker().getEntityVisibilityMultiplier(event.getEntity(), event.getLookingEntity(), event.getVisibilityModifier()); - }); - LivingEntityEvents.LivingTickEvent.TICK.register(event -> { - if (!event.isCanceled()) - LivingEntityEvents.TICK.invoker().onLivingEntityTick(event.getEntity()); - }); - LivingAttackEvent.ATTACK.register(event -> { - LivingEntityEvents.ATTACK.invoker().onAttack(event.getEntity(), event.getSource(), event.getAmount()); - }); + PayloadTypeRegistry.playS2C().register(AdvancedAddEntityPayload.TYPE, AdvancedAddEntityPayload.STREAM_CODEC); + EntityJoinLevelEvent.EVENT.register(PortingLibEntity::onEntityJoinWorld); } - public static Packet getEntitySpawningPacket(Entity entity) { - Packet base = new ClientboundAddEntityPacket(entity); - if (entity instanceof IEntityAdditionalSpawnData extra) { - FriendlyByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(entity.getId()); - extra.writeSpawnData(buf); - Packet extraPacket = ServerPlayNetworking.createS2CPacket(IEntityAdditionalSpawnData.EXTRA_DATA_PACKET, buf); - return new ClientboundBundlePacket(List.of(base, extraPacket)); + public static void onEntityJoinWorld(EntityJoinLevelEvent event) { + Entity entity = event.getEntity(); + if (entity.getClass().equals(ItemEntity.class)) { + ItemStack stack = ((ItemEntity) entity).getItem(); + Item item = stack.getItem(); + if (item.hasCustomEntity(stack)) { + Entity newEntity = item.createEntity(event.getLevel(), entity, stack); + if (newEntity != null) { + entity.discard(); + event.setCanceled(true); + var executor = LogicalSidedProvider.WORKQUEUE.get(event.getLevel().isClientSide ? EnvType.CLIENT : EnvType.SERVER); + executor.tell(new TickTask(0, () -> event.getLevel().addFreshEntity(newEntity))); + } + } } - return base; } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/client/PortingLibEntityClient.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/client/PortingLibEntityClient.java index d45940c8b..d5c98d999 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/client/PortingLibEntityClient.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/client/PortingLibEntityClient.java @@ -1,37 +1,34 @@ package io.github.fabricators_of_create.porting_lib.entity.client; -import java.util.Objects; - -import io.github.fabricators_of_create.porting_lib.core.PortingLib; -import io.github.fabricators_of_create.porting_lib.entity.IEntityAdditionalSpawnData; +import io.github.fabricators_of_create.porting_lib.entity.IEntityWithComplexSpawn; import io.github.fabricators_of_create.porting_lib.entity.MultiPartEntity; import io.github.fabricators_of_create.porting_lib.entity.PartEntity; import io.github.fabricators_of_create.porting_lib.entity.mixin.common.BlockableEventLoopAccessor; +import io.github.fabricators_of_create.porting_lib.entity.network.AdvancedAddEntityPayload; +import io.netty.buffer.Unpooled; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; public class PortingLibEntityClient implements ClientModInitializer { - @Environment(EnvType.CLIENT) - private static void handlePacketReceived(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { - int entityId = buf.readVarInt(); - buf.retain(); // save for execute - execute(client, () -> { - Entity entity = Objects.requireNonNull(client.level).getEntity(entityId); - if (entity instanceof IEntityAdditionalSpawnData extra) { - extra.readSpawnData(buf); - } else { - PortingLib.LOGGER.error("ExtraSpawnDataEntity spawn data received, but no corresponding entity was found! Entity: [{}]", entity); + public static void handleAddComplexEntity(AdvancedAddEntityPayload advancedAddEntityPayload, ClientPlayNetworking.Context context) { + try { + Entity entity = context.player().level().getEntity(advancedAddEntityPayload.entityId()); + if (entity instanceof IEntityWithComplexSpawn entityAdditionalSpawnData) { + final RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(advancedAddEntityPayload.customPayload()), entity.registryAccess()); + try { + execute(context.client(), () -> entityAdditionalSpawnData.readSpawnData(buf)); + } finally { + buf.release(); + } } - buf.release(); - }); + } catch (Throwable t) { + context.responseSender().disconnect(Component.translatable("porting_lib.network.advanced_add_entity.failed", t.getMessage())); + } } private static void execute(Minecraft mc, Runnable task) { @@ -48,7 +45,7 @@ private static void execute(Minecraft mc, Runnable task) { @Override public void onInitializeClient() { - ClientPlayNetworking.registerGlobalReceiver(IEntityAdditionalSpawnData.EXTRA_DATA_PACKET, PortingLibEntityClient::handlePacketReceived); + ClientPlayNetworking.registerGlobalReceiver(AdvancedAddEntityPayload.TYPE, PortingLibEntityClient::handleAddComplexEntity); ClientEntityEvents.ENTITY_LOAD.register((entity, world) -> { if (entity instanceof MultiPartEntity partEntity && partEntity.isMultipartEntity()) { for (PartEntity part : partEntity.getParts()) { diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/CriticalHitEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/CriticalHitEvent.java deleted file mode 100644 index 47415e633..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/CriticalHitEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; - -/** - * This event is fired whenever a player attacks an Entity in - * {@link Player#attack(Entity)}.
- *
- * This event is not cancelable.
- *
- * This event has a result.
- * DEFAULT: means the vanilla logic will determine if this a critical hit.
- * DENY: it will not be a critical hit but the player still will attack
- * ALLOW: this attack is forced to be critical - *
- **/ -public class CriticalHitEvent extends PlayerEvents { - public static final Event CRITICAL_HIT = EventFactory.createArrayBacked(CriticalCallback.class, callbacks -> event -> { - for (CriticalCallback callback : callbacks) - callback.onCriticalHit(event); - }); - private float damageModifier; - private final float oldDamageModifier; - private final Entity target; - private final boolean vanillaCritical; - - public CriticalHitEvent(Player player, Entity target, float damageModifier, boolean vanillaCritical) { - super(player); - this.target = target; - this.damageModifier = damageModifier; - this.oldDamageModifier = damageModifier; - this.vanillaCritical = vanillaCritical; - } - - /** - * The Entity that was damaged by the player. - */ - public Entity getTarget() { - return target; - } - - /** - * This set the damage multiplier for the hit. - * If you set it to 0, then the particles are still generated but damage is not done. - */ - public void setDamageModifier(float mod) { - this.damageModifier = mod; - } - - /** - * The damage modifier for the hit.
- * This is by default 1.5F for ciritcal hits and 1F for normal hits . - */ - public float getDamageModifier() { - return this.damageModifier; - } - - /** - * The orignal damage modifier for the hit wthout any changes.
- * This is 1.5F for ciritcal hits and 1F for normal hits . - */ - public float getOldDamageModifier() { - return this.oldDamageModifier; - } - - /** - * Returns true if this hit was critical by vanilla - */ - public boolean isVanillaCritical() { - return vanillaCritical; - } - - @Override - public void sendEvent() { - CRITICAL_HIT.invoker().onCriticalHit(this); - } - - @FunctionalInterface - public interface CriticalCallback { - void onCriticalHit(CriticalHitEvent event); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvent.java new file mode 100644 index 000000000..a8d48a457 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvent.java @@ -0,0 +1,201 @@ +package io.github.fabricators_of_create.porting_lib.entity.events; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.core.SectionPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.Pose; + +public abstract class EntityEvent extends BaseEvent { + protected final Entity entity; + + public EntityEvent(Entity entity) { + this.entity = entity; + } + + public Entity getEntity() { + return entity; + } + + /** + * EntityConstructing is fired when an Entity is being created.
+ * This event is fired within the constructor of the Entity.
+ *
+ * This event is not {@link CancellableEvent}.
+ **/ + public static class EntityConstructing extends EntityEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onConstructing(event); + }); + + public EntityConstructing(Entity entity) { + super(entity); + } + + @Override + public void sendEvent() { + EVENT.invoker().onConstructing(this); + } + + public interface Callback { + void onConstructing(EntityConstructing event); + } + } + + /** + * This event is fired on server and client after an Entity has entered a different section.
+ * Sections are 16x16x16 block grids of the world.
+ * This event does not fire when a new entity is spawned, only when an entity moves from one section to another one. + * Use {@link EntityJoinLevelEvent} to detect new entities joining the world. + *
+ * This event is not {@link CancellableEvent}.
+ **/ + public static class EnteringSection extends EntityEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEnteringSection(event); + }); + + private final long packedOldPos; + private final long packedNewPos; + + public EnteringSection(Entity entity, long packedOldPos, long packedNewPos) { + super(entity); + this.packedOldPos = packedOldPos; + this.packedNewPos = packedNewPos; + } + + /** + * A packed version of the old section's position. This is to be used with the various methods in {@link SectionPos}, + * such as {@link SectionPos#of(long)} or {@link SectionPos#x(long)} to avoid allocation. + * + * @return the packed position of the old section + */ + public long getPackedOldPos() { + return packedOldPos; + } + + /** + * A packed version of the new section's position. This is to be used with the various methods in {@link SectionPos}, + * such as {@link SectionPos#of(long)} or {@link SectionPos#x(long)} to avoid allocation. + * + * @return the packed position of the new section + */ + public long getPackedNewPos() { + return packedNewPos; + } + + /** + * @return the position of the old section + */ + public SectionPos getOldPos() { + return SectionPos.of(packedOldPos); + } + + /** + * @return the position of the new section + */ + public SectionPos getNewPos() { + return SectionPos.of(packedNewPos); + } + + /** + * Whether the chunk has changed as part of this event. If this method returns false, only the Y position of the + * section has changed. + */ + public boolean didChunkChange() { + return SectionPos.x(packedOldPos) != SectionPos.x(packedNewPos) || SectionPos.z(packedOldPos) != SectionPos.z(packedNewPos); + } + + @Override + public void sendEvent() { + EVENT.invoker().onEnteringSection(this); + } + + public interface Callback { + void onEnteringSection(EnteringSection event); + } + } + + /** + * This event is fired whenever the {@link Pose} changes, and in a few other hardcoded scenarios.
+ * CAREFUL: This is also fired in the Entity constructor. Therefore the entity(subclass) might not be fully initialized. Check Entity#isAddedToWorld() or !Entity#firstUpdate.
+ * If you change the player's size, you probably want to set the eye height accordingly as well
+ **/ + public static class Size extends EntityEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEntitySizeChange(event); + }); + + private final Pose pose; + private final EntityDimensions oldSize; + private EntityDimensions newSize; + private final float oldEyeHeight; + private float newEyeHeight; + + public Size(Entity entity, Pose pose, EntityDimensions size, float defaultEyeHeight) { + this(entity, pose, size, size, defaultEyeHeight, defaultEyeHeight); + } + + public Size(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float oldEyeHeight, float newEyeHeight) { + super(entity); + this.pose = pose; + this.oldSize = oldSize; + this.newSize = newSize; + this.oldEyeHeight = oldEyeHeight; + this.newEyeHeight = newEyeHeight; + } + + public Pose getPose() { + return pose; + } + + public EntityDimensions getOldSize() { + return oldSize; + } + + public EntityDimensions getNewSize() { + return newSize; + } + + public void setNewSize(EntityDimensions size) { + setNewSize(size, false); + } + + /** + * Set the new size of the entity. Set updateEyeHeight to true to also update the eye height according to the new size. + */ + public void setNewSize(EntityDimensions size, boolean updateEyeHeight) { + this.newSize = size; + if (updateEyeHeight) { + this.newEyeHeight = this.getEntity().getEyeHeight(this.getPose()); + } + } + + public float getOldEyeHeight() { + return oldEyeHeight; + } + + public float getNewEyeHeight() { + return newEyeHeight; + } + + public void setNewEyeHeight(float newHeight) { + this.newEyeHeight = newHeight; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntitySizeChange(this); + } + + public interface Callback { + void onEntitySizeChange(Size event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEventFactory.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEventFactory.java deleted file mode 100644 index d282cf9df..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEventFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDamageEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingHurtEvent; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.HitResult; - -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; - -public class EntityEventFactory { - public static boolean onProjectileImpact(Projectile projectile, HitResult ray) { - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, ray); - event.sendEvent(); - return event.isCanceled(); - } - - // This event is probably not going to be implemented but is here for possible future compatibility - public static boolean getMobGriefingEvent(Level level, @Nullable Entity entity) { -// if (entity == null) - return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - -// EntityMobGriefingEvent event = new EntityMobGriefingEvent(entity); -// MinecraftForge.EVENT_BUS.post(event); -// -// Result result = event.getResult(); -// return result == Result.DEFAULT ? level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) : result == Result.ALLOW; - } - - public static float onLivingHurt(LivingEntity entity, DamageSource src, float amount) { - LivingHurtEvent event = new LivingHurtEvent(entity, src, amount); - event.sendEvent(); - return (event.isCanceled() ? 0 : event.getAmount()); - } - - public static float onLivingDamage(LivingEntity entity, DamageSource src, float amount) { - LivingDamageEvent event = new LivingDamageEvent(entity, src, amount); - event.sendEvent(); - return (event.isCanceled() ? 0 : event.getAmount()); - } - - public static boolean onLivingDeath(LivingEntity entity, DamageSource src) { - LivingDeathEvent event = new LivingDeathEvent(entity, src); - event.sendEvent(); - return event.isCanceled(); - } - - public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Collection drops, int lootingLevel, boolean recentlyHit) { - return LivingEntityEvents.DROPS.invoker().onLivingEntityDrops(entity, source, drops, lootingLevel, recentlyHit); - } - - public static void onLivingJump(LivingEntity entity) { - new LivingEntityEvents.LivingJumpEvent(entity).sendEvent(); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvents.java deleted file mode 100644 index d483a1648..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityEvents.java +++ /dev/null @@ -1,212 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Entity.RemovalReason; -import net.minecraft.world.entity.EntityDimensions; -import net.minecraft.world.entity.Pose; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; - -public abstract class EntityEvents extends BaseEvent { - protected final Entity entity; - - public EntityEvents(Entity entity) { - this.entity = entity; - } - - public Entity getEntity() { - return entity; - } - - public static final Event SIZE = EventFactory.createArrayBacked(EntitySize.class, callbacks -> event -> { - for (EntitySize callback : callbacks) - callback.onEntitySizeChange(event); - }); - - public static final Event ON_JOIN_WORLD = EventFactory.createArrayBacked(JoinWorld.class, callbacks -> (entity, world, loadedFromDisk) -> { - for (JoinWorld callback : callbacks) - if (!callback.onJoinWorld(entity, world, loadedFromDisk)) - return true; - return false; - }); - - public static final Event ON_REMOVE = EventFactory.createArrayBacked(Remove.class, callbacks -> ((entity, reason) -> { - for (Remove e : callbacks) - e.onRemove(entity, reason); - })); - - public static final Event TELEPORT = EventFactory.createArrayBacked(Teleport.class, callbacks -> (event) -> { - for (Teleport callback : callbacks) { - callback.onTeleport(event); - if (event.isCanceled()) - return; - } - }); - - public static final Event START_TRACKING_TAIL = EventFactory.createArrayBacked(Tracking.class, callbacks -> (entity, player) -> { - for (Tracking callback : callbacks) { - callback.onTrackingStart(entity, player); - } - }); - - public static final Event ENTERING_SECTION = EventFactory.createArrayBacked(EnteringSection.class, callbacks -> (entity, packedOldPos, packedNewPos) -> { - for (EnteringSection e : callbacks) - e.onEntityEnterSection(entity, packedOldPos, packedNewPos); - }); - - public static final Event STRUCK_BY_LIGHTING = EventFactory.createArrayBacked(LightingStrike.class, callbacks -> event -> { - for (LightingStrike callback : callbacks) - callback.onEntityStruckByLightning(event); - }); - - public static final Event PROJECTILE_IMPACT = EventFactory.createArrayBacked(ProjectileImpact.class, callbacks -> event -> { - for (ProjectileImpact callback : callbacks) - callback.onProjectileImpact(event); - }); - - @FunctionalInterface - public interface ProjectileImpact { - void onProjectileImpact(ProjectileImpactEvent event); - } - - @FunctionalInterface - public interface EnteringSection { - void onEntityEnterSection(Entity entity, long packedOldPos, long packedNewPos); - } - - @FunctionalInterface - public interface JoinWorld { - boolean onJoinWorld(Entity entity, Level world, boolean loadedFromDisk); - } - - @FunctionalInterface - public interface Remove { - void onRemove(Entity entity, RemovalReason reason); - } - - @FunctionalInterface - public interface EyeHeight { - float onEntitySize(Entity entity, float eyeHeight); - } - - @FunctionalInterface - public interface LightingStrike { - void onEntityStruckByLightning(EntityStruckByLightningEvent event); - } - - @FunctionalInterface - public interface Teleport { - void onTeleport(EntityTeleportEvent event); - - class EntityTeleportEvent extends EntityEvents { - protected double targetX, targetY, targetZ; - - public EntityTeleportEvent(Entity entity, double targetX, double targetY, double targetZ) { - super(entity); - this.targetX = targetX; - this.targetY = targetY; - this.targetZ = targetZ; - } - - @Override - public void sendEvent() { - EntityEvents.TELEPORT.invoker().onTeleport(this); - } - - public Entity getEntity() { return entity; } - public double getTargetX() { return targetX; } - public void setTargetX(double targetX) { this.targetX = targetX; } - public double getTargetY() { return targetY; } - public void setTargetY(double targetY) { this.targetY = targetY; } - public double getTargetZ() { return targetZ; } - public void setTargetZ(double targetZ) { this.targetZ = targetZ; } - public Vec3 getTarget() { return new Vec3(this.targetX, this.targetY, this.targetZ); } - public double getPrevX() { return getEntity().getX(); } - public double getPrevY() { return getEntity().getY(); } - public double getPrevZ() { return getEntity().getZ(); } - public Vec3 getPrev() { return getEntity().position(); } - } - } - - public interface Tracking { - void onTrackingStart(Entity tracking, ServerPlayer player); - } - - @FunctionalInterface - public interface EntitySize { - void onEntitySizeChange(Size event); - } - - /** - * This event is fired whenever the {@link Pose} changes, and in a few other hardcoded scenarios.
- * CAREFUL: This is also fired in the Entity constructor. Therefore the entity(subclass) might not be fully initialized. Check Entity#isAddedToWorld() or !Entity#firstUpdate.
- * If you change the player's size, you probably want to set the eye height accordingly as well
- **/ - public static class Size extends EntityEvents { - private final Pose pose; - private final EntityDimensions oldSize; - private EntityDimensions newSize; - private final float oldEyeHeight; - private float newEyeHeight; - - public Size(Entity entity, Pose pose, EntityDimensions size, float defaultEyeHeight) { - this(entity, pose, size, size, defaultEyeHeight, defaultEyeHeight); - } - - public Size(Entity entity, Pose pose, EntityDimensions oldSize, EntityDimensions newSize, float oldEyeHeight, float newEyeHeight) { - super(entity); - this.pose = pose; - this.oldSize = oldSize; - this.newSize = newSize; - this.oldEyeHeight = oldEyeHeight; - this.newEyeHeight = newEyeHeight; - } - - public Pose getPose() { - return pose; - } - - public EntityDimensions getOldSize() { - return oldSize; - } - - public EntityDimensions getNewSize() { - return newSize; - } - - public void setNewSize(EntityDimensions size) { - setNewSize(size, false); - } - - /** - * Set the new size of the entity. Set updateEyeHeight to true to also update the eye height according to the new size. - */ - public void setNewSize(EntityDimensions size, boolean updateEyeHeight) { - this.newSize = size; - if (updateEyeHeight) { - this.newEyeHeight = this.getEntity().getEyeHeight(this.getPose()); - } - } - - public float getOldEyeHeight() { - return oldEyeHeight; - } - - public float getNewEyeHeight() { - return newEyeHeight; - } - - public void setNewEyeHeight(float newHeight) { - this.newEyeHeight = newHeight; - } - - @Override - public void sendEvent() { - SIZE.invoker().onEntitySizeChange(this); - } - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityInteractCallback.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityInteractCallback.java deleted file mode 100644 index b31e7af04..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityInteractCallback.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; - -import org.jetbrains.annotations.Nullable; - -public interface EntityInteractCallback { - /** - * Fired when an entity is interacted with by a player, from {@link Player#interactOn(Entity, InteractionHand)} - */ - Event EVENT = EventFactory.createArrayBacked(EntityInteractCallback.class, callbacks -> ((player, hand, target) -> { - for(EntityInteractCallback e : callbacks) { - InteractionResult result = e.onEntityInteract(player, hand, target); - if(result != null) - return result; - } - return null; - })); - - /** - * @return any non-null value to cancel the interaction and replace the result of it - */ - @Nullable - InteractionResult onEntityInteract(Player player, InteractionHand hand, Entity target); -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityJoinLevelEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityJoinLevelEvent.java new file mode 100644 index 000000000..28e3545b6 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityJoinLevelEvent.java @@ -0,0 +1,67 @@ +package io.github.fabricators_of_create.porting_lib.entity.events; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; + +/** + * This event is fired whenever an {@link Entity} joins a {@link Level}. + * This event is fired whenever an entity is added to a level in {@link Level#addFreshEntity(Entity)} + * and {@code PersistentEntitySectionManager#addNewEntity(Entity, boolean)}. + *

+ * Note: This event may be called before the underlying {@link LevelChunk} is promoted to {@link ChunkStatus#FULL}. + * You will cause chunk loading deadlocks if you do not delay your world interactions. + *

+ * This event is {@linkplain CancellableEvent cancellable}. + * If the event is canceled, the entity will not be added to the level. + *

+ * This event is fired on both logical sides. + **/ +public class EntityJoinLevelEvent extends EntityEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEntityJoin(event); + }); + + private final Level level; + private final boolean loadedFromDisk; + + public EntityJoinLevelEvent(Entity entity, Level level) { + this(entity, level, false); + } + + public EntityJoinLevelEvent(Entity entity, Level level, boolean loadedFromDisk) { + super(entity); + this.level = level; + this.loadedFromDisk = loadedFromDisk; + } + + /** + * {@return the level that the entity is set to join} + */ + public Level getLevel() { + return level; + } + + /** + * @return {@code true} if the entity was loaded from disk, {@code false} otherwise. + * On the {@linkplain EnvType#CLIENT logical client}, this will always return {@code false}. + */ + public boolean loadedFromDisk() { + return loadedFromDisk; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityJoin(this); + } + + public interface Callback { + void onEntityJoin(EntityJoinLevelEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvent.java new file mode 100644 index 000000000..0c921bccf --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvent.java @@ -0,0 +1,66 @@ +package io.github.fabricators_of_create.porting_lib.entity.events; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; + +/** + * This event gets fired whenever a entity mounts/dismounts another entity.
+ * entityBeingMounted can be null, be sure to check for that. + *
+ *
+ * This event is {@link CancellableEvent}.
+ * If this event is canceled, the entity does not mount/dismount the other entity.
+ * + */ +public class EntityMountEvent extends EntityEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEntityMounting(event); + }); + + private final Entity entityMounting; + private final Entity entityBeingMounted; + private final Level level; + + private final boolean isMounting; + + public EntityMountEvent(Entity entityMounting, Entity entityBeingMounted, Level level, boolean isMounting) { + super(entityMounting); + this.entityMounting = entityMounting; + this.entityBeingMounted = entityBeingMounted; + this.level = level; + this.isMounting = isMounting; + } + + public boolean isMounting() { + return isMounting; + } + + public boolean isDismounting() { + return !isMounting; + } + + public Entity getEntityMounting() { + return entityMounting; + } + + public Entity getEntityBeingMounted() { + return entityBeingMounted; + } + + public Level getLevel() { + return level; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityMounting(this); + } + + public interface Callback { + void onEntityMounting(EntityMountEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvents.java deleted file mode 100644 index fa45bdece..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityMountEvents.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.Entity; - -import org.apache.commons.lang3.function.TriFunction; - -public class EntityMountEvents { - /** - * Register one listener to both events. The listener receives the vehicle, the passenger, - * and a boolean determining if the passenger is mounting or dismounting. - * Returning false will cancel either event. - */ - public static void registerForBoth(TriFunction listener) { - MOUNT.register((vehicle, passenger) -> listener.apply(vehicle, passenger, true)); - DISMOUNT.register((vehicle, passenger) -> listener.apply(vehicle, passenger, false)); - } - - /** - * Fired when an entity tries to start riding another. - */ - public static final Event MOUNT = EventFactory.createArrayBacked(Mount.class, callbacks -> (vehicle, passenger) -> { - for (Mount callback : callbacks) { - if (!callback.canStartRiding(vehicle, passenger)) - return false; - } - return true; - }); - - @FunctionalInterface - public interface Mount { - /** - * @return false to cancel mounting - */ - boolean canStartRiding(Entity vehicle, Entity passenger); - } - - /** - * Fired when an entity tries to stop riding another. - */ - public static final Event DISMOUNT = EventFactory.createArrayBacked(Dismount.class, callbacks -> (vehicle, passenger) -> { - for (Dismount callback : callbacks) { - if (!callback.onStopRiding(vehicle, passenger)) - return false; - } - return true; - }); - - @FunctionalInterface - public interface Dismount { - /** - * @return false to cancel dismounting - */ - boolean onStopRiding(Entity vehicle, Entity passenger); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityReadExtraDataCallback.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityReadExtraDataCallback.java deleted file mode 100644 index 0352c1f61..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityReadExtraDataCallback.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.Entity; - -import javax.annotation.Nullable; - -public interface EntityReadExtraDataCallback { - Event EVENT = EventFactory.createArrayBacked(EntityReadExtraDataCallback.class, callbacks -> (entity, data) -> { - for (EntityReadExtraDataCallback callback : callbacks) { - callback.onLoad(entity, data); - } - }); - - void onLoad(Entity entity, @Nullable CompoundTag extraData); -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityStruckByLightningEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityStruckByLightningEvent.java index c62ea4c85..45a10fbeb 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityStruckByLightningEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityStruckByLightningEvent.java @@ -1,19 +1,28 @@ package io.github.fabricators_of_create.porting_lib.entity.events; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LightningBolt; /** * EntityStruckByLightningEvent is fired when an Entity is about to be struck by lightening.
* This event is fired whenever an EntityLightningBolt is updated to strike an Entity in - * {@link LightningBolt#tick()}.
+ * {@link LightningBolt#tick()} via {@link EntityHooks#onEntityStruckByLightning(Entity, LightningBolt)}.
*
* {@link #lightning} contains the instance of EntityLightningBolt attempting to strike an entity.
*
+ * This event is {@link CancellableEvent}.
* If this event is canceled, the Entity is not struck by the lightening.
- *
**/ -public class EntityStruckByLightningEvent extends EntityEvents { +public class EntityStruckByLightningEvent extends EntityEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onStruckByLightning(event); + }); + private final LightningBolt lightning; public EntityStruckByLightningEvent(Entity entity, LightningBolt lightning) { @@ -27,6 +36,10 @@ public LightningBolt getLightning() { @Override public void sendEvent() { - STRUCK_BY_LIGHTING.invoker().onEntityStruckByLightning(this); + EVENT.invoker().onStruckByLightning(this); + } + + public interface Callback { + void onStruckByLightning(EntityStruckByLightningEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityTeleportEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityTeleportEvent.java new file mode 100644 index 000000000..1810e61a2 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/EntityTeleportEvent.java @@ -0,0 +1,279 @@ +package io.github.fabricators_of_create.porting_lib.entity.events; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.ThrownEnderpearl; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +/** + * EntityTeleportEvent is fired when an event involving any teleportation of an Entity occurs.
+ * If a method utilizes this {@link BaseEvent} as its parameter, the method will + * receive every child event of this class.
+ *
+ * {@link #getTarget()} contains the target destination.
+ * {@link #getPrev()} contains the entity's current position.
+ *
+ **/ +public abstract class EntityTeleportEvent extends EntityEvent implements CancellableEvent { + protected double targetX; + protected double targetY; + protected double targetZ; + + public EntityTeleportEvent(Entity entity, double targetX, double targetY, double targetZ) { + super(entity); + this.targetX = targetX; + this.targetY = targetY; + this.targetZ = targetZ; + } + + public double getTargetX() { + return targetX; + } + + public void setTargetX(double targetX) { + this.targetX = targetX; + } + + public double getTargetY() { + return targetY; + } + + public void setTargetY(double targetY) { + this.targetY = targetY; + } + + public double getTargetZ() { + return targetZ; + } + + public void setTargetZ(double targetZ) { + this.targetZ = targetZ; + } + + public Vec3 getTarget() { + return new Vec3(this.targetX, this.targetY, this.targetZ); + } + + public double getPrevX() { + return getEntity().getX(); + } + + public double getPrevY() { + return getEntity().getY(); + } + + public double getPrevZ() { + return getEntity().getZ(); + } + + public Vec3 getPrev() { + return getEntity().position(); + } + + /** + * EntityTeleportEvent.TeleportCommand is fired before a living entity is teleported + * from use of {@link net.minecraft.server.commands.TeleportCommand}. + *
+ * This event is {@link CancellableEvent}.
+ * If the event is not canceled, the entity will be teleported. + *
+ * This event is only fired on the {@link EnvType#SERVER} side.
+ *
+ * If this event is canceled, the entity will not be teleported. + */ + public static class TeleportCommand extends EntityTeleportEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onTeleportCommand(event); + }); + + public TeleportCommand(Entity entity, double targetX, double targetY, double targetZ) { + super(entity, targetX, targetY, targetZ); + } + + @Override + public void sendEvent() { + EVENT.invoker().onTeleportCommand(this); + } + + public interface Callback { + void onTeleportCommand(TeleportCommand event); + } + } + + /** + * EntityTeleportEvent.SpreadPlayersCommand is fired before a living entity is teleported + * from use of {@link net.minecraft.server.commands.SpreadPlayersCommand}. + *
+ * This event is {@link CancellableEvent}.
+ * If the event is not canceled, the entity will be teleported. + *
+ * This event is only fired on the {@link EnvType#SERVER} side.
+ *
+ * If this event is canceled, the entity will not be teleported. + */ + public static class SpreadPlayersCommand extends EntityTeleportEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onSpreadPlayersCommand(event); + }); + + public SpreadPlayersCommand(Entity entity, double targetX, double targetY, double targetZ) { + super(entity, targetX, targetY, targetZ); + } + + @Override + public void sendEvent() { + EVENT.invoker().onSpreadPlayersCommand(this); + } + + public interface Callback { + void onSpreadPlayersCommand(SpreadPlayersCommand event); + } + } + + /** + * EntityTeleportEvent.EnderEntity is fired before an Enderman or Shulker randomly teleports. + *
+ * This event is {@link CancellableEvent}.
+ * If the event is not canceled, the entity will be teleported. + *
+ * This event is only fired on the {@link EnvType#SERVER} side.
+ *
+ * If this event is canceled, the entity will not be teleported. + */ + public static class EnderEntity extends EntityTeleportEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEnderEntityTeleport(event); + }); + + private final LivingEntity entityLiving; + + public EnderEntity(LivingEntity entity, double targetX, double targetY, double targetZ) { + super(entity, targetX, targetY, targetZ); + this.entityLiving = entity; + } + + public LivingEntity getEntityLiving() { + return entityLiving; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEnderEntityTeleport(this); + } + + public interface Callback { + void onEnderEntityTeleport(EnderEntity event); + } + } + + /** + * EntityTeleportEvent.EnderPearl is fired before an Entity is teleported from an EnderPearlEntity. + *
+ * This event is {@link CancellableEvent}.
+ * If the event is not canceled, the entity will be teleported. + *
+ * This event is only fired on the {@link EnvType#SERVER} side.
+ *
+ * If this event is canceled, the entity will not be teleported. + */ + public static class EnderPearl extends EntityTeleportEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEnderPearlTeleport(event); + }); + + private final ServerPlayer player; + private final ThrownEnderpearl pearlEntity; + private float attackDamage; + private final HitResult hitResult; + + @ApiStatus.Internal + public EnderPearl(ServerPlayer entity, double targetX, double targetY, double targetZ, ThrownEnderpearl pearlEntity, float attackDamage, HitResult hitResult) { + super(entity, targetX, targetY, targetZ); + this.pearlEntity = pearlEntity; + this.player = entity; + this.attackDamage = attackDamage; + this.hitResult = hitResult; + } + + public ThrownEnderpearl getPearlEntity() { + return pearlEntity; + } + + public ServerPlayer getPlayer() { + return player; + } + + @Nullable + public HitResult getHitResult() { + return this.hitResult; + } + + public float getAttackDamage() { + return attackDamage; + } + + public void setAttackDamage(float attackDamage) { + this.attackDamage = attackDamage; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEnderPearlTeleport(this); + } + + public interface Callback { + void onEnderPearlTeleport(EnderPearl event); + } + } + + /** + * EntityTeleportEvent.ChorusFruit is fired before a LivingEntity is teleported due to consuming Chorus Fruit. + *
+ * This event is {@link CancellableEvent}.
+ * If the event is not canceled, the entity will be teleported. + *
+ * This event is only fired on the {@link EnvType#SERVER} side.
+ *
+ * If this event is canceled, the entity will not be teleported. + */ + public static class ChorusFruit extends EntityTeleportEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onChorusFruitTeleport(event); + }); + + private final LivingEntity entityLiving; + + public ChorusFruit(LivingEntity entity, double targetX, double targetY, double targetZ) { + super(entity, targetX, targetY, targetZ); + this.entityLiving = entity; + } + + public LivingEntity getEntityLiving() { + return entityLiving; + } + + @Override + public void sendEvent() { + EVENT.invoker().onChorusFruitTeleport(this); + } + + public interface Callback { + void onChorusFruitTeleport(ChorusFruit event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityEvents.java deleted file mode 100644 index 3beecd14d..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityEvents.java +++ /dev/null @@ -1,395 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.MobSpawnType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.monster.MagmaCube; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.LevelAccessor; - -// TODO: Rename to LivingEvent in 1.20.4 to avoid confusing modders -public abstract class LivingEntityEvents extends EntityEvents { - public static final Event EXPERIENCE_DROP = EventFactory.createArrayBacked(ExperienceDrop.class, callbacks -> (i, attackingPlayer, entity) -> { - for (ExperienceDrop callback : callbacks) { - return callback.onLivingEntityExperienceDrop(i, attackingPlayer, entity); - } - - return i; - }); - - public static final Event KNOCKBACK_STRENGTH = EventFactory.createArrayBacked(KnockBackStrength.class, callbacks -> (strength, player) -> { - for (KnockBackStrength callback : callbacks) { - return callback.onLivingEntityTakeKnockback(strength, player); - } - - return strength; - }); - - public static final Event DROPS = EventFactory.createArrayBacked(Drops.class, callbacks -> (target, source, drops, lootingLevel, recentlyHit) -> { - for (Drops callback : callbacks) { - if (callback.onLivingEntityDrops(target, source, drops, lootingLevel, recentlyHit)) { - return true; - } - } - - return false; - }); - - public static final Event FALL = EventFactory.createArrayBacked(Fall.class, callbacks -> (info) -> { - for (Fall e : callbacks) { - e.onFall(info); - if (info.isCanceled()) { - return; - } - } - }); - - public static final Event LOOTING_LEVEL = EventFactory.createArrayBacked(LootingLevel.class, callbacks -> (source, target, level, recent) -> { - for (LootingLevel callback : callbacks) { - int lootingLevel = callback.modifyLootingLevel(source, target, level, recent); - if (lootingLevel != level) { - return lootingLevel; - } - } - - return level; - }); - - @Deprecated(forRemoval = true) - public static final Event TICK = EventFactory.createArrayBacked(Tick.class, callbacks -> (entity) -> { - for (Tick callback : callbacks) { - callback.onLivingEntityTick(entity); - } - }); - - @Deprecated(forRemoval = true) - public static final Event HURT = EventFactory.createArrayBacked(ActuallyHurt.class, callbacks -> (source, damaged, amount) -> { - for (ActuallyHurt callback : callbacks) { - float newAmount = callback.onHurt(source, damaged, amount); - if (newAmount != amount) return newAmount; - } - return amount; - }); - - /** - * Modders should individually mixin into the entity spawns they want to change - */ - @Deprecated(forRemoval = true) - public static final Event CHECK_SPAWN = EventFactory.createArrayBacked(CheckSpawn.class, callbacks -> ((entity, world, x, y, z, spawner, spawnReason) -> { - for (CheckSpawn callback : callbacks) - if (!callback.onCheckSpawn(entity, world, x, y, z, spawner, spawnReason)) - return true; - return false; - })); - - @Deprecated(forRemoval = true) - public static final Event JUMP = EventFactory.createArrayBacked(Jump.class, callbacks -> (entity) -> { - for (Jump callback : callbacks) { - callback.onLivingEntityJump(entity); - } - }); - - @Deprecated(forRemoval = true) - public static final Event ATTACK = EventFactory.createArrayBacked(Attack.class, callbacks -> (entity, source, amount) -> { - for (Attack callback : callbacks) { - if (callback.onAttack(entity, source, amount)) { - return true; - } - } - return false; - }); - - /** - * Use fabric apis event {@link net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents#EQUIPMENT_CHANGE} - */ - @Deprecated(forRemoval = true) - public static final Event EQUIPMENT_CHANGE = EventFactory.createArrayBacked(EquipmentChange.class, callbacks -> ((entity, slot, from, to) -> { - for (EquipmentChange callback : callbacks) - callback.onEquipmentChange(entity, slot, from, to); - })); - - @Deprecated(forRemoval = true) - public static final Event VISIBILITY = EventFactory.createArrayBacked(Visibility.class, callbacks -> (entity, lookingEntity, originalMultiplier) -> { - for (Visibility e : callbacks) { - double newMultiplier = e.getEntityVisibilityMultiplier(entity, lookingEntity, originalMultiplier); - if (newMultiplier != originalMultiplier) - return newMultiplier; - } - return originalMultiplier; - }); - - public static final Event CHANGE_TARGET = EventFactory.createArrayBacked(ChangeTarget.class, callbacks -> (event) -> { - for (ChangeTarget e : callbacks) { - e.onChangeTarget(event); - if (event.isCanceled()) - return; - } - }); - - private final LivingEntity livingEntity; - - public LivingEntityEvents(LivingEntity entity) { - super(entity); - livingEntity = entity; - } - - @Override - public LivingEntity getEntity() { - return livingEntity; - } - - /** - * LivingUpdateEvent is fired when a LivingEntity is ticked in {@link LivingEntity#tick()}.
- *
- * This event is cancelable.
- * If this event is canceled, the Entity does not update.
- *
- * This event does not have a result.
- *
- **/ - public static class LivingTickEvent extends LivingEntityEvents { - public static final Event TICK = EventFactory.createArrayBacked(NewTick.class, callbacks -> (event) -> { - for (NewTick callback : callbacks) - callback.onLivingTick(event); - }); - - public LivingTickEvent(LivingEntity e) { - super(e); - } - - @Override - public void sendEvent() { - TICK.invoker().onLivingTick(this); - } - } - - /** - * LivingJumpEvent is fired when an Entity jumps.
- * This event is fired whenever an Entity jumps in - * {@link LivingEntity#jumpFromGround()}, {@link MagmaCube#jumpFromGround()}, - * and {@code Horse#jumpFromGround()}.
- *
- * This event is not cancelable.
- *
- * This event does not have a result.}
- *
- **/ - public static class LivingJumpEvent extends LivingEntityEvents { - public static final Event JUMP = EventFactory.createArrayBacked(NewJump.class, callbacks -> (event) -> { - for (NewJump callback : callbacks) - callback.onLivingEntityJump(event); - }); - - public LivingJumpEvent(LivingEntity e) { - super(e); - } - - @Override - public void sendEvent() { - JUMP.invoker().onLivingEntityJump(this); - } - } - - public static class LivingVisibilityEvent extends LivingEntityEvents { - public static final Event VISIBILITY = EventFactory.createArrayBacked(NewVisibility.class, callbacks -> event -> { - for (NewVisibility e : callbacks) - e.getEntityVisibilityMultiplier(event); - }); - private double visibilityModifier; - @Nullable - private final Entity lookingEntity; - - public LivingVisibilityEvent(LivingEntity livingEntity, @Nullable Entity lookingEntity, double originalMultiplier) { - super(livingEntity); - this.visibilityModifier = originalMultiplier; - this.lookingEntity = lookingEntity; - } - - /** - * @param mod Is multiplied with the current modifier - */ - public void modifyVisibility(double mod) { - visibilityModifier *= mod; - } - - /** - * @return The current modifier - */ - public double getVisibilityModifier() { - return visibilityModifier; - } - - /** - * @return The entity trying to see this LivingEntity, if available - */ - @Nullable - public Entity getLookingEntity() { - return lookingEntity; - } - - @Override - public void sendEvent() { - VISIBILITY.invoker().getEntityVisibilityMultiplier(this); - } - } - - @FunctionalInterface - public interface EquipmentChange { - void onEquipmentChange(LivingEntity entity, EquipmentSlot slot, @Nonnull ItemStack from, @Nonnull ItemStack to); - } - - @FunctionalInterface - public interface Attack { - boolean onAttack(LivingEntity entity, DamageSource source, float amount); - } - - @FunctionalInterface - public interface Hurt { - float onHurt(DamageSource source, float amount); - } - - @FunctionalInterface - public interface ActuallyHurt { - float onHurt(DamageSource source, LivingEntity damaged, float amount); - } - - @FunctionalInterface - public interface CheckSpawn { - boolean onCheckSpawn(Mob entity, LevelAccessor world, double x, double y, double z, @Nullable BaseSpawner spawner, MobSpawnType spawnReason); - } - - @FunctionalInterface - public interface Fall { - void onFall(FallEvent event); - - final class FallEvent extends EntityEvents { - private final DamageSource source; - private float distance, damageMultiplier; - - public FallEvent(LivingEntity entity, DamageSource source, float distance, float damageMultiplier) { - super(entity); - this.source = source; - this.distance = distance; - this.damageMultiplier = damageMultiplier; - } - - @Override - public void sendEvent() { - FALL.invoker().onFall(this); - } - - public DamageSource getSource() { - return source; - } - - public float getDistance() { - return distance; - } - - public float getDamageMultiplier() { - return damageMultiplier; - } - - public void setDamageMultiplier(float damageMultiplier) { - this.damageMultiplier = damageMultiplier; - } - - public void setDistance(float distance) { - this.distance = distance; - } - } - } - - @FunctionalInterface - public interface ExperienceDrop { - int onLivingEntityExperienceDrop(int i, Player attackingPlayer, LivingEntity entity); - } - - @FunctionalInterface - public interface KnockBackStrength { - double onLivingEntityTakeKnockback(double strength, Player player); - } - - @FunctionalInterface - public interface Drops { - boolean onLivingEntityDrops(LivingEntity target, DamageSource source, Collection drops, int lootingLevel, boolean recentlyHit); - } - - @FunctionalInterface - public interface LootingLevel { - int modifyLootingLevel(DamageSource source, LivingEntity target, int currentLevel, boolean recentlyHit); - } - - @FunctionalInterface - public interface Tick { - void onLivingEntityTick(LivingEntity entity); - } - - @FunctionalInterface - public interface Jump { - void onLivingEntityJump(LivingEntity entity); - } - - @FunctionalInterface - public interface NewTick { - void onLivingTick(LivingTickEvent event); - } - - @FunctionalInterface - public interface NewJump { - void onLivingEntityJump(LivingJumpEvent event); - } - - @FunctionalInterface - public interface Visibility { - double getEntityVisibilityMultiplier(LivingEntity entity, Entity lookingEntity, double originalMultiplier); - } - - @FunctionalInterface - public interface NewVisibility { - void getEntityVisibilityMultiplier(LivingVisibilityEvent event); - } - - @FunctionalInterface - public interface ChangeTarget { - void onChangeTarget(ChangeTargetEvent event); - - final class ChangeTargetEvent extends EntityEvents { - private final LivingTargetType targetType; - private final LivingEntity originalTarget; - private LivingEntity newTarget; - - public ChangeTargetEvent(LivingEntity entity, LivingEntity originalTarget, LivingTargetType targetType) { - super(entity); - this.originalTarget = originalTarget; - this.newTarget = originalTarget; - this.targetType = targetType; - } - - @Override - public void sendEvent() { - CHANGE_TARGET.invoker().onChangeTarget(this); - } - - public LivingEntity getNewTarget() { return newTarget; } - public void setNewTarget(LivingEntity newTarget) { this.newTarget = newTarget; } - public LivingTargetType getTargetType() { return targetType; } - public LivingEntity getOriginalTarget() { return originalTarget; } - - public enum LivingTargetType { MOB_TARGET, BEHAVIOR_TARGET } - } - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityUseItemEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityUseItemEvents.java deleted file mode 100644 index a916a7cd4..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingEntityUseItemEvents.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import javax.annotation.Nonnull; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; - -public interface LivingEntityUseItemEvents { - - Event LIVING_USE_ITEM_FINISH = EventFactory.createArrayBacked(LivingUseItemFinish.class, callbacks -> (entity, item, duration, result) -> { - for(LivingUseItemFinish e : callbacks) { - ItemStack itemStack = e.onUseItem(entity, item, duration, result); - if(itemStack != null) - return itemStack; - } - return null; - }); - - @FunctionalInterface - interface LivingUseItemFinish { - ItemStack onUseItem(LivingEntity entity, @Nonnull ItemStack item, int duration, @Nonnull ItemStack result); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/MobEntitySetTargetCallback.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/MobEntitySetTargetCallback.java deleted file mode 100644 index 3f5a4c1c8..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/MobEntitySetTargetCallback.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.LivingEntity; - -public interface MobEntitySetTargetCallback { - Event EVENT = EventFactory.createArrayBacked(MobEntitySetTargetCallback.class, callbacks -> (targeting, target) -> { - for (MobEntitySetTargetCallback callback : callbacks) { - callback.onMobEntitySetTarget(targeting, target); - } - }); - - void onMobEntitySetTarget(LivingEntity targeting, LivingEntity target); -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerEvents.java deleted file mode 100644 index 3da6467e4..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerEvents.java +++ /dev/null @@ -1,161 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.ExperienceOrb; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class PlayerEvents extends LivingEntityEvents { - - public static final Event BREAK_SPEED = EventFactory.createArrayBacked(PlayerBreakSpeed.class, callbacks -> event -> { - for(PlayerBreakSpeed e : callbacks) - e.setBreakSpeed(event); - }); - - public static final Event PICKUP_XP = EventFactory.createArrayBacked(PlayerXpPickUp.class, callbacks -> event -> { - for (PlayerXpPickUp e : callbacks) - e.onPlayerPicksUpXp(event); - }); - - public static final Event XP_CHANGE = EventFactory.createArrayBacked(PlayerXpChange.class, callbacks -> event -> { - for (PlayerXpChange e : callbacks) - e.onPlayerXpChange(event); - }); - - public static final Event LOGGED_IN = EventFactory.createArrayBacked(PlayerLoggedInOrOut.class, callbacks -> player -> { - for (PlayerLoggedInOrOut e : callbacks) - e.handleConnection(player); - }); - - public static final Event LOGGED_OUT = EventFactory.createArrayBacked(PlayerLoggedInOrOut.class, callbacks -> player -> { - for (PlayerLoggedInOrOut e : callbacks) - e.handleConnection(player); - }); - - private final Player entityPlayer; - - public PlayerEvents(Player player) { - super(player); - entityPlayer = player; - } - - /** - * @return Player - */ - public Player getPlayer() { - return entityPlayer; - } - - @Override - public Player getEntity() { - return entityPlayer; - } - - public static class PickupXp extends PlayerEvents { - - private final ExperienceOrb orb; - - public PickupXp(Player player, ExperienceOrb orb) { - super(player); - this.orb = orb; - } - - public ExperienceOrb getOrb() { - return orb; - } - - @Override - public void sendEvent() { - PICKUP_XP.invoker().onPlayerPicksUpXp(this); - } - } - - public static class XpChange extends PlayerEvents { - private int amount; - - public XpChange(Player player, int amount) { - super(player); - this.amount = amount; - } - - public int getAmount() { - return this.amount; - } - - public void setAmount(int amount) { - this.amount = amount; - } - - @Override - public void sendEvent() { - XP_CHANGE.invoker().onPlayerXpChange(this); - } - } - - /** - * BreakSpeed is fired when a player attempts to harvest a block.
- * This event is fired whenever a player attempts to harvest a block in - * {@link Player#getDigSpeed(BlockState, BlockPos)}.
- *
- * {@link #state} contains the block being broken.
- * {@link #originalSpeed} contains the original speed at which the player broke the block.
- * {@link #newSpeed} contains the newSpeed at which the player will break the block.
- * {@link #pos} contains the coordinates at which this event is occurring. Optional value.
- *
- * This event is cancelable.
- * If it is canceled, the player is unable to break the block.
- *
- * This event does not have a result.
- *
- **/ - public static class BreakSpeed extends PlayerEvents { - private final BlockState state; - private final float originalSpeed; - private float newSpeed = 0.0f; - private final BlockPos pos; // Y position of -1 notes unknown location - - public BreakSpeed(Player player, BlockState state, float original, BlockPos pos) { - super(player); - this.state = state; - this.originalSpeed = original; - this.setNewSpeed(original); - this.pos = pos != null ? pos : new BlockPos(0, -1, 0); - } - - public BlockState getState() { return state; } - public float getOriginalSpeed() { return originalSpeed; } - public float getNewSpeed() { return newSpeed; } - public void setNewSpeed(float newSpeed) { this.newSpeed = newSpeed; } - public BlockPos getPos() { return pos; } - - @Override - public void sendEvent() { - BREAK_SPEED.invoker().setBreakSpeed(this); - } - } - - @FunctionalInterface - public interface PlayerBreakSpeed { - void setBreakSpeed(BreakSpeed event); - } - - @FunctionalInterface - public interface PlayerXpChange { - void onPlayerXpChange(XpChange event); - } - - @FunctionalInterface - public interface PlayerXpPickUp { - void onPlayerPicksUpXp(PickupXp event); - } - - /** - * Use this interface to handle players logging in and out. - */ - @FunctionalInterface - public interface PlayerLoggedInOrOut { - void handleConnection(Player player); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerInteractionEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerInteractionEvents.java deleted file mode 100644 index c7af910e1..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerInteractionEvents.java +++ /dev/null @@ -1,193 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import com.google.common.base.Preconditions; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.fabricmc.fabric.api.event.player.AttackBlockCallback; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public abstract class PlayerInteractionEvents extends PlayerEvents { - /** - * This event is fired when a player left clicks while targeting a block. - * This event controls which of {@link Block#attack(BlockState, Level, BlockPos, Player)} and/or the item harvesting methods will be called - * Canceling the event will cause none of the above noted methods to be called. - * There are various results to this event, see the getters below. - *

- * Note that if the event is canceled and the player holds down left mouse, the event will continue to fire. - * This is due to how vanilla calls the left click handler methods. - *

- * Also note that creative mode directly breaks the block without running any other logic. - * Therefore, in creative mode, {@link #setUseBlock} and {@link #setUseItem} have no effect. - *

- * This event is fired after {@link AttackBlockCallback}. - * This event will not fire if {@link AttackBlockCallback} is canceled. - * Developers should use the fabric version of this event, and only use this event when needed. - */ - public static final Event LEFT_CLICK_BLOCK = EventFactory.createArrayBacked(PlayerLeftClickBlock.class, callbacks -> (event -> { - for(PlayerLeftClickBlock e : callbacks) - e.onLeftClickBlock(event); - })); - - /** - * This event is fired on the client side when the player left clicks empty space with any ItemStack. - * The server is not aware of when the client left clicks empty space, you will need to tell the server yourself. - * This event cannot be canceled. - */ - public static final Event LEFT_CLICK_EMPTY = EventFactory.createArrayBacked(PlayerLeftClickEmpty.class, callbacks -> (event -> { - for(PlayerLeftClickEmpty e : callbacks) - e.onLeftClickEmpty(event); - })); - - private final InteractionHand hand; - private final BlockPos pos; - @Nullable - private final Direction face; - private InteractionResult cancellationResult = InteractionResult.PASS; - - private PlayerInteractionEvents(Player player, InteractionHand hand, BlockPos pos, @Nullable Direction face) { - super(Preconditions.checkNotNull(player, "Null player in PlayerInteractEvent!")); - this.hand = Preconditions.checkNotNull(hand, "Null hand in PlayerInteractEvent!"); - this.pos = Preconditions.checkNotNull(pos, "Null position in PlayerInteractEvent!"); - this.face = face; - } - - public static class LeftClickBlock extends PlayerInteractionEvents { - private Result useBlock = Result.DEFAULT; - private Result useItem = Result.DEFAULT; - - public LeftClickBlock(Player player, BlockPos pos, Direction face) { - super(player, InteractionHand.MAIN_HAND, pos, face); - } - - /** - * @return If {@link Block#attack(BlockState, Level, BlockPos, Player)} should be called. Changing this has no effect in creative mode - */ - public Result getUseBlock() { - return useBlock; - } - - /** - * @return If the block should be attempted to be mined with the current item. Changing this has no effect in creative mode - */ - public Result getUseItem() { - return useItem; - } - - public void setUseBlock(Result triggerBlock) { - this.useBlock = triggerBlock; - } - - public void setUseItem(Result triggerItem) { - this.useItem = triggerItem; - } - - @Override - public void setCanceled(boolean canceled) { - super.setCanceled(canceled); - if (canceled) { - useBlock = Result.DENY; - useItem = Result.DENY; - } - } - @Override - public void sendEvent() { - LEFT_CLICK_BLOCK.invoker().onLeftClickBlock(this); - } - } - - public static class LeftClickEmpty extends PlayerInteractionEvents { - - public LeftClickEmpty(Player player) { - super(player, InteractionHand.MAIN_HAND, player.blockPosition(), null); - } - - @Override - public void sendEvent() { - LEFT_CLICK_EMPTY.invoker().onLeftClickEmpty(this); - } - } - - /** - * @return The hand involved in this interaction. Will never be null. - */ - @NotNull - public InteractionHand getHand() { - return hand; - } - - /** - * @return The itemstack involved in this interaction, {@code ItemStack.EMPTY} if the hand was empty. - */ - @NotNull - public ItemStack getItemStack() { - return getEntity().getItemInHand(hand); - } - - /** - * If the interaction was on an entity, will be a BlockPos centered on the entity. - * If the interaction was on a block, will be the position of that block. - * Otherwise, will be a BlockPos centered on the player. - * Will never be null. - * @return The position involved in this interaction. - */ - @NotNull - public BlockPos getPos() { - return pos; - } - - /** - * @return The face involved in this interaction. For all non-block interactions, this will return null. - */ - @Nullable - public Direction getFace() { - return face; - } - - /** - * @return Convenience method to get the level of this interaction. - */ - public Level getLevel() { - return getEntity().level(); - } - - /** - * @return The InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant - * method of the event. By default, this is {@link InteractionResult#PASS}, meaning cancelled events will cause - * the client to keep trying more interactions until something works. - */ - public InteractionResult getCancellationResult() { - return cancellationResult; - } - - /** - * Set the InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant - * method of the event. - * Note that this only has an effect on {@link RightClickBlock}, {@link RightClickItem}, {@link EntityInteract}, and {@link EntityInteractSpecific}. - */ - public void setCancellationResult(InteractionResult result) { - this.cancellationResult = result; - } - - @FunctionalInterface - public interface PlayerLeftClickBlock { - void onLeftClickBlock(LeftClickBlock event); - } - - @FunctionalInterface - public interface PlayerLeftClickEmpty { - void onLeftClickEmpty(LeftClickEmpty event); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerTickEvents.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerTickEvents.java deleted file mode 100644 index 259eb4bb3..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/PlayerTickEvents.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.player.Player; - -public class PlayerTickEvents { - public static final Event START = EventFactory.createArrayBacked(Start.class, callbacks -> (player) -> { - for (Start callback : callbacks) { - callback.onStartOfPlayerTick(player); - } - }); - - public static final Event END = EventFactory.createArrayBacked(End.class, callbacks -> (player) -> { - for (End callback : callbacks) { - callback.onEndOfPlayerTick(player); - } - }); - - @FunctionalInterface - public interface End { - void onEndOfPlayerTick(Player player); - } - - @FunctionalInterface - public interface Start { - void onStartOfPlayerTick(Player player); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactCallback.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactCallback.java deleted file mode 100644 index 2ea994b9c..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactCallback.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.phys.HitResult; - -/** - * Will be removed in 1.20.2+ - * Use {@link ProjectileImpactEvent} instead. - */ -@Deprecated(forRemoval = true) -public interface ProjectileImpactCallback { - Event EVENT = EventFactory.createArrayBacked(ProjectileImpactCallback.class, callbacks -> (proj, hit) -> { - for (ProjectileImpactCallback callback : callbacks) { - if (callback.onImpact(proj, hit)) return true; - } - return false; - }); - - boolean onImpact(Projectile projectile, HitResult hitResult); -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactEvent.java index 990bedfa9..6b85085a2 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ProjectileImpactEvent.java @@ -1,25 +1,31 @@ package io.github.fabricators_of_create.porting_lib.entity.events; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.phys.HitResult; -import org.jetbrains.annotations.NotNull; - import java.util.Objects; /** * This event is fired when a projectile entity impacts something.
+ * This event is fired via {@link EntityHooks#onProjectileImpact(Projectile, HitResult)} * This event is fired for all vanilla projectiles by Porting Lib, * custom projectiles should fire this event and check the result in a similar fashion. * This event is cancelable. When canceled, the impact will not be processed and the projectile will continue flying. * Killing or other handling of the entity after event cancellation is up to the modder. */ -public class ProjectileImpactEvent extends EntityEvents { +public class ProjectileImpactEvent extends EntityEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onImpact(event); + }); + private final HitResult ray; private final Projectile projectile; - private ImpactResult result = ImpactResult.DEFAULT; - public ProjectileImpactEvent(Projectile projectile, HitResult ray) { super(projectile); this.ray = ray; @@ -34,43 +40,12 @@ public Projectile getProjectile() { return projectile; } - /** - * This method only exists in lex forge and is here for compatibility - */ - @Deprecated() - public void setImpactResult(ImpactResult result) { - this.result = Objects.requireNonNull(result); - } - - /** - * This method only exists in lex forge and is here for compatibility - */ - @Deprecated() - public ImpactResult getImpactResult() { - return this.isCanceled() ? ImpactResult.SKIP_ENTITY : result; - } - @Override public void sendEvent() { - PROJECTILE_IMPACT.invoker().onProjectileImpact(this); + EVENT.invoker().onImpact(this); } - public enum ImpactResult { - /** - * The default behaviour, the projectile will be destroyed and the hit will be processed. - */ - DEFAULT, - /** - * The projectile will pass through the current entity as if it wasn't there. This will return default behaviour if there is no entity. - */ - SKIP_ENTITY, - /** - * Damage the entity and stop the projectile here, the projectile will not pierce. - */ - STOP_AT_CURRENT, - /** - * Cancel the piercing aspect of the projectile, and do not damage the entity. - */ - STOP_AT_CURRENT_NO_DAMAGE + public interface Callback { + void onImpact(ProjectileImpactEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingAttackEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingAttackEvent.java similarity index 64% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingAttackEvent.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingAttackEvent.java index 6893f90fa..0b63dcff8 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingAttackEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingAttackEvent.java @@ -1,10 +1,12 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; +package io.github.fabricators_of_create.porting_lib.entity.events.living; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; /** * LivingAttackEvent is fired when a living Entity is attacked.
@@ -12,20 +14,20 @@ * {@link LivingEntity#hurt(DamageSource, float)} and * {@link Player#hurt(DamageSource, float)}.
*
+ * This event is fired via the {@link EntityHooks#onLivingAttack(LivingEntity, DamageSource, float)}.
+ *
* {@link #source} contains the DamageSource of the attack.
* {@link #amount} contains the amount of damage dealt to the entity.
*
- * This event is cancelable.
+ * This event is {@link CancellableEvent}.
* If this event is canceled, the Entity does not take attack damage.
- *
- * This event does not have a result.
- *
**/ -public class LivingAttackEvent extends LivingEntityEvents { - public static final Event ATTACK = EventFactory.createArrayBacked(LivingAttackCallback.class, callbacks -> event -> { - for (LivingAttackCallback e : callbacks) - e.onLivingAttack(event); +public class LivingAttackEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onLivingAttack(event); }); + private final DamageSource source; private final float amount; @@ -45,11 +47,10 @@ public float getAmount() { @Override public void sendEvent() { - ATTACK.invoker().onLivingAttack(this); + EVENT.invoker().onLivingAttack(this); } - @FunctionalInterface - public interface LivingAttackCallback { + public interface Callback { void onLivingAttack(LivingAttackEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingChangeTargetEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingChangeTargetEvent.java new file mode 100644 index 000000000..bd0df322e --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingChangeTargetEvent.java @@ -0,0 +1,113 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.behavior.StartAttacking; + +import org.jetbrains.annotations.ApiStatus; + +/** + * This event allows you to change the target an entity has.
+ *
+ * This event is fired via the {@link EntityHooks#onLivingChangeTarget(LivingEntity, LivingEntity, ILivingTargetType)}
+ *
+ * {@link #getOriginalTarget()} returns the target that should originally be set. + * The return value cannot be affected by calling {@link #setNewTarget(LivingEntity)}.
+ * {@link #getNewTarget()} returns the new target that this entity will have. + * The return value can be affected by calling {@link #setNewTarget(LivingEntity)}.
+ * {@link #getTargetType()} returns the target type that caused the change of targets.
+ *
+ * This event is {@link CancellableEvent}.
+ *
+ * If you cancel this event, the target will not be changed and it will stay the same. + */ +public class LivingChangeTargetEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLivingChangeTarget(event); + }); + + private final ILivingTargetType targetType; + private final LivingEntity originalTarget; + private LivingEntity newTarget; + private boolean changedTarget = false; + + public LivingChangeTargetEvent(LivingEntity entity, LivingEntity originalTarget, ILivingTargetType targetType) { + super(entity); + this.originalTarget = originalTarget; + this.newTarget = originalTarget; + this.targetType = targetType; + } + + /** + * {@return the new target of this entity.} + */ + public LivingEntity getNewTarget() { + return newTarget; + } + + /** + * Sets the new target this entity shall have. + * + * @param newTarget The new target of this entity. + */ + public void setNewTarget(LivingEntity newTarget) { + this.newTarget = newTarget; + this.changedTarget = true; + } + + /** + * {@return the living target type.} + */ + public ILivingTargetType getTargetType() { + return targetType; + } + + /** + * {@return the original entity MC intended to use as a target before firing this event.} + */ + public LivingEntity getOriginalTarget() { + return originalTarget; + } + + @ApiStatus.Internal + public boolean changedTarget() { + return this.changedTarget; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingChangeTarget(this); + } + + /** + * A living target type indicates what kind of system caused a change of + * targets. For a list of default target types, take a look at + * {@link LivingTargetType}. + */ + public static interface ILivingTargetType { + + } + + /** + * This enum contains two default living target types. + */ + public static enum LivingTargetType implements ILivingTargetType { + /** + * This target type indicates that the target has been set by calling {@link Mob#setTarget(LivingEntity)}. + */ + MOB_TARGET, + /** + * This target type indicates that the target has been set by the {@link StartAttacking} behavior. + */ + BEHAVIOR_TARGET; + } + + public interface Callback { + void onLivingChangeTarget(LivingChangeTargetEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDamageEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDamageEvent.java index 82100cc33..beaf10474 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDamageEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDamageEvent.java @@ -1,6 +1,5 @@ package io.github.fabricators_of_create.porting_lib.entity.events.living; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.damagesource.DamageSource; @@ -24,7 +23,7 @@ * * @see LivingHurtEvent **/ -public class LivingDamageEvent extends LivingEntityEvents { +public class LivingDamageEvent extends LivingEvent { public static final Event DAMAGE = EventFactory.createArrayBacked(DamageCallback.class, callbacks -> event -> { for (DamageCallback e : callbacks) e.onLivingDamage(event); diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingDeathEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDeathEvent.java similarity index 75% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingDeathEvent.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDeathEvent.java index 787d4a0c8..e031d5a87 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/LivingDeathEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDeathEvent.java @@ -1,5 +1,6 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; +package io.github.fabricators_of_create.porting_lib.entity.events.living; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.server.level.ServerPlayer; @@ -18,18 +19,19 @@ *
* {@link #source} contains the DamageSource that caused the entity to die.
*
- * This event is cancelable.
+ * This event is {@link CancellableEvent}.
* If this event is canceled, the Entity does not die.
*
* This event does not have a result.
*
**/ @Deprecated -public class LivingDeathEvent extends LivingEntityEvents { - public static final Event DEATH = EventFactory.createArrayBacked(Death.class, callbacks -> event -> { - for (Death e : callbacks) +public class LivingDeathEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback e : callbacks) e.onLivingDeath(event); }); + private final DamageSource source; public LivingDeathEvent(LivingEntity entity, DamageSource source) { @@ -43,11 +45,11 @@ public DamageSource getSource() { @Override public void sendEvent() { - DEATH.invoker().onLivingDeath(this); + EVENT.invoker().onLivingDeath(this); } @FunctionalInterface - public interface Death { + public interface Callback { void onLivingDeath(LivingDeathEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDropsEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDropsEvent.java new file mode 100644 index 000000000..4989cd124 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingDropsEvent.java @@ -0,0 +1,64 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import java.util.Collection; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; + +/** + * LivingDropsEvent is fired when an Entity's death causes dropped items to appear.
+ * This event is fired whenever an Entity dies and drops items in + * {@link LivingEntity#die(DamageSource)}.
+ *
+ * This event is fired via the {@link EntityHooks#onLivingDrops(LivingEntity, DamageSource, Collection, boolean)} .
+ *
+ * {@link #source} contains the DamageSource that caused the drop to occur.
+ * {@link #drops} contains the ArrayList of EntityItems that will be dropped.
+ * {@link #recentlyHit} determines whether the Entity doing the drop has recently been damaged.
+ *
+ * This event is {@link CancellableEvent}.
+ * If this event is canceled, the Entity does not drop anything.
+ **/ +public class LivingDropsEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLivingDrop(event); + }); + + private final DamageSource source; + private final Collection drops; + private final boolean recentlyHit; + + public LivingDropsEvent(LivingEntity entity, DamageSource source, Collection drops, boolean recentlyHit) { + super(entity); + this.source = source; + this.drops = drops; + this.recentlyHit = recentlyHit; + } + + public DamageSource getSource() { + return source; + } + + public Collection getDrops() { + return drops; + } + + public boolean isRecentlyHit() { + return recentlyHit; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingDrop(this); + } + + public interface Callback { + void onLivingDrop(LivingDropsEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEntityUseItemEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEntityUseItemEvent.java new file mode 100644 index 000000000..6ebe7be96 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEntityUseItemEvent.java @@ -0,0 +1,162 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; + +public abstract class LivingEntityUseItemEvent extends LivingEvent { + private final ItemStack item; + private int duration; + + private LivingEntityUseItemEvent(LivingEntity entity, ItemStack item, int duration) { + super(entity); + this.item = item; + this.setDuration(duration); + } + + public ItemStack getItem() { + return item; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + /** + * Fired when a player starts 'using' an item, typically when they hold right mouse. + * Examples: + * Drawing a bow + * Eating Food + * Drinking Potions/Milk + * Guarding with a sword + * + * Cancel the event, or set the duration or {@literal <=} 0 to prevent it from processing. + * + */ + public static class Start extends LivingEntityUseItemEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onStartUsingItem(event); + }); + + public Start(LivingEntity entity, ItemStack item, int duration) { + super(entity, item, duration); + } + + @Override + public void sendEvent() { + EVENT.invoker().onStartUsingItem(this); + } + + public interface Callback { + void onStartUsingItem(Start event); + } + } + + /** + * Fired every tick that a player is 'using' an item, see {@link Start} for info. + * + * Cancel the event, or set the duration to {@literal <=} 0 to cause the player to stop using the item. + * + */ + public static class Tick extends LivingEntityUseItemEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onUsingTick(event); + }); + + public Tick(LivingEntity entity, ItemStack item, int duration) { + super(entity, item, duration); + } + + @Override + public void sendEvent() { + EVENT.invoker().onUsingTick(this); + } + + public interface Callback { + void onUsingTick(Tick event); + } + } + + /** + * Fired when a player stops using an item without the use duration timing out. + * Example: + * Stop eating 1/2 way through + * Stop defending with sword + * Stop drawing bow. This case would fire the arrow + * + * Duration on this event is how long the item had left in it's count down before 'finishing' + * + * Canceling this event will prevent the Item from being notified that it has stopped being used, + * The only vanilla item this would effect are bows, and it would cause them NOT to fire there arrow. + */ + public static class Stop extends LivingEntityUseItemEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onStopUsingItem(event); + }); + + public Stop(LivingEntity entity, ItemStack item, int duration) { + super(entity, item, duration); + } + + @Override + public void sendEvent() { + EVENT.invoker().onStopUsingItem(this); + } + + public interface Callback { + void onStopUsingItem(Stop event); + } + } + + /** + * Fired after an item has fully finished being used. + * The item has been notified that it was used, and the item/result stacks reflect after that state. + * This means that when this is fired for a Potion, the potion effect has already been applied. + * + * {@link LivingEntityUseItemEvent#item} is a copy of the item BEFORE it was used. + * + * If you wish to cancel those effects, you should cancel one of the above events. + * + * The result item stack is the stack that is placed in the player's inventory in replacement of the stack that is currently being used. + * + */ + public static class Finish extends LivingEntityUseItemEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onFinishUsingItem(event); + }); + + private ItemStack result; + + public Finish(LivingEntity entity, ItemStack item, int duration, ItemStack result) { + super(entity, item, duration); + this.setResultStack(result); + } + + public ItemStack getResultStack() { + return result; + } + + public void setResultStack(ItemStack result) { + this.result = result; + } + + @Override + public void sendEvent() { + EVENT.invoker().onFinishUsingItem(this); + } + + public interface Callback { + void onFinishUsingItem(Finish event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEvent.java new file mode 100644 index 000000000..f72863a10 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingEvent.java @@ -0,0 +1,109 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import javax.annotation.Nullable; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +/** + * LivingEvent is fired whenever an event involving a {@link LivingEntity} occurs.
+ * If a method utilizes this {@link Event} as its parameter, the method will + * receive every child event of this class.
+ *
+ **/ +public abstract class LivingEvent extends EntityEvent { + private final LivingEntity livingEntity; + + public LivingEvent(LivingEntity entity) { + super(entity); + livingEntity = entity; + } + + @Override + public LivingEntity getEntity() { + return livingEntity; + } + + /** + * LivingJumpEvent is fired when an Entity jumps.
+ * This event is fired whenever an Entity jumps in + * {@code LivingEntity#jumpFromGround()}, {@code MagmaCube#jumpFromGround()}, + * {@code Slime#jumpFromGround()}, {@code Camel#executeRidersJump()}, + * and {@code AbstractHorse#executeRidersJump()}.
+ *
+ * This event is fired via the {@link EntityHooks#onLivingJump(LivingEntity)}.
+ *
+ * This event is not {@link CancellableEvent}.
+ **/ + public static class LivingJumpEvent extends LivingEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> (event) -> { + for (Callback callback : callbacks) + callback.onLivingEntityJump(event); + }); + + public LivingJumpEvent(LivingEntity e) { + super(e); + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingEntityJump(this); + } + + public interface Callback { + void onLivingEntityJump(LivingJumpEvent event); + } + } + + public static class LivingVisibilityEvent extends LivingEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback e : callbacks) + e.onLivingVisibility(event); + }); + private double visibilityModifier; + @Nullable + private final Entity lookingEntity; + + public LivingVisibilityEvent(LivingEntity livingEntity, @Nullable Entity lookingEntity, double originalMultiplier) { + super(livingEntity); + this.visibilityModifier = originalMultiplier; + this.lookingEntity = lookingEntity; + } + + /** + * @param mod Is multiplied with the current modifier + */ + public void modifyVisibility(double mod) { + visibilityModifier *= mod; + } + + /** + * @return The current modifier + */ + public double getVisibilityModifier() { + return visibilityModifier; + } + + /** + * @return The entity trying to see this LivingEntity, if available + */ + @Nullable + public Entity getLookingEntity() { + return lookingEntity; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingVisibility(this); + } + + public interface Callback { + void onLivingVisibility(LivingVisibilityEvent event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingExperienceDropEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingExperienceDropEvent.java new file mode 100644 index 000000000..6a914685d --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingExperienceDropEvent.java @@ -0,0 +1,62 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Nullable; + +/** + * Event for when an entity drops experience on its death, can be used to change + * the amount of experience points dropped or completely prevent dropping of experience + * by canceling the event. + */ +public class LivingExperienceDropEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onDropExperience(event); + }); + + @Nullable + private final Player attackingPlayer; + private final int originalExperiencePoints; + + private int droppedExperiencePoints; + + public LivingExperienceDropEvent(LivingEntity entity, @Nullable Player attackingPlayer, int originalExperience) { + super(entity); + + this.attackingPlayer = attackingPlayer; + this.originalExperiencePoints = this.droppedExperiencePoints = originalExperience; + } + + public int getDroppedExperience() { + return droppedExperiencePoints; + } + + public void setDroppedExperience(int droppedExperience) { + this.droppedExperiencePoints = droppedExperience; + } + + /** + * @return The player that last attacked the entity and thus caused the experience. This can be null, in case the player has since logged out. + */ + @Nullable + public Player getAttackingPlayer() { + return attackingPlayer; + } + + public int getOriginalExperience() { + return originalExperiencePoints; + } + + @Override + public void sendEvent() { + EVENT.invoker().onDropExperience(this); + } + + public interface Callback { + void onDropExperience(LivingExperienceDropEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingFallEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingFallEvent.java new file mode 100644 index 000000000..d929ddb76 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingFallEvent.java @@ -0,0 +1,62 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; + +/** + * LivingFallEvent is fired when an Entity is set to be falling.
+ * This event is fired whenever an Entity is set to fall in + * {@link LivingEntity#causeFallDamage(float, float, DamageSource)}.
+ *
+ * This event is fired via the {@link EntityHooks#onLivingFall(LivingEntity, float, float)}.
+ *
+ * {@link #distance} contains the distance the Entity is to fall. If this event is canceled, this value is set to 0.0F. + *
+ * This event is {@link CancellableEvent}.
+ * If this event is canceled, the Entity does not fall.
+ *
+ **/ +public class LivingFallEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLivingFall(event); + }); + + private float distance; + private float damageMultiplier; + + public LivingFallEvent(LivingEntity entity, float distance, float damageMultiplier) { + super(entity); + this.setDistance(distance); + this.setDamageMultiplier(damageMultiplier); + } + + public float getDistance() { + return distance; + } + + public void setDistance(float distance) { + this.distance = distance; + } + + public float getDamageMultiplier() { + return damageMultiplier; + } + + public void setDamageMultiplier(float damageMultiplier) { + this.damageMultiplier = damageMultiplier; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingFall(this); + } + + public interface Callback { + void onLivingFall(LivingFallEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingHurtEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingHurtEvent.java index 42e121ca2..5d168a966 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingHurtEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingHurtEvent.java @@ -1,6 +1,7 @@ package io.github.fabricators_of_create.porting_lib.entity.events.living; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.damagesource.DamageSource; @@ -12,22 +13,22 @@ * {@code LivingEntity#actuallyHurt(DamageSource, float)} and * {@code Player#actuallyHurt(DamageSource, float)}.
*
+ * This event is fired via the {@link EntityHooks#onLivingHurt(LivingEntity, DamageSource, float)}.
+ *
* {@link #source} contains the DamageSource that caused this Entity to be hurt.
* {@link #amount} contains the amount of damage dealt to the Entity that was hurt.
*
- * This event is cancelable.
+ * This event is {@link CancellableEvent}.
* If this event is canceled, the Entity is not hurt.
- *
- * This event does not have a result.
- *
* * @see LivingDamageEvent **/ -public class LivingHurtEvent extends LivingEntityEvents { - public static final Event HURT = EventFactory.createArrayBacked(HurtCallback.class, callbacks -> event -> { - for (HurtCallback e : callbacks) - e.onLivingHurt(event); +public class LivingHurtEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLivingHurt(event); }); + private final DamageSource source; private float amount; @@ -51,11 +52,10 @@ public void setAmount(float amount) { @Override public void sendEvent() { - HURT.invoker().onLivingHurt(this); + EVENT.invoker().onLivingHurt(this); } - @FunctionalInterface - public interface HurtCallback { + public interface Callback { void onLivingHurt(LivingHurtEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingKnockBackEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingKnockBackEvent.java new file mode 100644 index 000000000..fbde544a4 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingKnockBackEvent.java @@ -0,0 +1,92 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.player.Player; + +/** + * LivingKnockBackEvent is fired when a living entity is about to be knocked back.
+ * This event is fired whenever an Entity is knocked back in + * {@link LivingEntity#hurt(DamageSource, float)}, + * {@code LivingEntity#blockUsingShield(LivingEntity)}, + * {@link Mob#doHurtTarget(Entity)} and + * {@link Player#attack(Entity)}
+ *
+ * This event is fired via {@link EntityHooks#onLivingKnockBack(LivingEntity, float, double, double)} .
+ *
+ * {@link #strength} contains the strength of the knock back.
+ * {@link #ratioX} contains the x ratio of the knock back.
+ * {@link #ratioZ} contains the z ratio of the knock back.
+ *
+ * This event is {@link CancellableEvent}.
+ * If this event is canceled, the entity is not knocked back.
+ **/ +public class LivingKnockBackEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLivingKnockBack(event); + }); + + protected float strength; + protected double ratioX, ratioZ; + protected final float originalStrength; + protected final double originalRatioX, originalRatioZ; + + public LivingKnockBackEvent(LivingEntity target, float strength, double ratioX, double ratioZ) { + super(target); + this.strength = this.originalStrength = strength; + this.ratioX = this.originalRatioX = ratioX; + this.ratioZ = this.originalRatioZ = ratioZ; + } + + public float getStrength() { + return this.strength; + } + + public double getRatioX() { + return this.ratioX; + } + + public double getRatioZ() { + return this.ratioZ; + } + + public float getOriginalStrength() { + return this.originalStrength; + } + + public double getOriginalRatioX() { + return this.originalRatioX; + } + + public double getOriginalRatioZ() { + return this.originalRatioZ; + } + + public void setStrength(float strength) { + this.strength = strength; + } + + public void setRatioX(double ratioX) { + this.ratioX = ratioX; + } + + public void setRatioZ(double ratioZ) { + this.ratioZ = ratioZ; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLivingKnockBack(this); + } + + public interface Callback { + void onLivingKnockBack(LivingKnockBackEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingUseTotemEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingUseTotemEvent.java new file mode 100644 index 000000000..b88525117 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/LivingUseTotemEvent.java @@ -0,0 +1,68 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.living; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; + +/** + * Fired when an Entity attempts to use a totem to prevent its death. + * + *

This event is {@linkplain CancellableEvent cancellable}. + * If this event is cancelled, the totem will not prevent the entity's death.

+ * + *

+ * This event is fired on the {@linkplain EnvType#SERVER logical server}. + *

+ */ +public class LivingUseTotemEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onUseTotem(event); + }); + + private final DamageSource source; + private final ItemStack totem; + private final InteractionHand hand; + + public LivingUseTotemEvent(LivingEntity entity, DamageSource source, ItemStack totem, InteractionHand hand) { + super(entity); + this.source = source; + this.totem = totem; + this.hand = hand; + } + + /** + * {@return the damage source that caused the entity to die} + */ + public DamageSource getSource() { + return source; + } + + /** + * {@return the totem of undying being used from the entity's inventory} + */ + public ItemStack getTotem() { + return totem; + } + + /** + * {@return the hand holding the totem} + */ + public InteractionHand getHandHolding() { + return hand; + } + + @Override + public void sendEvent() { + EVENT.invoker().onUseTotem(this); + } + + public interface Callback { + void onUseTotem(LivingUseTotemEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/MobEffectEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/MobEffectEvent.java index 43f9c0fc8..45f32da23 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/MobEffectEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/MobEffectEvent.java @@ -1,41 +1,25 @@ package io.github.fabricators_of_create.porting_lib.entity.events.living; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.core.Holder; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; - -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; /** * This event is fired when an interaction between a {@link LivingEntity} and {@link MobEffectInstance} happens. */ -public abstract class MobEffectEvent extends LivingEntityEvents { - public static final Event REMOVE = EventFactory.createArrayBacked(RemoveCallback.class, callbacks -> event -> { - for (RemoveCallback c : callbacks) - c.onEffectRemove(event); - }); - public static final Event APPLICABLE = EventFactory.createArrayBacked(ApplicableCallback.class, callbacks -> event -> { - for (ApplicableCallback c : callbacks) - c.onEffectApplicable(event); - }); - public static final Event ADDED = EventFactory.createArrayBacked(AddedCallback.class, callbacks -> event -> { - for (AddedCallback c : callbacks) - c.onEffectAdded(event); - }); - public static final Event EXPIRED = EventFactory.createArrayBacked(ExpiredCallback.class, callbacks -> event -> { - for (ExpiredCallback c : callbacks) - c.onEffectExpired(event); - }); - +public abstract class MobEffectEvent extends LivingEvent { @Nullable protected final MobEffectInstance effectInstance; - public MobEffectEvent(LivingEntity living, MobEffectInstance effectInstance) { + protected MobEffectEvent(LivingEntity living, MobEffectInstance effectInstance) { super(living); this.effectInstance = effectInstance; } @@ -47,29 +31,48 @@ public MobEffectInstance getEffectInstance() { /** * This Event is fired when a {@link MobEffect} is about to get removed from an Entity. - * This Event is cancelable. If canceled, the effect will not be removed. + * This Event is {@link CancellableEvent}. If canceled, the effect will not be removed. * This Event does not have a result. */ - public static class Remove extends MobEffectEvent { - private final MobEffect effect; + public static class Remove extends MobEffectEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onRemoveEffect(event); + }); + + private final Holder effect; + @Nullable + private final EffectCure cure; - public Remove(LivingEntity living, MobEffect effect) { + @ApiStatus.Internal + public Remove(LivingEntity living, Holder effect, @Nullable EffectCure cure) { super(living, living.getEffect(effect)); this.effect = effect; + this.cure = cure; } - public Remove(LivingEntity living, MobEffectInstance effectInstance) { + @ApiStatus.Internal + public Remove(LivingEntity living, MobEffectInstance effectInstance, @Nullable EffectCure cure) { super(living, effectInstance); this.effect = effectInstance.getEffect(); + this.cure = cure; } /** - * @return the {@link MobEffectEvent} which is being removed from the entity + * @return the {@link MobEffect} which is being removed from the entity */ - public MobEffect getEffect() { + public Holder getEffect() { return this.effect; } + /** + * {@return the {@link EffectCure} the effect is being cured by. Null if the effect is not removed due to being cured} + */ + @Nullable + public EffectCure getCure() { + return cure; + } + /** * @return the {@link MobEffectInstance}. In the remove event, this can be null if the entity does not have a {@link MobEffect} of the right type active. */ @@ -81,46 +84,111 @@ public MobEffectInstance getEffectInstance() { @Override public void sendEvent() { - REMOVE.invoker().onEffectRemove(this); + EVENT.invoker().onRemoveEffect(this); + } + + public interface Callback { + void onRemoveEffect(Remove event); } } /** * This event is fired to check if a {@link MobEffectInstance} can be applied to an entity. - * This event is not cancelable. - * This event has a result. *

- * {@link Result#ALLOW ALLOW} will apply this mob effect. - * {@link Result#DENY DENY} will not apply this mob effect. - * {@link Result#DEFAULT DEFAULT} will run vanilla logic to determine if this mob effect is applicable in {@link LivingEntity#canBeAffected}. + * It will be fired whenever {@link LivingEntity#canBeAffected(MobEffectInstance)} would be invoked. + *

+ * */ public static class Applicable extends MobEffectEvent { - public Applicable(LivingEntity living, @NotNull MobEffectInstance effectInstance) { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> effect -> { + for (final Callback callback : callbacks) + callback.onEffectApplicable(effect); + }); + + protected Result result = Result.DEFAULT; + + @ApiStatus.Internal + public Applicable(LivingEntity living, MobEffectInstance effectInstance) { super(living, effectInstance); } @Override - @NotNull public MobEffectInstance getEffectInstance() { return super.getEffectInstance(); } + /** + * Changes the result of this event. + * + * @see {@link Result} for the possible states. + */ + public void setResult(Result result) { + this.result = result; + } + + /** + * {@return the result of this event, which controls if the mob effect will be applied} + */ + public Result getResult() { + return this.result; + } + + /** + * {@return If the mob effect should be applied or not, based on the current event result} + */ + @SuppressWarnings("deprecation") // Expected as the single call site for canBeAffected + public boolean getApplicationResult() { + if (this.result == Result.APPLY) { + return true; + } + return this.result == Result.DEFAULT && this.getEntity().canBeAffected(this.getEffectInstance()); + } + @Override public void sendEvent() { - APPLICABLE.invoker().onEffectApplicable(this); + EVENT.invoker().onEffectApplicable(this); + } + + public static enum Result { + /** + * Forces the event to apply the mob effect to the target entity. + */ + APPLY, + + /** + * The result of {@link LivingEntity#canBeAffected(MobEffectInstance)} will be used to determine if the mob effect will be applied. + * + * @see {@link Post#wasClickHandled()} + */ + DEFAULT, + + /** + * Forces the event to not apply the mob effect. + */ + DO_NOT_APPLY; + } + + public interface Callback { + void onEffectApplicable(Applicable event); } } /** * This event is fired when a new {@link MobEffectInstance} is added to an entity. * This event is also fired if an entity already has the effect but with a different duration or amplifier. - * This event is not cancelable. + * This event is not {@link CancellableEvent}. * This event does not have a result. */ public static class Added extends MobEffectEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEffectAdded(event); + }); + private final MobEffectInstance oldEffectInstance; private final Entity source; + @ApiStatus.Internal public Added(LivingEntity living, MobEffectInstance oldEffectInstance, MobEffectInstance newEffectInstance, Entity source) { super(living, newEffectInstance); this.oldEffectInstance = oldEffectInstance; @@ -131,7 +199,6 @@ public Added(LivingEntity living, MobEffectInstance oldEffectInstance, MobEffect * @return the added {@link MobEffectInstance}. This is the unmerged MobEffectInstance if the old MobEffectInstance is not null. */ @Override - @NotNull public MobEffectInstance getEffectInstance() { return super.getEffectInstance(); } @@ -154,39 +221,37 @@ public Entity getEffectSource() { @Override public void sendEvent() { - ADDED.invoker().onEffectAdded(this); + EVENT.invoker().onEffectAdded(this); + } + + public interface Callback { + void onEffectAdded(Added event); } } /** * This event is fired when a {@link MobEffectInstance} expires on an entity. - * This event is not cancelable. + * This event is {@link CancellableEvent}. * This event does not have a result. */ - public static class Expired extends MobEffectEvent { + public static class Expired extends MobEffectEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onEffectExpired(event); + }); + + @ApiStatus.Internal public Expired(LivingEntity living, MobEffectInstance effectInstance) { super(living, effectInstance); } @Override public void sendEvent() { - EXPIRED.invoker().onEffectExpired(this); + EVENT.invoker().onEffectExpired(this); } - } - - public interface RemoveCallback { - void onEffectRemove(Remove event); - } - public interface ApplicableCallback { - void onEffectApplicable(Applicable event); - } - - public interface AddedCallback { - void onEffectAdded(Added event); - } - - public interface ExpiredCallback { - void onEffectExpired(Expired event); + public interface Callback { + void onEffectExpired(Expired event); + } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ShieldBlockEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/ShieldBlockEvent.java similarity index 86% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ShieldBlockEvent.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/ShieldBlockEvent.java index aff4429d3..a41647fca 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/ShieldBlockEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/living/ShieldBlockEvent.java @@ -1,5 +1,6 @@ -package io.github.fabricators_of_create.porting_lib.entity.events; +package io.github.fabricators_of_create.porting_lib.entity.events.living; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.util.Mth; @@ -13,10 +14,10 @@ * Note: The shield item stack "should" be available from {@link LivingEntity#getUseItem()} * at least for players. */ -public class ShieldBlockEvent extends EntityEvents { - public static Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { - for (Callback e : callbacks) - e.onShieldBlock(event); +public class ShieldBlockEvent extends LivingEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onShieldBlock(event); }); private final DamageSource source; @@ -31,11 +32,6 @@ public ShieldBlockEvent(LivingEntity blocker, DamageSource source, float blocked this.dmgBlocked = blocked; } - @Override - public LivingEntity getEntity() { - return (LivingEntity) super.getEntity(); - } - /** * @return The damage source. */ @@ -60,6 +56,7 @@ public float getBlockedDamage() { /** * Controls if {@link LivingEntity#hurtCurrentlyUsedShield} is called. + * * @return If the shield item will take durability damage or not. */ public boolean shieldTakesDamage() { @@ -86,7 +83,6 @@ public void sendEvent() { EVENT.invoker().onShieldBlock(this); } - @FunctionalInterface public interface Callback { void onShieldBlock(ShieldBlockEvent event); } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/AttackEntityEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/AttackEntityEvent.java index 49d7dc16f..9f4894f68 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/AttackEntityEvent.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/AttackEntityEvent.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.events.player; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerEvents; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.world.entity.Entity; @@ -13,17 +13,15 @@ *
* {@link #target} contains the Entity that was damaged by the player.
*
- * This event is cancelable.
+ * This event is {@link CancellableEvent}.
* If this event is canceled, the player does not attack the Entity.
- *
- * This event does not have a result.
- *
**/ -public class AttackEntityEvent extends PlayerEvents { - public static final Event ATTACK_ENTITY = EventFactory.createArrayBacked(AttackEntityCallback.class, callbacks -> event -> { - for (AttackEntityCallback e : callbacks) - e.onAttackEntity(event); +public class AttackEntityEvent extends PlayerEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onAttackEntity(event); }); + private final Entity target; public AttackEntityEvent(Player player, Entity target) { @@ -37,11 +35,10 @@ public Entity getTarget() { @Override public void sendEvent() { - ATTACK_ENTITY.invoker().onAttackEntity(this); + EVENT.invoker().onAttackEntity(this); } - @FunctionalInterface - public interface AttackEntityCallback { + public interface Callback { void onAttackEntity(AttackEntityEvent event); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/CriticalHitEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/CriticalHitEvent.java new file mode 100644 index 000000000..78edc90a9 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/CriticalHitEvent.java @@ -0,0 +1,111 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.player; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; + +/** + * This event is fired when a player attacks an entity in {@link Player#attack(Entity)}. + * It can be used to change the critical hit status and damage modifier + *

+ * In the event the attack was not a critical hit, the event will still be fired, but it will be preemptively cancelled. + **/ +public class CriticalHitEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onCriticalHit(event); + }); + + private final Entity target; + private final float vanillaDmgMultiplier; + private final boolean isVanillaCritical; + + private float dmgMultiplier; + private boolean isCriticalHit; + + /** + * Fire via {@link EntityHooks#fireCriticalHit(Player, Entity, boolean, float)} + */ + public CriticalHitEvent(Player player, Entity target, float dmgMultiplier, boolean isCriticalHit) { + super(player); + this.target = target; + this.dmgMultiplier = this.vanillaDmgMultiplier = dmgMultiplier; + this.isCriticalHit = this.isVanillaCritical = isCriticalHit; + } + + /** + * {@return the entity that was attacked by the player} + */ + public Entity getTarget() { + return this.target; + } + + /** + * The damage multiplier is applied to the base attack's damage if the attack {@linkplain #isCriticalHit() critically hits}. + *

+ * A damage multiplier of 1.0 will not change the damage, a value of 1.5 will increase the damage by 50%, and so on. + */ + public float getDamageMultiplier() { + return this.dmgMultiplier; + } + + /** + * Sets the damage multiplier for the critical hit. Not used if {@link #isCriticalHit()} is false. + *

+ * Changing the damage modifier to zero does not guarantee that the attack does zero damage. + * + * @param dmgMultiplier The new damage modifier. Must not be negative. + * @see #getDamageMultiplier() + */ + public void setDamageMultiplier(float dmgMultiplier) { + if (dmgMultiplier < 0) { + throw new UnsupportedOperationException("Attempted to set a negative damage multiplier: " + dmgMultiplier); + } + this.dmgMultiplier = dmgMultiplier; + } + + /** + * {@return if the attack will critically hit} + */ + public boolean isCriticalHit() { + return this.isCriticalHit; + } + + /** + * Changes the critical hit state. + * + * @param isCriticalHit true if the attack should critically hit + */ + public void setCriticalHit(boolean isCriticalHit) { + this.isCriticalHit = isCriticalHit; + } + + /** + * Gets the original damage multiplier set by vanilla. + *

+ * If the event {@link #isVanillaCritical()}, the damage multiplier will be 1.5, otherwise it will be 1.0 + * + * @see #getDamageMultiplier() + */ + public float getVanillaMultiplier() { + return this.vanillaDmgMultiplier; + } + + /** + * {@return true if the attack was considered a critical hit by vanilla} + */ + public boolean isVanillaCritical() { + return this.isVanillaCritical; + } + + @Override + public void sendEvent() { + EVENT.invoker().onCriticalHit(this); + } + + public interface Callback { + void onCriticalHit(CriticalHitEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerDestroyItemEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerDestroyItemEvent.java new file mode 100644 index 000000000..bc7c554d6 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerDestroyItemEvent.java @@ -0,0 +1,73 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.player; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +/** + * PlayerDestroyItemEvent is fired when a player destroys an item.
+ * This event is fired whenever a player destroys an item in + * {@link MultiPlayerGameMode#destroyBlock(BlockPos)}, + * {@link MultiPlayerGameMode#useItem(Player, InteractionHand)}, + * {@link MultiPlayerGameMode#useItemOn(LocalPlayer, InteractionHand, BlockHitResult)} , + * {@link Player#attack(Entity)}, + * {@code Player#hurtCurrentlyUsedShield(float)}, + * {@link Player#interactOn(Entity, InteractionHand)}, + * {@link ServerPlayerGameMode#useItem(ServerPlayer, Level, ItemStack, InteractionHand)} , + * {@link ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult)} + * and {@link ServerPlayerGameMode#destroyBlock(BlockPos)}.
+ *
+ * {@link #original} contains the original ItemStack before the item was destroyed.
+ * (@link #hand) contains the hand that the current item was held in.
+ *
+ * This event is not {@link CancellableEvent}.
+ *
+ * This event is fired from {@link EntityHooks#onPlayerDestroyItem(Player, ItemStack, InteractionHand)}.
+ **/ +public class PlayerDestroyItemEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onPlayerDestroyItem(event); + }); + + private final ItemStack original; + @Nullable + private final InteractionHand hand; // May be null if this player destroys the item by any use besides holding it. + + public PlayerDestroyItemEvent(Player player, ItemStack original, @Nullable InteractionHand hand) { + super(player); + this.original = original; + this.hand = hand; + } + + public ItemStack getOriginal() { + return this.original; + } + + @Nullable + public InteractionHand getHand() { + return this.hand; + } + + @Override + public void sendEvent() { + EVENT.invoker().onPlayerDestroyItem(this); + } + + public interface Callback { + void onPlayerDestroyItem(PlayerDestroyItemEvent event); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerEvent.java new file mode 100644 index 000000000..be8aabaa2 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerEvent.java @@ -0,0 +1,639 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.player; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Optional; + +/** + * PlayerEvent is fired whenever an event involving a {@link Player} occurs.
+ * If a method utilizes this {@link BaseEvent} as its parameter, the method will + * receive every child event of this class.
+ **/ +public abstract class PlayerEvent extends LivingEvent { + private final Player player; + + public PlayerEvent(Player player) { + super(player); + this.player = player; + } + + @Override + public Player getEntity() { + return player; + } + +// /** TODO: Implement +// * HarvestCheck is fired when a player attempts to harvest a block.
+// * This event is fired whenever a player attempts to harvest a block in +// * {@link Player#hasCorrectToolForDrops(BlockState)}.
+// *
+// * This event is fired via the {@link EntityHooks#doPlayerHarvestCheck(Player, BlockState, BlockGetter, BlockPos)}.
+// *
+// * {@link #state} contains the {@link BlockState} that is being checked for harvesting.
+// * {@link #success} contains the boolean value for whether the Block will be successfully harvested.
+// *
+// * This event is not {@link CancellableEvent}.
+// **/ +// public static class HarvestCheck extends PlayerEvent { +// public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { +// for (final Callback callback : callbacks) +// callback.onHarvestCheck(event); +// }); +// +// private final BlockState state; +// private final BlockGetter level; +// private final BlockPos pos; +// private boolean success; +// +// public HarvestCheck(Player player, BlockState state, BlockGetter level, BlockPos pos, boolean success) { +// super(player); +// this.state = state; +// this.level = level; +// this.pos = pos; +// this.success = success; +// } +// +// public BlockState getTargetBlock() { +// return this.state; +// } +// +// public BlockGetter getLevel() { +// return level; +// } +// +// public BlockPos getPos() { +// return pos; +// } +// +// public boolean canHarvest() { +// return this.success; +// } +// +// public void setCanHarvest(boolean success) { +// this.success = success; +// } +// +// @Override +// public void sendEvent() { +// EVENT.invoker().onHarvestCheck(this); +// } +// +// public interface Callback { +// void onHarvestCheck(HarvestCheck event); +// } +// } + + /** + * BreakSpeed is fired when a player attempts to harvest a block.
+ * This event is fired whenever a player attempts to harvest a block in + * {@link Player#getDigSpeed(BlockState, BlockPos)}.
+ *
+ * This event is fired via the {@link EntityHooks#getBreakSpeed(Player, BlockState, float, BlockPos)}.
+ *
+ * {@link #state} contains the block being broken.
+ * {@link #originalSpeed} contains the original speed at which the player broke the block.
+ * {@link #newSpeed} contains the newSpeed at which the player will break the block.
+ * {@link #pos} contains the coordinates at which this event is occurring. Optional value.
+ *
+ * This event is {@link CancellableEvent}.
+ * If it is canceled, the player is unable to break the block.
+ **/ + public static class BreakSpeed extends PlayerEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onBreakSpeed(event); + }); + + private static final BlockPos LEGACY_UNKNOWN = new BlockPos(0, -1, 0); + private final BlockState state; + private final float originalSpeed; + private float newSpeed = 0.0f; + private final Optional pos; // Y position of -1 notes unknown location + + public BreakSpeed(Player player, BlockState state, float original, @Nullable BlockPos pos) { + super(player); + this.state = state; + this.originalSpeed = original; + this.setNewSpeed(original); + this.pos = Optional.ofNullable(pos); + } + + public BlockState getState() { + return state; + } + + public float getOriginalSpeed() { + return originalSpeed; + } + + public float getNewSpeed() { + return newSpeed; + } + + public void setNewSpeed(float newSpeed) { + this.newSpeed = newSpeed; + } + + public Optional getPosition() { + return this.pos; + } + + @Override + public void sendEvent() { + EVENT.invoker().onBreakSpeed(this); + } + + public interface Callback { + void onBreakSpeed(BreakSpeed event); + } + } + + /** + * NameFormat is fired when a player's display name is retrieved.
+ * This event is fired whenever a player's name is retrieved in + * {@link Player#getDisplayName()} or {@link Player#refreshDisplayName()}.
+ *
+ * This event is fired via the {@link EntityHooks#getPlayerDisplayName(Player, Component)}.
+ *
+ * {@link #username} contains the username of the player. + * {@link #displayname} contains the display name of the player. + *
+ * This event is not {@link CancellableEvent}. + **/ + public static class NameFormat extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onNameFormat(event); + }); + + private final Component username; + private Component displayname; + + public NameFormat(Player player, Component username) { + super(player); + this.username = username; + this.setDisplayname(username); + } + + public Component getUsername() { + return username; + } + + public Component getDisplayname() { + return displayname; + } + + public void setDisplayname(Component displayname) { + this.displayname = displayname; + } + + @Override + public void sendEvent() { + EVENT.invoker().onNameFormat(this); + } + + public interface Callback { + void onNameFormat(NameFormat event); + } + } + + /** + * TabListNameFormat is fired when a player's display name for the tablist is retrieved.
+ * This event is fired whenever a player's display name for the tablist is retrieved in + * {@link ServerPlayer#getTabListDisplayName()} or {@link ServerPlayer#refreshTabListName()}.
+ *
+ * This event is fired via the {@link EntityHooks#getPlayerTabListDisplayName(Player)}.
+ *
+ * {@link #getDisplayName()} contains the display name of the player or null if the client should determine the display name itself. + *
+ * This event is not {@link CancellableEvent}. + **/ + public static class TabListNameFormat extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onTabListNameFormat(event); + }); + + @Nullable + private Component displayName; + + public TabListNameFormat(Player player) { + super(player); + } + + @Nullable + public Component getDisplayName() { + return displayName; + } + + public void setDisplayName(@Nullable Component displayName) { + this.displayName = displayName; + } + + @Override + public void sendEvent() { + EVENT.invoker().onTabListNameFormat(this); + } + + public interface Callback { + void onTabListNameFormat(TabListNameFormat event); + } + } + + /** + * Fired when the EntityPlayer is cloned, typically caused by the impl sending a RESPAWN_PLAYER event. + * Either caused by death, or by traveling from the End to the overworld. + */ + public static class Clone extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onClone(event); + }); + + private final Player original; + private final boolean wasDeath; + + public Clone(Player _new, Player oldPlayer, boolean wasDeath) { + super(_new); + this.original = oldPlayer; + this.wasDeath = wasDeath; + } + + /** + * The old EntityPlayer that this new entity is a clone of. + */ + public Player getOriginal() { + return original; + } + + /** + * True if this event was fired because the player died. + * False if it was fired because the entity switched dimensions. + */ + public boolean isWasDeath() { + return wasDeath; + } + + @Override + public void sendEvent() { + EVENT.invoker().onClone(this); + } + + public interface Callback { + void onClone(Clone event); + } + } + + /** + * Fired when an Entity is started to be "tracked" by this player (the player receives updates about this entity, e.g. motion). + * + */ + public static class StartTracking extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onStartTracking(event); + }); + + private final Entity target; + + public StartTracking(Player player, Entity target) { + super(player); + this.target = target; + } + + /** + * The Entity now being tracked. + */ + public Entity getTarget() { + return target; + } + + @Override + public void sendEvent() { + EVENT.invoker().onStartTracking(this); + } + + public interface Callback { + void onStartTracking(StartTracking event); + } + } + + /** + * Fired when an Entity is stopped to be "tracked" by this player (the player no longer receives updates about this entity, e.g. motion). + * + */ + public static class StopTracking extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onStopTracking(event); + }); + + private final Entity target; + + public StopTracking(Player player, Entity target) { + super(player); + this.target = target; + } + + /** + * The Entity no longer being tracked. + */ + public Entity getTarget() { + return target; + } + + @Override + public void sendEvent() { + EVENT.invoker().onStopTracking(this); + } + + public interface Callback { + void onStopTracking(StopTracking event); + } + } + + /** + * The player is being loaded from the world save. Note that the + * player won't have been added to the world yet. Intended to + * allow mods to load an additional file from the players directory + * containing additional mod related player data. + */ + public static class LoadFromFile extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onLoadFromFile(event); + }); + + private final File playerDirectory; + private final String playerUUID; + + public LoadFromFile(Player player, File originDirectory, String playerUUID) { + super(player); + this.playerDirectory = originDirectory; + this.playerUUID = playerUUID; + } + + /** + * Construct and return a recommended file for the supplied suffix + * + * @param suffix The suffix to use. + */ + public File getPlayerFile(String suffix) { + if ("dat".equals(suffix)) throw new IllegalArgumentException("The suffix 'dat' is reserved"); + return new File(this.getPlayerDirectory(), this.getPlayerUUID() + "." + suffix); + } + + /** + * The directory where player data is being stored. Use this + * to locate your mod additional file. + */ + public File getPlayerDirectory() { + return playerDirectory; + } + + /** + * The UUID is the standard for player related file storage. + * It is broken out here for convenience for quick file generation. + */ + public String getPlayerUUID() { + return playerUUID; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLoadFromFile(this); + } + + public interface Callback { + void onLoadFromFile(LoadFromFile event); + } + } + + /** + * The player is being saved to the world store. Note that the + * player may be in the process of logging out or otherwise departing + * from the world. Don't assume it's association with the world. + * This allows mods to load an additional file from the players directory + * containing additional mod related player data. + *
+ * Use this event to save the additional mod related player data to the world. + * + *
+ * WARNING: Do not overwrite the player's .dat file here. You will + * corrupt the world state. + */ + public static class SaveToFile extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onSaveToFile(event); + }); + + private final File playerDirectory; + private final String playerUUID; + + public SaveToFile(Player player, File originDirectory, String playerUUID) { + super(player); + this.playerDirectory = originDirectory; + this.playerUUID = playerUUID; + } + + /** + * Construct and return a recommended file for the supplied suffix + * + * @param suffix The suffix to use. + */ + public File getPlayerFile(String suffix) { + if ("dat".equals(suffix)) throw new IllegalArgumentException("The suffix 'dat' is reserved"); + return new File(this.getPlayerDirectory(), this.getPlayerUUID() + "." + suffix); + } + + /** + * The directory where player data is being stored. Use this + * to locate your mod additional file. + */ + public File getPlayerDirectory() { + return playerDirectory; + } + + /** + * The UUID is the standard for player related file storage. + * It is broken out here for convenience for quick file generation. + */ + public String getPlayerUUID() { + return playerUUID; + } + + @Override + public void sendEvent() { + EVENT.invoker().onSaveToFile(this); + } + + public interface Callback { + void onSaveToFile(SaveToFile event); + } + } + + public static class ItemCraftedEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onItemCrafted(event); + }); + + private final ItemStack crafting; + private final Container craftMatrix; + + public ItemCraftedEvent(Player player, ItemStack crafting, Container craftMatrix) { + super(player); + this.crafting = crafting; + this.craftMatrix = craftMatrix; + } + + public ItemStack getCrafting() { + return this.crafting; + } + + public Container getInventory() { + return this.craftMatrix; + } + + @Override + public void sendEvent() { + EVENT.invoker().onItemCrafted(this); + } + + public interface Callback { + void onItemCrafted(ItemCraftedEvent event); + } + } + + public static class ItemSmeltedEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onItemSmelted(event); + }); + + private final ItemStack smelting; + + public ItemSmeltedEvent(Player player, ItemStack crafting) { + super(player); + this.smelting = crafting; + } + + public ItemStack getSmelting() { + return this.smelting; + } + + @Override + public void sendEvent() { + EVENT.invoker().onItemSmelted(this); + } + + public interface Callback { + void onItemSmelted(ItemSmeltedEvent event); + } + } + + public static class PlayerLoggedInEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPlayerLoggedIn(event); + }); + + public PlayerLoggedInEvent(Player player) { + super(player); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPlayerLoggedIn(this); + } + + public interface Callback { + void onPlayerLoggedIn(PlayerLoggedInEvent event); + } + } + + public static class PlayerLoggedOutEvent extends PlayerEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPlayerLoggedOut(event); + }); + + public PlayerLoggedOutEvent(Player player) { + super(player); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPlayerLoggedOut(this); + } + + public interface Callback { + void onPlayerLoggedOut(PlayerLoggedOutEvent event); + } + } + + /** + * Fired when the game type of a server player is changed to a different value than what it was previously. Eg Creative to Survival, not Survival to Survival. + * If the event is cancelled the game mode of the player is not changed and the value of newGameMode is ignored. + */ + public static class PlayerChangeGameModeEvent extends PlayerEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPlayerChangeGameMode(event); + }); + + private final GameType currentGameMode; + private GameType newGameMode; + + public PlayerChangeGameModeEvent(Player player, GameType currentGameMode, GameType newGameMode) { + super(player); + this.currentGameMode = currentGameMode; + this.newGameMode = newGameMode; + } + + public GameType getCurrentGameMode() { + return currentGameMode; + } + + public GameType getNewGameMode() { + return newGameMode; + } + + /** + * Sets the game mode the player will be changed to if this event is not cancelled. + */ + public void setNewGameMode(GameType newGameMode) { + this.newGameMode = newGameMode; + } + + @Override + public void sendEvent() { + EVENT.invoker().onPlayerChangeGameMode(this); + } + + public interface Callback { + void onPlayerChangeGameMode(PlayerChangeGameModeEvent event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerInteractEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerInteractEvent.java new file mode 100644 index 000000000..4f9d9d2a3 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerInteractEvent.java @@ -0,0 +1,536 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.player; + +import com.google.common.base.Preconditions; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.util.TriState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; + +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * PlayerInteractEvent is fired when a player interacts in some way. + * See the individual documentation on each subevent for more details. + **/ +public abstract class PlayerInteractEvent extends PlayerEvent { + private final InteractionHand hand; + private final BlockPos pos; + @Nullable + private final Direction face; + + protected PlayerInteractEvent(Player player, InteractionHand hand, BlockPos pos, @Nullable Direction face) { + super(Preconditions.checkNotNull(player, "Null player in PlayerInteractEvent!")); + this.hand = Preconditions.checkNotNull(hand, "Null hand in PlayerInteractEvent!"); + this.pos = Preconditions.checkNotNull(pos, "Null position in PlayerInteractEvent!"); + this.face = face; + } + + /** + * This event is fired on both sides whenever a player right clicks an entity. + * + * "Interact at" is an interact where the local vector (which part of the entity you clicked) is known. + * The state of this event affects whether {@link Entity#interactAt(Player, Vec3, InteractionHand)} is called. + * + * Let result be the return value of {@link Entity#interactAt(Player, Vec3, InteractionHand)}, or {@link #cancellationResult} if the event is cancelled. + * If we are on the client and result is not {@link InteractionResult#SUCCESS}, the client will then try {@link EntityInteract}. + */ + public static class EntityInteractSpecific extends PlayerInteractEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onEntityInteractSpecific(event); + }); + + private InteractionResult cancellationResult = InteractionResult.PASS; + + private final Vec3 localPos; + private final Entity target; + + public EntityInteractSpecific(Player player, InteractionHand hand, Entity target, Vec3 localPos) { + super(player, hand, target.blockPosition(), null); + this.localPos = localPos; + this.target = target; + } + + /** + * Returns the local interaction position. This is a 3D vector, where (0, 0, 0) is centered exactly at the + * center of the entity's bounding box at their feet. This means the X and Z values will be in the range + * [-width / 2, width / 2] while Y values will be in the range [0, height] + * + * @return The local position + */ + public Vec3 getLocalPos() { + return localPos; + } + + public Entity getTarget() { + return target; + } + + /** + * @return The InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. By default, this is {@link InteractionResult#PASS}, meaning cancelled events will cause + * the client to keep trying more interactions until something works. + */ + public InteractionResult getCancellationResult() { + return cancellationResult; + } + + /** + * Set the InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. + */ + public void setCancellationResult(InteractionResult result) { + this.cancellationResult = result; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityInteractSpecific(this); + } + + public interface Callback { + void onEntityInteractSpecific(EntityInteractSpecific event); + } + } + + /** + * This event is fired on both sides when the player right clicks an entity. + * It is responsible for all general entity interactions. + * + * This event is fired only if the result of the above {@link EntityInteractSpecific} is not {@link InteractionResult#SUCCESS}. + * This event's state affects whether {@link Entity#interact(Player, InteractionHand)} and + * {@link Item#interactLivingEntity(ItemStack, Player, LivingEntity, InteractionHand)} are called. + * + * Let result be {@link InteractionResult#SUCCESS} if {@link Entity#interact(Player, InteractionHand)} or + * {@link Item#interactLivingEntity(ItemStack, Player, LivingEntity, InteractionHand)} return true, + * or {@link #cancellationResult} if the event is cancelled. + * If we are on the client and result is not {@link InteractionResult#SUCCESS}, the client will then try {@link RightClickItem}. + */ + public static class EntityInteract extends PlayerInteractEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onEntityInteract(event); + }); + + private InteractionResult cancellationResult = InteractionResult.PASS; + + private final Entity target; + + public EntityInteract(Player player, InteractionHand hand, Entity target) { + super(player, hand, target.blockPosition(), null); + this.target = target; + } + + public Entity getTarget() { + return target; + } + + /** + * @return The InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. By default, this is {@link InteractionResult#PASS}, meaning cancelled events will cause + * the client to keep trying more interactions until something works. + */ + public InteractionResult getCancellationResult() { + return cancellationResult; + } + + /** + * Set the InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. + */ + public void setCancellationResult(InteractionResult result) { + this.cancellationResult = result; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityInteract(this); + } + + public interface Callback { + void onEntityInteract(EntityInteract event); + } + } + + /** + * This event is fired on both sides whenever the player right clicks while targeting a block.
+ * This event controls which of {@link Item#onItemUseFirst}, {@link Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)}, + * and {@link Item#useOn(UseOnContext)} will be called.
+ * Canceling the event will cause none of the above three to be called.
+ *
+ * Let result be the first non-pass return value of the above three methods, or pass, if they all pass.
+ * Or {@link #cancellationResult} if the event is cancelled.
+ * If result equals {@link InteractionResult#PASS}, we proceed to {@link RightClickItem}.
+ *
+ * There are various results to this event, see the getters below.
+ * Note that handling things differently on the client vs server may cause desynchronizations! + */ + public static class RightClickBlock extends PlayerInteractEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onRightClickBlock(event); + }); + + private InteractionResult cancellationResult = InteractionResult.PASS; + + private TriState useBlock = TriState.DEFAULT; + private TriState useItem = TriState.DEFAULT; + private BlockHitResult hitVec; + + public RightClickBlock(Player player, InteractionHand hand, BlockPos pos, BlockHitResult hitVec) { + super(player, hand, pos, hitVec.getDirection()); + this.hitVec = hitVec; + } + + /** + * @return If {@link Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)} should be called + */ + public TriState getUseBlock() { + return useBlock; + } + + /** + * @return If {@link Item#onItemUseFirst} and {@link Item#useOn(UseOnContext)} should be called + */ + public TriState getUseItem() { + return useItem; + } + + /** + * @return The ray trace result targeting the block. + */ + public BlockHitResult getHitVec() { + return hitVec; + } + + /** + * FALSE: {@link Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)} will never be called.
+ * DEFAULT: {@link Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)} will be called if {@link Item#onItemUseFirst} passes.
+ * Note that default activation can be blocked if the user is sneaking and holding an item that does not return true to {@link Item#doesSneakBypassUse}.
+ * TRUE: {@link Block#updateOrDestroy(BlockState, BlockState, LevelAccessor, BlockPos, int, int)} will always be called, unless {@link Item#onItemUseFirst} does not pass.
+ */ + public void setUseBlock(TriState triggerBlock) { + this.useBlock = triggerBlock; + } + + /** + * FALSE: Neither {@link Item#useOn(UseOnContext)} or {@link Item#onItemUseFirst} will be called.
+ * DEFAULT: {@link Item#onItemUseFirst} will always be called, and {@link Item#useOn(UseOnContext)} will be called if the block passes.
+ * TRUE: {@link Item#onItemUseFirst} will always be called, and {@link Item#useOn(UseOnContext)} will be called if the block passes, regardless of cooldowns or emptiness.
+ */ + public void setUseItem(TriState triggerItem) { + this.useItem = triggerItem; + } + + @Override + public void setCanceled(boolean canceled) { + CancellableEvent.super.setCanceled(canceled); + if (canceled) { + useBlock = TriState.FALSE; + useItem = TriState.FALSE; + } + } + + /** + * @return The InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. By default, this is {@link InteractionResult#PASS}, meaning cancelled events will cause + * the client to keep trying more interactions until something works. + */ + public InteractionResult getCancellationResult() { + return cancellationResult; + } + + /** + * Set the InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. + */ + public void setCancellationResult(InteractionResult result) { + this.cancellationResult = result; + } + + @Override + public void sendEvent() { + EVENT.invoker().onRightClickBlock(this); + } + + public interface Callback { + void onRightClickBlock(RightClickBlock event); + } + } + + /** + * This event is fired on both sides before the player triggers {@link Item#use(Level, Player, InteractionHand)}. + * Note that this is NOT fired if the player is targeting a block {@link RightClickBlock} or entity {@link EntityInteract} {@link EntityInteractSpecific}. + * + * Let result be the return value of {@link Item#use(Level, Player, InteractionHand)}, or {@link #cancellationResult} if the event is cancelled. + * If we are on the client and result is not {@link InteractionResult#SUCCESS}, the client will then continue to other hands. + */ + public static class RightClickItem extends PlayerInteractEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onRightClickItem(event); + }); + + private InteractionResult cancellationResult = InteractionResult.PASS; + + public RightClickItem(Player player, InteractionHand hand) { + super(player, hand, player.blockPosition(), null); + } + + /** + * @return The InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. By default, this is {@link InteractionResult#PASS}, meaning cancelled events will cause + * the client to keep trying more interactions until something works. + */ + public InteractionResult getCancellationResult() { + return cancellationResult; + } + + /** + * Set the InteractionResult that will be returned to vanilla if the event is cancelled, instead of calling the relevant + * method of the event. + */ + public void setCancellationResult(InteractionResult result) { + this.cancellationResult = result; + } + + @Override + public void sendEvent() { + EVENT.invoker().onRightClickItem(this); + } + + public interface Callback { + void onRightClickItem(RightClickItem event); + } + } + + /** + * This event is fired on the client side when the player right clicks empty space with an empty hand. + * The server is not aware of when the client right clicks empty space with an empty hand, you will need to tell the server yourself. + * This event cannot be canceled. + */ + public static class RightClickEmpty extends PlayerInteractEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onRightClickEmpty(event); + }); + + public RightClickEmpty(Player player, InteractionHand hand) { + super(player, hand, player.blockPosition(), null); + } + + @Override + public void sendEvent() { + EVENT.invoker().onRightClickEmpty(this); + } + + public interface Callback { + void onRightClickEmpty(RightClickEmpty event); + } + } + + /** + * This event is fired when a player left clicks while targeting a block. + * This event controls which of {@link Block#attack(BlockState, Level, BlockPos, Player)} and/or the item harvesting methods will be called + * Canceling the event will cause none of the above noted methods to be called. + * There are various results to this event, see the getters below. + *

+ * This event is fired at various points during left clicking on blocks, at both the start and end on the server, and at the start and while held down on the client. + * Use {@link #getAction()} to check which type of action triggered this event. + *

+ * Note that if the event is canceled and the player holds down left mouse, the event will continue to fire. + * This is due to how vanilla calls the left click handler methods. + *

+ * Also note that creative mode directly breaks the block without running any other logic. + * Therefore, in creative mode, {@link #setUseBlock} and {@link #setUseItem} have no effect. + */ + public static class LeftClickBlock extends PlayerInteractEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onLeftClickBlock(event); + }); + + private TriState useBlock = TriState.DEFAULT; + private TriState useItem = TriState.DEFAULT; + private final Action action; + + @ApiStatus.Internal + public LeftClickBlock(Player player, BlockPos pos, Direction face, Action action) { + super(player, InteractionHand.MAIN_HAND, pos, face); + this.action = action; + } + + /** + * @return If {@link Block#attack(BlockState, Level, BlockPos, Player)} should be called. Changing this has no effect in creative mode + */ + public TriState getUseBlock() { + return useBlock; + } + + /** + * @return If the block should be attempted to be mined with the current item. Changing this has no effect in creative mode + */ + public TriState getUseItem() { + return useItem; + } + + /** + * @return The action type for this interaction. Will never be null. + */ + public Action getAction() { + return this.action; + } + + public void setUseBlock(TriState triggerBlock) { + this.useBlock = triggerBlock; + } + + public void setUseItem(TriState triggerItem) { + this.useItem = triggerItem; + } + + @Override + public void setCanceled(boolean canceled) { + CancellableEvent.super.setCanceled(canceled); + if (canceled) { + useBlock = TriState.FALSE; + useItem = TriState.FALSE; + } + } + + @Override + public void sendEvent() { + EVENT.invoker().onLeftClickBlock(this); + } + + public enum Action { + /** + * When the player first left clicks a block + */ + START, + /** + * When the player stops left clicking a block by completely breaking it + */ + STOP, + /** + * When the player stops left clicking a block by releasing the button, or no longer targeting the same block before it breaks. + */ + ABORT, + /** + * When the player is actively mining a block on the client side + * Warning: The event is fired every tick on the client + */ + CLIENT_HOLD; + + public static Action convert(ServerboundPlayerActionPacket.Action action) { + return switch (action) { + default -> START; + case START_DESTROY_BLOCK -> START; + case STOP_DESTROY_BLOCK -> STOP; + case ABORT_DESTROY_BLOCK -> ABORT; + }; + } + } + + public interface Callback { + void onLeftClickBlock(LeftClickBlock event); + } + } + + /** + * This event is fired on the client side when the player left clicks empty space with any ItemStack. + * The server is not aware of when the client left clicks empty space, you will need to tell the server yourself. + * This event cannot be canceled. + */ + public static class LeftClickEmpty extends PlayerInteractEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onLeftClickEmpty(event); + }); + + public LeftClickEmpty(Player player) { + super(player, InteractionHand.MAIN_HAND, player.blockPosition(), null); + } + + @Override + public void sendEvent() { + EVENT.invoker().onLeftClickEmpty(this); + } + + public interface Callback { + void onLeftClickEmpty(LeftClickEmpty event); + } + } + + /** + * @return The hand involved in this interaction. Will never be null. + */ + public InteractionHand getHand() { + return hand; + } + + /** + * @return The itemstack involved in this interaction, {@code ItemStack.EMPTY} if the hand was empty. + */ + public ItemStack getItemStack() { + return getEntity().getItemInHand(hand); + } + + /** + * If the interaction was on an entity, will be a BlockPos centered on the entity. + * If the interaction was on a block, will be the position of that block. + * Otherwise, will be a BlockPos centered on the player. + * Will never be null. + * + * @return The position involved in this interaction. + */ + public BlockPos getPos() { + return pos; + } + + /** + * @return The face involved in this interaction. For all non-block interactions, this will return null. + */ + @Nullable + public Direction getFace() { + return face; + } + + /** + * @return Convenience method to get the level of this interaction. + */ + public Level getLevel() { + return getEntity().level(); + } + + /** + * @return The effective, i.e. logical, side of this interaction. This will be {@link EnvType#CLIENT} on the client thread, and {@link EnvType#SERVER} on the server thread. + */ + public EnvType getSide() { + return getLevel().isClientSide ? EnvType.CLIENT : EnvType.SERVER; + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerXpEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerXpEvent.java new file mode 100644 index 000000000..74f50c665 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/player/PlayerXpEvent.java @@ -0,0 +1,120 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.player; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.player.Player; + +/** + * PlayerXpEvent is fired whenever an event involving player experience occurs.
+ * If a method utilizes this {@link BaseEvent} as its parameter, the method will + * receive every child event of this class.
+ */ +public abstract class PlayerXpEvent extends PlayerEvent { + public PlayerXpEvent(Player player) { + super(player); + } + + /** + * This event is fired after the player collides with an experience orb, but before the player has been given the experience. + * It can be cancelled, and no further processing will be done. + */ + public static class PickupXp extends PlayerXpEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPickupXp(event); + }); + + private final ExperienceOrb orb; + + public PickupXp(Player player, ExperienceOrb orb) { + super(player); + this.orb = orb; + } + + public ExperienceOrb getOrb() { + return orb; + } + + @Override + public void sendEvent() { + EVENT.invoker().onPickupXp(this); + } + + public interface Callback { + void onPickupXp(PickupXp event); + } + } + + /** + * This event is fired when the player's experience changes through the {@link Player#giveExperiencePoints(int)} method. + * It can be cancelled, and no further processing will be done. + */ + public static class XpChange extends PlayerXpEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onXpChange(event); + }); + + private int amount; + + public XpChange(Player player, int amount) { + super(player); + this.amount = amount; + } + + public int getAmount() { + return this.amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + @Override + public void sendEvent() { + EVENT.invoker().onXpChange(this); + } + + public interface Callback { + void onXpChange(XpChange event); + } + } + + /** + * This event is fired when the player's experience level changes through the {@link Player#giveExperienceLevels(int)} method. + * It can be cancelled, and no further processing will be done. + */ + public static class LevelChange extends PlayerXpEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onLevelChange(event); + }); + + private int levels; + + public LevelChange(Player player, int levels) { + super(player); + this.levels = levels; + } + + public int getLevels() { + return this.levels; + } + + public void setLevels(int levels) { + this.levels = levels; + } + + @Override + public void sendEvent() { + EVENT.invoker().onLevelChange(this); + } + + public interface Callback { + void onLevelChange(LevelChange event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/EntityTickEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/EntityTickEvent.java new file mode 100644 index 000000000..fc65fe354 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/EntityTickEvent.java @@ -0,0 +1,81 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.tick; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.world.entity.Entity; + +/** + * Base class of the two entity tick events. + * + * @see EntityTickEvent.Pre + * @see EntityTickEvent.Post + */ +public abstract class EntityTickEvent extends EntityEvent { + protected EntityTickEvent(Entity entity) { + super(entity); + } + + /** + * {@link EntityTickEvent.Pre} is fired once per game tick, per entity, before the entity performs work for the current tick. + *

+ * This event fires on both the logical server and logical client. + */ + public static class Pre extends EntityTickEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPreTick(event); + }); + + public Pre(Entity entity) { + super(entity); + } + + /** + * Cancels this event, preventing the current tick from being executed for the entity. + *

+ * Additionally, if this event is canceled, then {@link EntityTickEvent.Post} will not be fired for the current tick. + */ + @Override + public void setCanceled(boolean canceled) { + CancellableEvent.super.setCanceled(canceled); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPreTick(this); + } + + public interface Callback { + void onPreTick(Pre event); + } + } + + /** + * {@link EntityTickEvent.Post} is fired once per game tick, per entity, after the entity performs work for the current tick. + *

+ * If {@link EntityTickEvent.Pre} was canceled for the current tick, this event will not fire. + *

+ * This event fires on both the logical server and logical client. + */ + public static class Post extends EntityTickEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPostTick(event); + }); + + public Post(Entity entity) { + super(entity); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPostTick(this); + } + + public interface Callback { + void onPostTick(Post event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/PlayerTickEvent.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/PlayerTickEvent.java new file mode 100644 index 000000000..2cdf94308 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/events/tick/PlayerTickEvent.java @@ -0,0 +1,82 @@ +package io.github.fabricators_of_create.porting_lib.entity.events.tick; + +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerEvent; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + +/** + * Base class of the two player tick events. + *

+ * These events are separate from {@link EntityTickEvent} due to the semantics of player ticks. + * On the client, players tick from the usual {@link Entity#tick()} method, but on the server, they rely + * on {@link ServerPlayer#doTick()} which is called from {@link ServerGamePacketListenerImpl#tick()}. + *

+ * Use of these events should only be necessary if you rely on this specific timing. + * + * @see PlayerTickEvent.Pre + * @see PlayerTickEvent.Post + */ +public abstract class PlayerTickEvent extends PlayerEvent { + protected PlayerTickEvent(Player player) { + super(player); + } + + /** + * {@link PlayerTickEvent.Pre} is fired once per game tick, per player, before the player performs work for the current tick. + *

+ * This event will fire on both the logical server and logical client, for subclasses of {@link Player} on their respective sides. + *

+ * As such, be sure to check {@link Level#isClientSide()} before performing any operations. + */ + public static class Pre extends PlayerTickEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPreTick(event); + }); + + public Pre(Player player) { + super(player); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPreTick(this); + } + + public interface Callback { + void onPreTick(Pre event); + } + } + + /** + * {@link PlayerTickEvent.Post} is fired once per game tick, per player, after the player performs work for the current tick. + *

+ * This event will fire on both the logical server and logical client, for subclasses of {@link Player} on their respective sides. + *

+ * As such, be sure to check {@link Level#isClientSide()} before performing any operations. + */ + public static class Post extends PlayerTickEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (final Callback callback : callbacks) + callback.onPostTick(event); + }); + + public Post(Player player) { + super(player); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPostTick(this); + } + + public interface Callback { + void onPostTick(Post event); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/AbstractMinecartExtensions.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/AbstractMinecartExt.java similarity index 75% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/AbstractMinecartExtensions.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/AbstractMinecartExt.java index 2ce96a81b..ad85989c0 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/AbstractMinecartExtensions.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/AbstractMinecartExt.java @@ -1,8 +1,8 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; +package io.github.fabricators_of_create.porting_lib.entity.ext; import net.minecraft.core.BlockPos; -public interface AbstractMinecartExtensions { +public interface AbstractMinecartExt { default void moveMinecartOnRail(BlockPos pos) { throw new RuntimeException("this should be overridden via mixin. what?"); } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/EntityExt.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/EntityExt.java new file mode 100644 index 000000000..1aa38ee73 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/EntityExt.java @@ -0,0 +1,48 @@ +package io.github.fabricators_of_create.porting_lib.entity.ext; + +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.IEntityWithComplexSpawn; +import io.github.fabricators_of_create.porting_lib.entity.network.AdvancedAddEntityPayload; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.item.ItemEntity; + +import java.util.Collection; +import java.util.function.Consumer; + +public interface EntityExt { + default CompoundTag getCustomData() { + throw new RuntimeException("this should be overridden via mixin. what?"); + } + + default Collection captureDrops() { + throw new RuntimeException("this should be overridden via mixin. what?"); + } + + default Collection captureDrops(Collection value) { + throw new RuntimeException("this should be overridden via mixin. what?"); + } + + /** + * If a rider of this entity can interact with this entity. Should return true on the + * ridden entity if so. + * + * @return if the entity can be interacted with from a rider + */ + default boolean canRiderInteract() { + return false; + } + + /** + * Sends the pairing data to the client. + * + * @param serverPlayer The player to send the data to. + * @param bundleBuilder Callback to add a custom payload to the packet. + */ + default void sendPairingData(ServerPlayer serverPlayer, Consumer bundleBuilder) { + if (this instanceof IEntityWithComplexSpawn) { + bundleBuilder.accept(new AdvancedAddEntityPayload(MixinHelper.cast(this))); + } + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/ItemExtensions.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/ItemExt.java similarity index 56% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/ItemExtensions.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/ItemExt.java index 030ca6d97..fcf12bb91 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/ItemExtensions.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/ItemExt.java @@ -1,12 +1,13 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; +package io.github.fabricators_of_create.porting_lib.entity.ext; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; -public interface ItemExtensions { +public interface ItemExt { /** * Determines if this Item has a special entity for when they are in the world. * Is called when a EntityItem is spawned in the world, if true and @@ -26,14 +27,28 @@ default boolean hasCustomEntity(ItemStack stack) { * Returning null here will not kill the EntityItem and will leave it to * function normally. Called when the item it placed in a level. * - * @param level The level object - * @param location The EntityItem object, useful for getting the position of - * the entity - * @param stack The current item stack + * @param level The level object + * @param location The EntityItem object, useful for getting the position of + * the entity + * @param stack The current item stack * @return A new Entity object to spawn or null */ @Nullable default Entity createEntity(Level level, Entity location, ItemStack stack) { return null; } + + /** + * Called when the player Left Clicks (attacks) an entity. Processed before + * damage is done, if return value is true further processing is canceled and + * the entity is not attacked. + * + * @param stack The Item being used + * @param player The player that is attacking + * @param entity The entity being attacked + * @return True to cancel the rest of the interaction. + */ + default boolean onLeftClickEntity(ItemStack stack, Player player, Entity entity) { + return false; + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/LevelExtensions.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LevelExt.java similarity index 84% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/LevelExtensions.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LevelExt.java index 4e8ed4bab..9232c452e 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/LevelExtensions.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LevelExt.java @@ -1,11 +1,11 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; +package io.github.fabricators_of_create.porting_lib.entity.ext; import io.github.fabricators_of_create.porting_lib.entity.PartEntity; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import java.util.Collection; -public interface LevelExtensions { +public interface LevelExt { /** * All part entities in this world. Used when collecting entities in an AABB to fix parts being * ignored whose parent entity is in a chunk that does not intersect with the AABB. diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LivingEntityExt.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LivingEntityExt.java new file mode 100644 index 000000000..b081296e8 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/LivingEntityExt.java @@ -0,0 +1,14 @@ +package io.github.fabricators_of_create.porting_lib.entity.ext; + +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; + +public interface LivingEntityExt { + /** + * Removes all potion effects that have the given {@link EffectCure} in their set of cures + * @param cure the EffectCure being used + */ + default boolean removeEffectsCuredBy(EffectCure cure) { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support removeEffectsCuredBy(EffectCure)"); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectExt.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectExt.java new file mode 100644 index 000000000..56ab63af5 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectExt.java @@ -0,0 +1,29 @@ +package io.github.fabricators_of_create.porting_lib.entity.ext; + +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; +import io.github.fabricators_of_create.porting_lib.entity.EffectCures; +import io.github.fabricators_of_create.porting_lib.entity.client.MobEffectRenderer; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; + +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public interface MobEffectExt { + /*** + * Fill the given set with the {@link EffectCure}s this effect should be curable with by default + */ + default void fillEffectCures(Set cures, MobEffectInstance effectInstance) { + cures.addAll(EffectCures.DEFAULT_CURES); + if (MixinHelper.cast(this) == MobEffects.POISON.value()) { + cures.add(EffectCures.HONEY); + } + } + + @Nullable + default MobEffectRenderer getRenderer() { + return null; + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectInstanceExt.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectInstanceExt.java new file mode 100644 index 000000000..cf8c37662 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectInstanceExt.java @@ -0,0 +1,12 @@ +package io.github.fabricators_of_create.porting_lib.entity.ext; + +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; + +import java.util.Set; + +public interface MobEffectInstanceExt { + default Set getCures() { + throw PortingLib.createMixinException(this.getClass().getSimpleName() + " does not support getCures()"); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/PlayerExtension.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/PlayerExt.java similarity index 81% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/PlayerExtension.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/PlayerExt.java index 539d91d2d..ce89f6852 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/PlayerExtension.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/PlayerExt.java @@ -1,4 +1,4 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; +package io.github.fabricators_of_create.porting_lib.entity.ext; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; @@ -6,7 +6,7 @@ import javax.annotation.Nullable; -public interface PlayerExtension { +public interface PlayerExt { default float getDigSpeed(BlockState state, @Nullable BlockPos pos) { setDigSpeedContext(pos); return ((Player) this).getDestroySpeed(state); diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/SlimeExtension.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/SlimeExt.java similarity index 66% rename from modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/SlimeExtension.java rename to modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/SlimeExt.java index 5a13bf84e..96f2bb12f 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/SlimeExtension.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/ext/SlimeExt.java @@ -1,6 +1,6 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; +package io.github.fabricators_of_create.porting_lib.entity.ext; -public interface SlimeExtension { +public interface SlimeExt { /** * Called when the slime spawns particles on landing, see onUpdate. * Return true to prevent the spawning of the default particles. diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/EntityExtensions.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/EntityExtensions.java deleted file mode 100644 index 48c6a0f75..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/EntityExtensions.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; - -import io.github.fabricators_of_create.porting_lib.entity.ITeleporter; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; - -import java.util.Collection; - -public interface EntityExtensions { - default CompoundTag getCustomData() { - throw new RuntimeException("this should be overridden via mixin. what?"); - } - - default Collection captureDrops() { - throw new RuntimeException("this should be overridden via mixin. what?"); - } - - default Collection captureDrops(Collection value) { - throw new RuntimeException("this should be overridden via mixin. what?"); - } - - /** - * If a rider of this entity can interact with this entity. Should return true on the - * ridden entity if so. - * - * @return if the entity can be interacted with from a rider - */ - default boolean canRiderInteract() { - return false; - } - - default Entity changeDimension(ServerLevel p_20118_, ITeleporter teleporter) { - throw new RuntimeException("this should be overridden via mixin. what?"); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/MobEffectExtensions.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/MobEffectExtensions.java deleted file mode 100644 index 1e94a6206..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/extensions/MobEffectExtensions.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.extensions; - -import io.github.fabricators_of_create.porting_lib.entity.client.MobEffectRenderer; - -import org.jetbrains.annotations.Nullable; - -public interface MobEffectExtensions { - @Nullable - default MobEffectRenderer getRenderer() { - return null; - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/accessor/PlayerDataStorageAccessor.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/accessor/PlayerDataStorageAccessor.java new file mode 100644 index 000000000..a5014e2b4 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/accessor/PlayerDataStorageAccessor.java @@ -0,0 +1,14 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.accessor; + +import net.minecraft.world.level.storage.PlayerDataStorage; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.File; + +@Mixin(PlayerDataStorage.class) +public interface PlayerDataStorageAccessor { + @Accessor + File getPlayerDir(); +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/ClientLevelMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/ClientLevelMixin.java index 091ab4a4b..7669838e8 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/ClientLevelMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/ClientLevelMixin.java @@ -1,24 +1,52 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.client; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityJoinLevelEvent; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.storage.WritableLevelData; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.function.Supplier; + @Environment(EnvType.CLIENT) @Mixin(ClientLevel.class) -public abstract class ClientLevelMixin { +public abstract class ClientLevelMixin extends Level { + protected ClientLevelMixin(WritableLevelData writableLevelData, ResourceKey resourceKey, RegistryAccess registryAccess, Holder holder, Supplier supplier, boolean bl, boolean bl2, long l, int i) { + super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i); + } + @Inject(method = "addEntity", at = @At("HEAD"), cancellable = true) public void port_lib$addEntityEvent(Entity entity, CallbackInfo ci) { - if (EntityEvents.ON_JOIN_WORLD.invoker().onJoinWorld(entity, (Level) (Object) this, false)) + EntityJoinLevelEvent event = new EntityJoinLevelEvent(entity, this); + event.sendEvent(); + if (event.isCanceled()) ci.cancel(); } + + @WrapOperation(method = "tickNonPassenger", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;tick()V")) + private void preEntityTick(Entity instance, Operation original) { + if (!EntityHooks.fireEntityTickPre(instance).isCanceled()) { + original.call(instance); + EntityHooks.fireEntityTickPost(instance); + } + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EffectRenderingInventoryScreenMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EffectRenderingInventoryScreenMixin.java index a1b7eee7b..c75831d08 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EffectRenderingInventoryScreenMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EffectRenderingInventoryScreenMixin.java @@ -37,9 +37,9 @@ private Iterable shouldRenderEffect(Iterable Collection effectInstances = (Collection) elements; return effectInstances.stream().filter(mobEffectInstance -> { - MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); - if (renderer != null) - return renderer.isVisibleInInventory(mobEffectInstance); +// MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); TODO: PORT +// if (renderer != null) +// return renderer.isVisibleInInventory(mobEffectInstance); return true; }).collect(Collectors.toList()); } @@ -48,21 +48,21 @@ private Iterable shouldRenderEffect(Iterable private void handleCustomRenderers(GuiGraphics graphics, int blitX, int blitY, int z, int width, int height, TextureAtlasSprite sprite, Operation original, @Local(index = 2) int x, @Local(index = 3) int offsetDelta, @Local(index = 5) boolean wide, @Local(index = 9) MobEffectInstance mobEffectInstance, @Local(index = 7) int i, @Share("offset") LocalRef offset) { if (offset.get() == null) offset.set(0); - MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); - if (renderer != null && renderer.renderInventoryIcon(mobEffectInstance, (EffectRenderingInventoryScreen) (Object) this, graphics, x + (wide ? 6 : 7), offset.get() + i, 0)) { - offset.set(offset.get() + offsetDelta); - return; - } +// MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); TODO: PORT +// if (renderer != null && renderer.renderInventoryIcon(mobEffectInstance, (EffectRenderingInventoryScreen) (Object) this, graphics, x + (wide ? 6 : 7), offset.get() + i, 0)) { +// offset.set(offset.get() + offsetDelta); +// return; +// } original.call(graphics, blitX, blitY + offset.get(), z, width, height, sprite); } @Inject(method = "renderLabels", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen;getEffectName(Lnet/minecraft/world/effect/MobEffectInstance;)Lnet/minecraft/network/chat/Component;")) private void renderCustomInventoryText(GuiGraphics graphics, int x, int height, Iterable statusEffects, CallbackInfo ci, @Local(index = 7) MobEffectInstance mobEffectInstance, @Local(index = 5) int i, @Share("custom") LocalRef cancelled) { - MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); - if (renderer != null && renderer.renderInventoryText(mobEffectInstance, (EffectRenderingInventoryScreen) (Object) this, graphics, x, i, 0)) - cancelled.set(true); - else - cancelled.set(false); +// MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); TODO: PORT +// if (renderer != null && renderer.renderInventoryText(mobEffectInstance, (EffectRenderingInventoryScreen) (Object) this, graphics, x, i, 0)) +// cancelled.set(true); +// else +// cancelled.set(false); } @WrapWithCondition(method = "renderLabels", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;III)I")) diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EntityRenderDispatcherMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EntityRenderDispatcherMixin.java index 164fb758e..6a13f9324 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EntityRenderDispatcherMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/EntityRenderDispatcherMixin.java @@ -19,20 +19,20 @@ @Mixin(EntityRenderDispatcher.class) public abstract class EntityRenderDispatcherMixin { @Inject(method = "renderHitbox", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;renderLineBox(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/phys/AABB;FFFF)V", ordinal = 0, shift = At.Shift.AFTER)) - private static void renderMultipartHitboxes(PoseStack pMatrixStack, VertexConsumer pBuffer, Entity entity, float pPartialTicks, CallbackInfo ci) { + private static void renderMultipartHitboxes(PoseStack poseStack, VertexConsumer vertexConsumer, Entity entity, float pPartialTicks, float g, float h, float i, CallbackInfo ci) { if (entity instanceof MultiPartEntity pEntity && pEntity.isMultipartEntity()) { double d0 = -Mth.lerp(pPartialTicks, entity.xOld, entity.getX()); double d1 = -Mth.lerp(pPartialTicks, entity.yOld, entity.getY()); double d2 = -Mth.lerp(pPartialTicks, entity.zOld, entity.getZ()); for(PartEntity part : pEntity.getParts()) { - pMatrixStack.pushPose(); + poseStack.pushPose(); double d3 = d0 + Mth.lerp(pPartialTicks, part.xOld, part.getX()); double d4 = d1 + Mth.lerp(pPartialTicks, part.yOld, part.getY()); double d5 = d2 + Mth.lerp(pPartialTicks, part.zOld, part.getZ()); - pMatrixStack.translate(d3, d4, d5); - LevelRenderer.renderLineBox(pMatrixStack, pBuffer, part.getBoundingBox().move(-part.getX(), -part.getY(), -part.getZ()), 0.25F, 1.0F, 0.0F, 1.0F); - pMatrixStack.popPose(); + poseStack.translate(d3, d4, d5); + LevelRenderer.renderLineBox(poseStack, vertexConsumer, part.getBoundingBox().move(-part.getX(), -part.getY(), -part.getZ()), 0.25F, 1.0F, 0.0F, 1.0F); + poseStack.popPose(); } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/GuiMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/GuiMixin.java index 8350e675d..be43f092e 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/GuiMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/GuiMixin.java @@ -23,18 +23,18 @@ private Iterable shouldRenderEffect(Iterable Collection effectInstances = (Collection) elements; return effectInstances.stream().filter(mobEffectInstance -> { - MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); - if (renderer != null) - return renderer.isVisibleInGui(mobEffectInstance); +// MobEffectRenderer renderer = mobEffectInstance.getEffect().getRenderer(); TODO: PORT +// if (renderer != null) +// return renderer.isVisibleInGui(mobEffectInstance); return true; }).collect(Collectors.toList()); } - @WrapWithCondition(method = "renderEffects", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) - private boolean shouldRenderGuiIcon(List list, Object obj, @Local(index = 0) GuiGraphics graphics, @Local(index = 8) MobEffectInstance mobEffect, @Local(index = 10) int x, @Local(index = 11) int y, @Local(index = 12) float alpha) { - MobEffectRenderer renderer = mobEffect.getEffect().getRenderer(); - if (renderer != null) - return !renderer.renderGuiIcon(mobEffect, (Gui) (Object) this, graphics, x, y, 0, alpha); - return true; - } +// @WrapWithCondition(method = "renderEffects", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) +// private boolean shouldRenderGuiIcon(List list, Object obj, @Local(index = 0) GuiGraphics graphics, @Local(index = 8) MobEffectInstance mobEffect, @Local(index = 10) int x, @Local(index = 11) int y, @Local(index = 12) float alpha) { +// MobEffectRenderer renderer = mobEffect.getEffect().getRenderer(); TODO: PORT +// if (renderer != null) +// return !renderer.renderGuiIcon(mobEffect, (Gui) (Object) this, graphics, x, y, 0, alpha); +// return true; +// } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/LocalPlayerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/LocalPlayerMixin.java index 82d021612..6e05192cb 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/LocalPlayerMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/LocalPlayerMixin.java @@ -1,7 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.client; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; @@ -15,7 +14,6 @@ public abstract class LocalPlayerMixin { @Inject(method = "hurt", at = @At("HEAD")) public void port_lib$attackEvent(DamageSource source, float amount, CallbackInfoReturnable cir) { - LivingAttackEvent event = new LivingAttackEvent((LivingEntity) (Object) this, source, amount); - event.sendEvent(); + EntityHooks.onPlayerAttack((LivingEntity) (Object) this, source, amount); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MinecraftMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MinecraftMixin.java index 92160fe37..ca790fbda 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MinecraftMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MinecraftMixin.java @@ -1,15 +1,23 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.client; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerInteractionEvents; +import com.llamalad7.mixinextras.sugar.Local; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerInteractEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.HitResult; + import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Minecraft.class) @@ -18,8 +26,18 @@ public class MinecraftMixin { @Nullable public LocalPlayer player; + @Shadow + @Nullable + public HitResult hitResult; + + @Inject(method = "startUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 1)) + private void onEmptyClick(CallbackInfo ci, @Local(index = 5) ItemStack itemStack, @Local(index = 4) InteractionHand hand) { + if (itemStack.isEmpty() && (this.hitResult == null || this.hitResult.getType() == HitResult.Type.MISS)) + EntityHooks.onEmptyClick(this.player, hand); + } + @Inject(method = "startAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;resetAttackStrengthTicker()V", shift = At.Shift.AFTER)) private void leftClickEmpty(CallbackInfoReturnable cir) { - new PlayerInteractionEvents.LeftClickEmpty(this.player).sendEvent(); + EntityHooks.onEmptyLeftClick(this.player); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MultiPlayerGameModeMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MultiPlayerGameModeMixin.java index 13d80b9aa..a06f69b86 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MultiPlayerGameModeMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/MultiPlayerGameModeMixin.java @@ -1,34 +1,48 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.client; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import com.llamalad7.mixinextras.sugar.Local; import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityInteractCallback; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerInteractionEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerInteractEvent; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.util.TriState; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.Vec3; + +import org.apache.commons.lang3.mutable.MutableObject; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Environment(EnvType.CLIENT) @Mixin(MultiPlayerGameMode.class) @@ -37,53 +51,79 @@ public class MultiPlayerGameModeMixin { @Final private Minecraft minecraft; - @Shadow - private GameType localPlayerMode; - - @Inject(method = "interact", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ServerboundInteractPacket;createInteractionPacket(Lnet/minecraft/world/entity/Entity;ZLnet/minecraft/world/InteractionHand;)Lnet/minecraft/network/protocol/game/ServerboundInteractPacket;"), cancellable = true) - public void port_lib$onEntityInteract(Player player, Entity target, InteractionHand hand, CallbackInfoReturnable cir) { - if (this.localPlayerMode != GameType.SPECTATOR) { // don't fire for spectators to match non-specific EntityInteract - InteractionResult cancelResult = EntityInteractCallback.EVENT.invoker().onEntityInteract(player, hand, target); - if (cancelResult != null) cir.setReturnValue(cancelResult); - } + @WrapOperation(method = "interactAt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;interactAt(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;")) + public InteractionResult onEntityInteractAt(Entity instance, Player player, Vec3 vec3, InteractionHand hand, Operation original, Player p_105231_, Entity p_105232_, EntityHitResult p_105233_) { + InteractionResult cancelResult = EntityHooks.onInteractEntityAt(player, instance, p_105233_, hand); + if (cancelResult != null) return cancelResult; + return original.call(instance, player, vec3, hand); } @WrapWithCondition(method = "method_41936", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;destroyBlock(Lnet/minecraft/core/BlockPos;)Z")) private boolean wrapBlockLeftClick(MultiPlayerGameMode instance, BlockPos pLoc, BlockPos other, Direction pFace, int i) { - PlayerInteractionEvents.LeftClickBlock event = new PlayerInteractionEvents.LeftClickBlock(this.minecraft.player, pLoc, pFace); - event.sendEvent(); - return !event.isCanceled(); + return !EntityHooks.onLeftClickBlock(this.minecraft.player, pLoc, pFace, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK).isCanceled(); } @WrapWithCondition(method = "method_41935", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;destroyBlock(Lnet/minecraft/core/BlockPos;)Z")) - private boolean continueWrapBlockLeftClick(MultiPlayerGameMode instance, BlockPos pLoc, BlockPos other, Direction pFace, int i) { - PlayerInteractionEvents.LeftClickBlock event = new PlayerInteractionEvents.LeftClickBlock(this.minecraft.player, pLoc, pFace); - event.sendEvent(); - return !event.isCanceled(); + private boolean continueWrapBlockLeftClick(MultiPlayerGameMode instance, BlockPos pLoc, BlockPos other, Direction pFace, int i) { + return !EntityHooks.onLeftClickBlock(this.minecraft.player, pLoc, pFace, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK).isCanceled(); } @Inject(method = "continueDestroyBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/Tutorial;onDestroyBlock(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;F)V", ordinal = 1, shift = At.Shift.AFTER), cancellable = true) private void continueLeftClickBlock(BlockPos pPosBlock, Direction pDirectionFacing, CallbackInfoReturnable cir) { - PlayerInteractionEvents.LeftClickBlock event = new PlayerInteractionEvents.LeftClickBlock(this.minecraft.player, pPosBlock, pDirectionFacing); - event.sendEvent(); - if (event.getUseItem() == BaseEvent.Result.DENY) cir.setReturnValue(true); + if (EntityHooks.onClientMineHold(this.minecraft.player, pPosBlock, pDirectionFacing).getUseItem() == TriState.FALSE) + cir.setReturnValue(true); } - private PlayerInteractionEvents.LeftClickBlock capturedEvent; + private ThreadLocal capturedEvent = new ThreadLocal<>(); @Inject(method = "startDestroyBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;", ordinal = 1)) public void port_lib$startDestroy(BlockPos loc, Direction face, CallbackInfoReturnable cir) { - capturedEvent = new PlayerInteractionEvents.LeftClickBlock(minecraft.player, loc, face); - capturedEvent.sendEvent(); + var e = EntityHooks.onLeftClickBlock(minecraft.player, loc, face, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK); + capturedEvent.set(e); } @WrapWithCondition(method = "method_41930", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;attack(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;)V")) private boolean cancelLeftClickAttack(BlockState blockState, Level level, BlockPos blockPos, Player player) { - return capturedEvent.getUseBlock() != BaseEvent.Result.DENY; + return capturedEvent.get().getUseBlock() != TriState.FALSE; } @Inject(method = "method_41930", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;getDestroyProgress(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F"), cancellable = true) private void cancelUsePacket(BlockState blockState, BlockPos blockPos, Direction direction, int i, CallbackInfoReturnable cir) { - if (capturedEvent.getUseItem() == BaseEvent.Result.DENY) cir.setReturnValue(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, direction, i)); + if (capturedEvent.get().getUseItem() == TriState.FALSE) + cir.setReturnValue(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, direction, i)); + } + + @Inject(method = "method_41929", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;use(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResultHolder;" + ), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) + private void onItemRightClick(InteractionHand hand, Player player, MutableObject result, int sequence, CallbackInfoReturnable cir, ServerboundUseItemPacket packet) { + InteractionResult cancelResult = EntityHooks.onItemRightClick(player, hand); + if (cancelResult != null) { + result.setValue(cancelResult); + cir.setReturnValue(packet); + } + } + + @Inject(method = "method_41929", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;setItemInHand(Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;)V", + shift = At.Shift.AFTER + )) + private void onPlayerDestroyItem(InteractionHand hand, Player player, MutableObject result, int sequence, CallbackInfoReturnable cir, @Local(index = 6) ItemStack destroyed, @Local(index = 8) ItemStack item) { + if (item.isEmpty()) + EntityHooks.onPlayerDestroyItem(player, destroyed, hand); + } + + @Inject(method = "performUseItemOn", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;", + ordinal = 0 + ), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) + private void onRightClickBlock(LocalPlayer player, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable cir, BlockPos pos) { + PlayerInteractEvent.RightClickBlock event = EntityHooks.onRightClickBlock(player, hand, pos, hitResult); + if (event.isCanceled()) { + cir.setReturnValue(event.getCancellationResult()); + } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/RemotePlayerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/RemotePlayerMixin.java index e6351f41c..a1d15371d 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/RemotePlayerMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/client/RemotePlayerMixin.java @@ -1,7 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.client; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.client.player.RemotePlayer; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; @@ -15,7 +14,6 @@ public abstract class RemotePlayerMixin { @Inject(method = "hurt", at = @At("HEAD")) public void port_lib$attackEvent(DamageSource source, float amount, CallbackInfoReturnable cir) { - LivingAttackEvent event = new LivingAttackEvent((LivingEntity) (Object) this, source, amount); - event.sendEvent(); + EntityHooks.onPlayerAttack((LivingEntity) (Object) this, source, amount); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractArrowMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractArrowMixin.java index c81988734..4954d7bc5 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractArrowMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractArrowMixin.java @@ -1,110 +1,50 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; -import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; - -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.entity.projectile.ProjectileDeflection; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(AbstractArrow.class) public abstract class AbstractArrowMixin extends Entity { - @Shadow - public abstract void setPierceLevel(byte b); - - @Unique - private final IntOpenHashSet ignoredEntities = new IntOpenHashSet(); - public AbstractArrowMixin(EntityType variant, Level world) { super(variant, world); } - @Inject(method = "canHitEntity", at = @At("HEAD"), cancellable = true) - private void dontHitIgnored(Entity entity, CallbackInfoReturnable cir) { - if (ignoredEntities.contains(entity.getId())) - cir.setReturnValue(false); - } - - @WrapWithCondition( - method = "tick", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;onHit(Lnet/minecraft/world/phys/HitResult;)V" - ) - ) - private boolean onImpact(AbstractArrow arrow, HitResult result, - @Local LocalRef entityHit, - @Share("isCanceled") LocalBooleanRef isCanceled) { - // note: Forge additionally checks that the result != MISS before running any logic. - // this is likely left over from an earlier version. - // this behavior is intentionally not replicated because 1. compat and 2. it probably doesn't matter. - ProjectileImpactEvent event = new ProjectileImpactEvent(arrow, result); - event.sendEvent(); - - boolean canceled = switch (event.getImpactResult()) { - case SKIP_ENTITY -> { - if (result.getType() != HitResult.Type.ENTITY) { - // didn't hit an entity, do vanilla logic - yield false; - } else { - this.ignoredEntities.add(entityHit.get().getEntity().getId()); - // cancel and skip further processing - entityHit.set(null); - yield true; - } - } - case STOP_AT_CURRENT_NO_DAMAGE -> { - this.discard(); - // cancel and skip further processing - entityHit.set(null); - yield true; - } - case STOP_AT_CURRENT -> { - this.setPierceLevel((byte) 0); - // does not cancel - yield false; - } - case DEFAULT -> false; // don't cancel, do vanilla logic - }; - - if (canceled) { - // need to save this. have to separately cancel the hasImpulse set - isCanceled.set(true); - return false; + @WrapOperation(method = "tick", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;" + )) + private ProjectileDeflection onProjectileImpact(AbstractArrow instance, HitResult hitResult, Operation original, @Share("canceled") LocalBooleanRef canceled, @Share("hasImpulse") LocalBooleanRef lastHasImpulse) { + if (EntityHooks.onProjectileImpact(instance, hitResult)) { + canceled.set(true); + lastHasImpulse.set(this.hasImpulse); + return ProjectileDeflection.REVERSE; // Return anything that isn't none } + canceled.set(false); + return original.call(instance, hitResult); + } - return true; - } - - @WrapWithCondition( - method = "tick", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;hasImpulse:Z" - ) - ) - private boolean handleImpulse(AbstractArrow instance, boolean value, - @Share("isCanceled") LocalBooleanRef isCanceled) { - boolean canceled = isCanceled.get(); - isCanceled.set(false); // reset, don't leak state - return !canceled; + @Inject(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;hasImpulse:Z", shift = At.Shift.AFTER)) + private void restoreHasImpulse(CallbackInfo ci, @Share("canceled") LocalBooleanRef canceled, @Share("hasImpulse") LocalBooleanRef lastHasImpulse) { + if (canceled.get()) + this.hasImpulse = lastHasImpulse.get(); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHorseMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHorseMixin.java index 4dc4c4465..41e98cf9c 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHorseMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHorseMixin.java @@ -1,7 +1,7 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.world.entity.LivingEntity; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.world.entity.animal.horse.AbstractHorse; import net.minecraft.world.phys.Vec3; @@ -15,6 +15,6 @@ public class AbstractHorseMixin { @Inject(method = "executeRidersJump", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/animal/horse/AbstractHorse;hasImpulse:Z", shift = At.Shift.AFTER)) private void onHorseJump(float f, Vec3 vec3, CallbackInfo ci) { - new LivingEntityEvents.LivingJumpEvent((LivingEntity) (Object) this).sendEvent(); + EntityHooks.onLivingJump(MixinHelper.cast(this)); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHurtingProjectileMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHurtingProjectileMixin.java index ecca4952b..6aa4b2122 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHurtingProjectileMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractHurtingProjectileMixin.java @@ -1,20 +1,19 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; - -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; import net.minecraft.world.phys.HitResult; @Mixin(AbstractHurtingProjectile.class) public class AbstractHurtingProjectileMixin { - @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;onHit(Lnet/minecraft/world/phys/HitResult;)V")) - private boolean onImpact(AbstractHurtingProjectile projectile, HitResult result) { - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); + @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;")) + private boolean onProjectileImpact(AbstractHurtingProjectile projectile, HitResult result) { + return !EntityHooks.onProjectileImpact(projectile, result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractMinecartMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractMinecartMixin.java index 64d229b55..488659666 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractMinecartMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/AbstractMinecartMixin.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.extensions.AbstractMinecartExtensions; +import io.github.fabricators_of_create.porting_lib.entity.ext.AbstractMinecartExt; import net.minecraft.core.BlockPos; import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(AbstractMinecart.class) -public abstract class AbstractMinecartMixin extends Entity implements AbstractMinecartExtensions { +public abstract class AbstractMinecartMixin extends Entity implements AbstractMinecartExt { @Shadow protected abstract double getMaxSpeed(); diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/BundlePacketMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/BundlePacketMixin.java index 73854e387..6ce220aa0 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/BundlePacketMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/BundlePacketMixin.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.List; -import io.github.fabricators_of_create.porting_lib.entity.IEntityAdditionalSpawnData; +import io.github.fabricators_of_create.porting_lib.entity.IEntityWithComplexSpawn; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -14,7 +14,7 @@ import net.minecraft.network.protocol.Packet; /** - * this is needed for {@link IEntityAdditionalSpawnData} to work properly on dedicated servers, since it ends up nesting bundle packets. + * this is needed for {@link IEntityWithComplexSpawn} to work properly on dedicated servers, since it ends up nesting bundle packets. */ @Mixin(BundlePacket.class) public class BundlePacketMixin { diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/CatSpawnerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/CatSpawnerMixin.java deleted file mode 100644 index 3f58fb34b..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/CatSpawnerMixin.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.MobSpawnType; -import net.minecraft.world.entity.animal.Cat; -import net.minecraft.world.entity.npc.CatSpawner; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(CatSpawner.class) -public class CatSpawnerMixin { - @Inject(method = "spawnCat", at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/animal/Cat;finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/entity/SpawnGroupData;", - shift = At.Shift.BEFORE), - locals = LocalCapture.CAPTURE_FAILHARD, - cancellable = true - ) - public void port_lib$checkSpawn(BlockPos blockPos, ServerLevel serverLevel, CallbackInfoReturnable cir, Cat cat) { - if (LivingEntityEvents.CHECK_SPAWN.invoker().onCheckSpawn(cat, serverLevel, blockPos.getX(), blockPos.getY(), blockPos.getZ(), null, MobSpawnType.NATURAL)) - cir.setReturnValue(0); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ChorusFruitItemMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ChorusFruitItemMixin.java index 686479428..e191d6f4e 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ChorusFruitItemMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ChorusFruitItemMixin.java @@ -2,27 +2,39 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ChorusFruitItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ChorusFruitItem.class) public abstract class ChorusFruitItemMixin { - @WrapOperation( - method = "finishUsingItem", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;randomTeleport(DDDZ)Z") - ) - private boolean port_lib$finishUsingItem(LivingEntity instance, double x, double y, double z, boolean particleEffects, Operation original) { - EntityEvents.Teleport.EntityTeleportEvent event = new EntityEvents.Teleport.EntityTeleportEvent(instance, x, y, z); - event.sendEvent(); - if (event.isCanceled()) { - return false; - } else { - return original.call(instance, x, y, z, particleEffects); - } + @WrapOperation(method = "finishUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;randomTeleport(DDDZ)Z")) + private boolean onChorusFruitTeleport(LivingEntity instance, double x, double y, double z, boolean fireEvent, Operation original, @Share("event") LocalRef eventRef) { + EntityTeleportEvent.ChorusFruit event = EntityHooks.onChorusFruitTeleport(instance, x, y, z); + eventRef.set(event); + if (!event.isCanceled()) + return original.call(instance, event.getTargetX(), event.getTargetY(), event.getTargetZ(), fireEvent); + return true; + } + + @Inject(method = "finishUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;gameEvent(Lnet/minecraft/core/Holder;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/level/gameevent/GameEvent$Context;)V"), cancellable = true) + private void shouldCancel(ItemStack itemStack, Level level, LivingEntity livingEntity, CallbackInfoReturnable cir, @Local(index = 4) ItemStack result, @Share("event") LocalRef eventRef) { + if (eventRef.get().isCanceled()) + cir.setReturnValue(result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EnderManMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EnderManMixin.java index 0c3ff4182..2d4331ec3 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EnderManMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EnderManMixin.java @@ -1,6 +1,14 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.monster.EnderMan; import net.minecraft.world.entity.monster.Monster; @@ -8,8 +16,6 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(EnderMan.class) public abstract class EnderManMixin extends Monster { @@ -17,11 +23,11 @@ protected EnderManMixin(EntityType entityType, Level level) { super(entityType, level); } - @Inject(method = "teleport(DDD)Z", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/EnderMan;randomTeleport(DDDZ)Z")) - private void port_lib$teleport(double x, double y, double z, CallbackInfoReturnable cir) { - EntityEvents.Teleport.EntityTeleportEvent event = new EntityEvents.Teleport.EntityTeleportEvent(this, x, y, z); - event.sendEvent(); - if (event.isCanceled()) - cir.setReturnValue(false); + @WrapOperation(method = "teleport(DDD)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/EnderMan;randomTeleport(DDDZ)Z")) + private boolean onEnderTeleport(EnderMan instance, double x, double y, double z, boolean fireEvent, Operation original) { + EntityTeleportEvent.EnderEntity event = EntityHooks.onEnderTeleport(instance, x, y, z); + if (!event.isCanceled()) + return original.call(instance, event.getTargetX(), event.getTargetY(), event.getTargetZ(), fireEvent); + return false; } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EntityMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EntityMixin.java index 1cd707b0d..a02195abc 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EntityMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/EntityMixin.java @@ -2,13 +2,14 @@ import java.util.Collection; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -16,17 +17,12 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import io.github.fabricators_of_create.porting_lib.entity.ITeleporter; import io.github.fabricators_of_create.porting_lib.entity.events.EntityDataEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityMountEvents; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvent; import io.github.fabricators_of_create.porting_lib.entity.events.MinecartEvents; -import io.github.fabricators_of_create.porting_lib.entity.extensions.EntityExtensions; +import io.github.fabricators_of_create.porting_lib.entity.ext.EntityExt; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; @@ -34,33 +30,25 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.level.Level; -import net.minecraft.world.level.portal.PortalInfo; @Mixin(Entity.class) -public abstract class EntityMixin implements EntityExtensions { +public abstract class EntityMixin implements EntityExt { @Unique private Collection port_lib$captureDrops = null; - @WrapOperation(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getEyeHeight(Lnet/minecraft/world/entity/Pose;Lnet/minecraft/world/entity/EntityDimensions;)F")) - private float entitySizeConstructEvent(Entity instance, Pose pose, EntityDimensions dimensions, Operation original) { - EntityEvents.Size sizeEvent = new EntityEvents.Size((Entity) (Object) this, Pose.STANDING, this.dimensions, original.call(instance, pose, dimensions)); - sizeEvent.sendEvent(); + @Inject(method = "", at = @At("TAIL")) + private void entitySizeConstructEvent(EntityType entityType, Level level, CallbackInfo ci) { + EntityEvent.Size sizeEvent = EntityHooks.getEntitySizeForge((Entity) (Object) this, Pose.STANDING, this.dimensions, this.eyeHeight); this.dimensions = sizeEvent.getNewSize(); - return sizeEvent.getNewEyeHeight(); + this.eyeHeight = sizeEvent.getNewEyeHeight(); + new EntityEvent.EntityConstructing((Entity) (Object) this).sendEvent(); } - @WrapOperation(method = "refreshDimensions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getEyeHeight(Lnet/minecraft/world/entity/Pose;Lnet/minecraft/world/entity/EntityDimensions;)F")) - private float entitySizeEvent(Entity instance, Pose pose, EntityDimensions dimensions, Operation original, @Local(index = 3) EntityDimensions old, @Share("size") LocalRef event) { - EntityEvents.Size sizeEvent = new EntityEvents.Size((Entity) (Object) this, pose, this.dimensions, old, getEyeHeight(), original.call(instance, pose, dimensions)); - event.set(sizeEvent); - sizeEvent.sendEvent(); - this.dimensions = sizeEvent.getNewSize(); - return sizeEvent.getNewEyeHeight(); - } - - @ModifyVariable(method = "refreshDimensions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;reapplyPosition()V"), index = 3) - private EntityDimensions modifyDimensions(EntityDimensions value, @Share("size") LocalRef event) { - return event.get().getNewSize(); + @WrapOperation(method = "refreshDimensions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getDimensions(Lnet/minecraft/world/entity/Pose;)Lnet/minecraft/world/entity/EntityDimensions;")) + private EntityDimensions entitySizeEvent(Entity instance, Pose pose, Operation original, @Local(index = 1) EntityDimensions old) { + EntityDimensions newD = original.call(instance, pose); + EntityEvent.Size sizeEvent = EntityHooks.getEntitySizeForge(instance, pose, old, newD, newD.eyeHeight()); + return sizeEvent.getNewSize(); } // CAPTURE DROPS @@ -98,114 +86,52 @@ public Collection captureDrops(Collection value) { @Nullable private Entity vehicle; - @Shadow - private float eyeHeight; - @Shadow private Level level; - @Shadow - public abstract void unRide(); - - @Shadow - protected abstract void removeAfterChangingDimensions(); - - @Shadow - public abstract boolean isRemoved(); - - @Shadow - @Nullable - protected abstract PortalInfo findDimensionEntryPoint(ServerLevel destination); - @Shadow public abstract EntityType getType(); - @Shadow - private float yRot; - @Shadow public abstract int getId(); - @Shadow - public abstract Pose getPose(); - @Shadow private EntityDimensions dimensions; @Shadow - protected abstract float getEyeHeight(Pose pose, EntityDimensions dimensions); + public abstract float getEyeHeight(); @Shadow - public abstract float getEyeHeight(); + private float eyeHeight; @Inject( method = "startRiding(Lnet/minecraft/world/entity/Entity;Z)Z", at = @At( value = "INVOKE", - target = "Lnet/minecraft/world/entity/Entity;isPassenger()Z", + target = "Lnet/minecraft/world/entity/Entity;canRide(Lnet/minecraft/world/entity/Entity;)Z", shift = At.Shift.BEFORE ), cancellable = true ) public void port_lib$startRiding(Entity entity, boolean bl, CallbackInfoReturnable cir) { - if (!EntityMountEvents.MOUNT.invoker().canStartRiding(entity, (Entity) (Object) this)) { + if (!EntityHooks.canMountEntity((Entity) (Object) this, entity, true)) cir.setReturnValue(false); - } } @Inject(method = "removeVehicle", at = @At(value = "CONSTANT", args = "nullValue=true"), cancellable = true) public void port_lib$removeRidingEntity(CallbackInfo ci) { - if (!EntityMountEvents.DISMOUNT.invoker().onStopRiding(this.vehicle, (Entity) (Object) this)) { + if (!EntityHooks.canMountEntity((Entity) (Object) this, this.vehicle, false)) ci.cancel(); - } } @Inject(method = "remove", at = @At("TAIL")) public void port_lib$onEntityRemove(Entity.RemovalReason reason, CallbackInfo ci) { - EntityEvents.ON_REMOVE.invoker().onRemove((Entity) (Object) this, reason); +// EntityEvent.ON_REMOVE.invoker().onRemove((Entity) (Object) this, reason); TODO: PORT if ((Object) this instanceof AbstractMinecart cart) { MinecartEvents.REMOVE.invoker().minecartRemove(cart, level); } } - @Unique - @Override - public Entity changeDimension(ServerLevel p_20118_, ITeleporter teleporter) { - if (this.level instanceof ServerLevel && !this.isRemoved()) { - this.level.getProfiler().push("changeDimension"); - this.unRide(); - this.level.getProfiler().push("reposition"); - PortalInfo portalinfo = teleporter.getPortalInfo((Entity) (Object) this, p_20118_, this::findDimensionEntryPoint); - if (portalinfo == null) { - return null; - } else { - Entity transportedEntity = teleporter.placeEntity((Entity) (Object) this, (ServerLevel) this.level, p_20118_, this.yRot, spawnPortal -> { //Forge: Start vanilla logic - this.level.getProfiler().popPush("reloading"); - Entity entity = this.getType().create(p_20118_); - if (entity != null) { - entity.restoreFrom((Entity) (Object) this); - entity.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z, portalinfo.yRot, entity.getXRot()); - entity.setDeltaMovement(portalinfo.speed); - p_20118_.addDuringTeleport(entity); - if (spawnPortal && p_20118_.dimension() == Level.END) { - ServerLevel.makeObsidianPlatform(p_20118_); - } - } - return entity; - }); //Forge: End vanilla logic - - this.removeAfterChangingDimensions(); - this.level.getProfiler().pop(); - ((ServerLevel) this.level).resetEmptyTime(); - p_20118_.resetEmptyTime(); - this.level.getProfiler().pop(); - return transportedEntity; - } - } else { - return null; - } - } - // custom data @Unique @@ -255,4 +181,12 @@ public void afterSave(CompoundTag nbt, CallbackInfoReturnable cir) public void afterLoad(CompoundTag nbt, CallbackInfo ci) { EntityDataEvents.LOAD.invoker().onLoad((Entity) (Object) this, nbt); } + + @WrapOperation(method = "rideTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;tick()V")) + private void preEntityTick(Entity instance, Operation original) { + if (!EntityHooks.fireEntityTickPre(instance).isCanceled()) { + original.call(instance); + EntityHooks.fireEntityTickPost(instance); + } + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ExperienceOrbMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ExperienceOrbMixin.java index ea5d4cb24..40ab4962e 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ExperienceOrbMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ExperienceOrbMixin.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerEvents; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerXpEvent; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ExperienceOrb; @@ -8,7 +8,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -20,9 +19,9 @@ public ExperienceOrbMixin(EntityType variant, Level world) { super(variant, world); } - @Inject(method = "playerTouch", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, ordinal = 0), cancellable = true) + @Inject(method = "playerTouch", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;takeXpDelay:I", ordinal = 1), cancellable = true) private void port_lib$onPlayerPickupXp(Player player, CallbackInfo ci) { - PlayerEvents.PickupXp pickupXp = new PlayerEvents.PickupXp(player, (ExperienceOrb) (Object) this); + var pickupXp = new PlayerXpEvent.PickupXp(player, (ExperienceOrb) (Object) this); pickupXp.sendEvent(); if (pickupXp.isCanceled()) ci.cancel(); diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FireworkRocketEntityMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FireworkRocketEntityMixin.java index a7239e5c7..68de63371 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FireworkRocketEntityMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FireworkRocketEntityMixin.java @@ -1,22 +1,22 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; - import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.phys.HitResult; @Mixin(FireworkRocketEntity.class) public class FireworkRocketEntityMixin { - @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FireworkRocketEntity;onHit(Lnet/minecraft/world/phys/HitResult;)V")) - private boolean onImpact(FireworkRocketEntity projectile, HitResult result) { - if (result.getType() == HitResult.Type.MISS) - return true; - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); - } +// @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FireworkRocketEntity;onHit(Lnet/minecraft/world/phys/HitResult;)V")) +// private boolean onImpact(FireworkRocketEntity projectile, HitResult result) { TODO: PORT +// if (result.getType() == HitResult.Type.MISS) +// return true; +// ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); +// event.sendEvent(); +// return !event.isCanceled(); +// } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FishingHookMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FishingHookMixin.java index 0933b4913..7aed93ce6 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FishingHookMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FishingHookMixin.java @@ -1,9 +1,8 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; -import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.world.entity.projectile.FishingHook; import net.minecraft.world.phys.HitResult; @@ -13,12 +12,8 @@ @Mixin(FishingHook.class) public class FishingHookMixin { - @WrapWithCondition(method = "checkCollision", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FishingHook;onHit(Lnet/minecraft/world/phys/HitResult;)V")) - private boolean onImpact(FishingHook projectile, HitResult result) { - if (result.getType() == HitResult.Type.MISS) - return true; - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); + @WrapWithCondition(method = "checkCollision", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/FishingHook;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;")) + private boolean onProjectileImpact(FishingHook projectile, HitResult result) { + return result.getType() == HitResult.Type.MISS || !EntityHooks.onProjectileImpact(projectile, result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FurnaceResultSlotMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FurnaceResultSlotMixin.java new file mode 100644 index 000000000..88265b9d5 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/FurnaceResultSlotMixin.java @@ -0,0 +1,26 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.FurnaceResultSlot; + +import net.minecraft.world.item.ItemStack; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(FurnaceResultSlot.class) +public class FurnaceResultSlotMixin { + @Shadow + @Final + private Player player; + + @Inject(method = "checkTakeAchievements", at = @At("TAIL")) + private void onItemSmelted(ItemStack itemStack, CallbackInfo ci) { + EntityHooks.firePlayerSmeltedEvent(this.player, itemStack); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ItemMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ItemMixin.java index aa85a6486..446970048 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ItemMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ItemMixin.java @@ -1,10 +1,10 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.extensions.ItemExtensions; +import io.github.fabricators_of_create.porting_lib.entity.ext.ItemExt; import net.minecraft.world.item.Item; import org.spongepowered.asm.mixin.Mixin; @Mixin(Item.class) -public class ItemMixin implements ItemExtensions { +public class ItemMixin implements ItemExt { } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LevelMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LevelMixin.java index c8972ee6c..d52aa664a 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LevelMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LevelMixin.java @@ -1,7 +1,7 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; import io.github.fabricators_of_create.porting_lib.entity.PartEntity; -import io.github.fabricators_of_create.porting_lib.entity.extensions.LevelExtensions; +import io.github.fabricators_of_create.porting_lib.entity.ext.LevelExt; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.world.entity.Entity; @@ -22,7 +22,7 @@ import java.util.function.Predicate; @Mixin(value = Level.class, priority = 1100) // need to apply after lithium -public class LevelMixin implements LevelExtensions { +public class LevelMixin implements LevelExt { @Unique final Int2ObjectMap> port_lib$multiparts = new Int2ObjectOpenHashMap<>(); @@ -31,7 +31,7 @@ public class LevelMixin implements LevelExtensions { at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD ) - private void port_lib$appendPartEntitiesPredicate(@Nullable Entity entity, AABB area, Predicate predicate, CallbackInfoReturnable> cir, List list) { + private void appendPartEntitiesPredicate(@Nullable Entity entity, AABB area, Predicate predicate, CallbackInfoReturnable> cir, List list) { for (PartEntity p : this.getPartEntities()) { if (p != entity && p.getBoundingBox().intersects(area) && predicate.test(p)) { list.add(p); @@ -44,7 +44,7 @@ public class LevelMixin implements LevelExtensions { at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD ) - private void port_lib$appendPartEntitiesTypeTest(EntityTypeTest test, AABB area, Predicate predicate, CallbackInfoReturnable> cir, List list) { + private void appendPartEntitiesTypeTest(EntityTypeTest test, AABB area, Predicate predicate, CallbackInfoReturnable> cir, List list) { for (PartEntity p : this.getPartEntities()) { T t = test.tryCast(p); if (t != null && t.getBoundingBox().intersects(area) && predicate.test(t)) { diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LightningBoltMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LightningBoltMixin.java index 43a50e659..577ad6545 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LightningBoltMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LightningBoltMixin.java @@ -1,9 +1,9 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityStruckByLightningEvent; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LightningBolt; @@ -15,8 +15,6 @@ public class LightningBoltMixin { @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;thunderHit(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LightningBolt;)V")) private boolean shouldStrikeEntity(Entity entity, ServerLevel level, LightningBolt lightningBolt) { - var event = new EntityStruckByLightningEvent(entity, lightningBolt); - event.sendEvent(); - return !event.isCanceled(); + return !EntityHooks.onEntityStruckByLightning(entity, MixinHelper.cast(this)); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LivingEntityMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LivingEntityMixin.java index 6c3ad5b23..68ebed359 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LivingEntityMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LivingEntityMixin.java @@ -3,30 +3,40 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.Map; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.ShieldBlockEvent; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingKnockBackEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.ShieldBlockEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDamageEvent; - -import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingHurtEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingFallEvent; import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; +import io.github.fabricators_of_create.porting_lib.entity.ext.LivingEntityExt; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -36,16 +46,10 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.invoke.arg.Args; import com.llamalad7.mixinextras.injector.ModifyReturnValue; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingDeathEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents.Fall.FallEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityUseItemEvents; -import io.github.fabricators_of_create.porting_lib.entity.extensions.EntityExtensions; import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -57,7 +61,7 @@ import net.minecraft.world.level.Level; @Mixin(LivingEntity.class) -public abstract class LivingEntityMixin extends Entity implements EntityExtensions { +public abstract class LivingEntityMixin extends Entity implements LivingEntityExt { @Shadow protected int lastHurtByPlayerTime; @Shadow @@ -70,60 +74,47 @@ public abstract class LivingEntityMixin extends Entity implements EntityExtensio @Shadow public abstract int getUseItemRemainingTicks(); - private int port_lib$lootingLevel; + @Shadow + @Final + private Map, MobEffectInstance> activeEffects; + + @Shadow + protected abstract void onEffectRemoved(MobEffectInstance mobEffectInstance); + + @Shadow + private boolean effectsDirty; + + @Shadow + protected ItemStack useItem; + + @Shadow + public abstract InteractionHand getUsedItemHand(); + + @Shadow + protected int useItemRemaining; public LivingEntityMixin(EntityType variant, Level world) { super(variant, world); } - @ModifyVariable( - method = "dropAllDeathLoot", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/entity/LivingEntity;lastHurtByPlayerTime:I" - ) - ) - private int port_lib$grabLootingLevel(int lootingLevel) { - port_lib$lootingLevel = lootingLevel; - return lootingLevel; - } - - @ModifyArgs( - method = "dropAllDeathLoot", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;dropCustomDeathLoot(Lnet/minecraft/world/damagesource/DamageSource;IZ)V" - ) - ) - private void port_lib$modifyLootingLevel(Args args) { - DamageSource source = args.get(0); - int originalLevel = args.get(1); - boolean recentlyHit = args.get(2); - int modifiedLevel = LivingEntityEvents.LOOTING_LEVEL.invoker().modifyLootingLevel(source, (LivingEntity) (Object) this, originalLevel, recentlyHit); - args.set(1, modifiedLevel); - } - @Inject(method = "dropAllDeathLoot", at = @At("HEAD")) - private void port_lib$startCapturingDrops(DamageSource damageSource, CallbackInfo ci) { + private void port_lib$startCapturingDrops(ServerLevel serverLevel, DamageSource damageSource, CallbackInfo ci) { captureDrops(new ArrayList<>()); } - @Inject(method = "dropAllDeathLoot", at = @At("RETURN")) - private void port_lib$dropCapturedDrops(DamageSource source, CallbackInfo ci) { + @Inject(method = "dropAllDeathLoot", at = @At("TAIL")) + private void port_lib$dropCapturedDrops(ServerLevel level, DamageSource source, CallbackInfo ci) { Collection drops = this.captureDrops(null); - boolean cancelled = LivingEntityEvents.DROPS.invoker().onLivingEntityDrops( - (LivingEntity) (Object) this, source, drops, port_lib$lootingLevel, lastHurtByPlayerTime > 0 - ); - if (!cancelled) + if (!EntityHooks.onLivingDrops(MixinHelper.cast(this), source, drops, lastHurtByPlayerTime > 0)) drops.forEach(e -> level().addFreshEntity(e)); } @Unique - private FallEvent port_lib$currentFallEvent = null; + private LivingFallEvent port_lib$currentFallEvent = null; @Inject(method = "causeFallDamage", at = @At("HEAD"), cancellable = true) public void port_lib$cancelFall(float fallDistance, float multiplier, DamageSource source, CallbackInfoReturnable cir) { - port_lib$currentFallEvent = new FallEvent((LivingEntity) (Object) this, source, fallDistance, multiplier); + port_lib$currentFallEvent = new LivingFallEvent((LivingEntity) (Object) this, fallDistance, multiplier); port_lib$currentFallEvent.sendEvent(); if (port_lib$currentFallEvent.isCanceled()) { cir.setReturnValue(true); @@ -148,77 +139,89 @@ public LivingEntityMixin(EntityType variant, Level world) { @ModifyArgs(method = "dropExperience", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ExperienceOrb;award(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/phys/Vec3;I)V")) private void create$dropExperience(Args args) { - int amount = args.get(2); - int newAmount = LivingEntityEvents.EXPERIENCE_DROP.invoker().onLivingEntityExperienceDrop(amount, lastHurtByPlayer, (LivingEntity) (Object) this); - if (amount != newAmount) args.set(2, newAmount); + int reward = args.get(2); + int newReward = EntityHooks.getExperienceDrop(MixinHelper.cast(this), this.lastHurtByPlayer, reward); + if (reward != newReward) args.set(2, newReward); } - @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;tick()V"), cancellable = true) - private void tick(CallbackInfo ci) { - LivingEntityEvents.LivingTickEvent event = new LivingEntityEvents.LivingTickEvent((LivingEntity) (Object) this); - event.sendEvent(); - if (event.isCanceled()) - ci.cancel(); + @ModifyVariable(method = "knockback", at = @At("HEAD"), ordinal = 0, argsOnly = true) + private double modifyKnockbackStrength(double strength, double ogstrength, double xRatio, double zRatio, @Share("event") LocalRef eventRef) { + LivingKnockBackEvent event = EntityHooks.onLivingKnockBack(MixinHelper.cast(this), (float) strength, xRatio, zRatio); + eventRef.set(event); + if (!event.isCanceled() && event.getOriginalStrength() != event.getStrength()) { + return event.getStrength(); + } + return strength; } - @ModifyVariable(method = "knockback", at = @At("STORE"), ordinal = 0, argsOnly = true) - private double port_lib$takeKnockback(double f) { - if (lastHurtByPlayer != null) - return LivingEntityEvents.KNOCKBACK_STRENGTH.invoker().onLivingEntityTakeKnockback(f, lastHurtByPlayer); + @ModifyVariable(method = "knockback", at = @At("HEAD"), ordinal = 1, argsOnly = true) + private double modifyRatioX(double ratioX, @Share("event") LocalRef eventRef) { + var event = eventRef.get(); + if (event.getOriginalRatioX() != event.getRatioX()) + return event.getRatioX(); + return ratioX; + } - return f; + @ModifyVariable(method = "knockback", at = @At("HEAD"), ordinal = 2, argsOnly = true) + private double modifyRatioZ(double ratioZ, @Share("event") LocalRef eventRef) { + var event = eventRef.get(); + if (event.getOriginalRatioZ() != event.getRatioZ()) + return event.getRatioZ(); + return ratioZ; } - @ModifyVariable(method = "hurt", at = @At("HEAD"), argsOnly = true) - private float port_lib$onHurt(float amount, DamageSource source, float amount2) { - return LivingEntityEvents.HURT.invoker().onHurt(source, (LivingEntity) (Object) this, amount); + @Inject(method = "knockback", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getAttributeValue(Lnet/minecraft/core/Holder;)D"), cancellable = true) + private void shouldCancelKnockback(double strength, double xRatio, double zRatio, CallbackInfo ci, @Share("event") LocalRef eventRef) { + if (eventRef.get().isCanceled()) + ci.cancel(); + } + + @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) + private void onHurt(DamageSource damageSource, float amount, CallbackInfoReturnable cir) { + if (!EntityHooks.onLivingAttack(MixinHelper.cast(this), damageSource, amount)) + cir.setReturnValue(false); } - @Inject(method = "jumpFromGround", at = @At("TAIL")) + @Inject(method = "jumpFromGround", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;hasImpulse:Z", shift = At.Shift.AFTER)) public void onJump(CallbackInfo ci) { - new LivingEntityEvents.LivingJumpEvent((LivingEntity) (Object) this).sendEvent(); + EntityHooks.onLivingJump(MixinHelper.cast(this)); } - @Inject(method = "completeUsingItem", at = @At(value = "INVOKE", shift = At.Shift.BY, by = 2, target = "Lnet/minecraft/world/item/ItemStack;finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;"), - locals = LocalCapture.CAPTURE_FAILHARD) - public void port_lib$onFinishUsing(CallbackInfo ci, InteractionHand hand, ItemStack result) { - LivingEntityUseItemEvents.LIVING_USE_ITEM_FINISH.invoker().onUseItem((LivingEntity) (Object) this, this.getUseItem().copy(), getUseItemRemainingTicks(), result); + @WrapOperation(method = "completeUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;finishUsingItem(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/item/ItemStack;")) + public ItemStack onFinishUsing(ItemStack instance, Level level, LivingEntity livingEntity, Operation original) { + return EntityHooks.onItemUseFinish((LivingEntity) (Object) this, getUseItem().copy(), getUseItemRemainingTicks(), original.call(instance, level, livingEntity)); } - @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) - public void port_lib$attackEvent(DamageSource source, float amount, CallbackInfoReturnable cir) { - if (!((Object) this instanceof Player)) { - LivingAttackEvent event = new LivingAttackEvent((LivingEntity) (Object) this, source, amount); - event.sendEvent(); - if (event.isCanceled()) - cir.setReturnValue(false); + // We use wrap operation here because we want to fire an additional event inside the event check. + @WrapOperation(method = "releaseUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;releaseUsing(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;I)V")) + private void onStopUsingItem(ItemStack instance, Level level, LivingEntity livingEntity, int useItemRemaining, Operation original) { + if (!EntityHooks.onUseItemStop((LivingEntity) (Object) this, useItem, this.getUseItemRemainingTicks())) { + ItemStack copy = (Object) this instanceof Player ? useItem.copy() : null; + original.call(instance, level, livingEntity, useItemRemaining); + if (copy != null && useItem.isEmpty()) + EntityHooks.onPlayerDestroyItem((Player) (Object) this, copy, getUsedItemHand()); } } @ModifyReturnValue(method = "getVisibilityPercent", at = @At("RETURN")) private double modifyVisibility(double original, @javax.annotation.Nullable Entity pLookingEntity) { - LivingEntityEvents.LivingVisibilityEvent event = new LivingEntityEvents.LivingVisibilityEvent((LivingEntity) (Object) this, pLookingEntity, original); - event.sendEvent(); - return Math.max(0, event.getVisibilityModifier()); + return EntityHooks.getEntityVisibilityMultiplier(MixinHelper.cast(this), pLookingEntity, original); } @Inject(method = "die", at = @At("HEAD"), cancellable = true) private void onLivingDeath(DamageSource cause, CallbackInfo ci) { - LivingDeathEvent event = new LivingDeathEvent((LivingEntity) (Object) this, cause); - event.sendEvent(); - if (event.isCanceled()) + if (EntityHooks.onLivingDeath(MixinHelper.cast(this), cause)) ci.cancel(); } @ModifyExpressionValue(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isDamageSourceBlocked(Lnet/minecraft/world/damagesource/DamageSource;)Z")) private boolean shieldBlockEvent(boolean original, DamageSource pSource, float pAmount, @Share("shield_block") LocalRef eventRef) { if (original) { - ShieldBlockEvent event = new ShieldBlockEvent((LivingEntity) (Object) this, pSource, pAmount); - event.sendEvent(); - eventRef.set(event); - return !event.isCanceled(); + ShieldBlockEvent ev = EntityHooks.onShieldBlock((LivingEntity) (Object) this, pSource, pAmount); + eventRef.set(ev); + return !ev.isCanceled(); } - return original; + return false; } @WrapWithCondition(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;hurtCurrentlyUsedShield(F)V")) @@ -238,56 +241,66 @@ private float modifyActualDamage(float value, DamageSource pSource, float pAmoun return pAmount - eventRef.get().getBlockedDamage(); } - @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 0), index = 2) - private float livingHurtEvent(float value, DamageSource pDamageSource, @Share("hurt") LocalRef eventRef) { - LivingHurtEvent event = new LivingHurtEvent((LivingEntity) (Object) this, pDamageSource, value); - eventRef.set(event); - event.sendEvent(); - if (event.isCanceled()) - return 0; - return event.getAmount(); + @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 0), index = 2, argsOnly = true) + private float livingHurtEvent(float amount, DamageSource pDamageSource) { + return EntityHooks.onLivingHurt((LivingEntity) (Object) this, pDamageSource, amount); } @Inject(method = "actuallyHurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getDamageAfterArmorAbsorb(Lnet/minecraft/world/damagesource/DamageSource;F)F"), cancellable = true) - private void shouldCancelHurt(DamageSource damageSource, float f, CallbackInfo ci, @Share("hurt") LocalRef eventRef) { - if (eventRef.get().getAmount() <= 0) + private void shouldCancelHurt(DamageSource damageSource, float amount, CallbackInfo ci) { + if (amount <= 0) ci.cancel(); } - @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 6), index = 2) - private float livingDamageEvent(float value, DamageSource pDamageSource) { - LivingDamageEvent event = new LivingDamageEvent((LivingEntity) (Object) this, pDamageSource, value); - event.sendEvent(); - if (event.isCanceled()) - return 0; - return event.getAmount(); - } +// @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 6), index = 2) TODO: PORT +// private float livingDamageEvent(float value, DamageSource pDamageSource) { +// LivingDamageEvent event = new LivingDamageEvent((LivingEntity) (Object) this, pDamageSource, value); +// event.sendEvent(); +// if (event.isCanceled()) +// return 0; +// return event.getAmount(); +// } @Inject(method = "removeEffect", at = @At("HEAD"), cancellable = true) - private void onRemoveEffect(MobEffect effect, CallbackInfoReturnable cir) { - var event = new MobEffectEvent.Remove((LivingEntity) (Object) this, effect); - event.sendEvent(); - if (event.isCanceled()) cir.setReturnValue(false); + private void onRemoveEffect(Holder effect, CallbackInfoReturnable cir) { + if (EntityHooks.onEffectRemoved((LivingEntity) (Object) this, effect, null)) + cir.setReturnValue(false); } @WrapWithCondition(method = "removeAllEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;onEffectRemoved(Lnet/minecraft/world/effect/MobEffectInstance;)V")) - private boolean onRemoveAllEffectEvent(LivingEntity instance, MobEffectInstance effect, @Share("event") LocalRef eventRef) { - var event = new MobEffectEvent.Remove(instance, effect); - eventRef.set(event); - event.sendEvent(); - return !event.isCanceled(); + private boolean onRemoveAllEffectEvent(LivingEntity instance, MobEffectInstance effect, @Share("event") LocalBooleanRef eventRef) { + boolean canceled = EntityHooks.onEffectRemoved((LivingEntity) (Object) this, effect, null); + eventRef.set(canceled); + return !canceled; } @WrapWithCondition(method = "removeAllEffects", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;remove()V")) - private boolean skipRemove(Iterator iterator, @Share("event") LocalRef eventRef) { - return !eventRef.get().isCanceled(); + private boolean skipRemove(Iterator iterator, @Share("event") LocalBooleanRef eventRef) { + return !eventRef.get(); } - @Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true) - private void isEffectApplicable(MobEffectInstance effectInstance, CallbackInfoReturnable cir) { - MobEffectEvent.Applicable event = new MobEffectEvent.Applicable((LivingEntity) (Object) this, effectInstance); - event.sendEvent(); - if (event.getResult() != BaseEvent.Result.DEFAULT) cir.setReturnValue(event.getResult() == BaseEvent.Result.ALLOW); +// @Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true) TODO: Re-evaluate hook location on fabric +// private void isEffectApplicable(MobEffectInstance effectInstance, CallbackInfoReturnable cir) { +// MobEffectEvent.Applicable event = new MobEffectEvent.Applicable((LivingEntity) (Object) this, effectInstance); +// event.sendEvent(); +// if (event.getResult() != BaseEvent.Result.DEFAULT) +// cir.setReturnValue(event.getResult() == BaseEvent.Result.ALLOW); +// } + + @WrapMethod(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z") + private boolean onAddEffect(MobEffectInstance mobEffectInstance, Entity entity, Operation original) { + if (!EntityHooks.canMobEffectBeApplied((LivingEntity) (Object) this, mobEffectInstance)) { + return false; + } else { + return original.call(mobEffectInstance, entity); + } + } + + @WrapMethod(method = "forceAddEffect") + private void canAddEffect(MobEffectInstance mobEffectInstance, Entity entity, Operation original) { + if (EntityHooks.canMobEffectBeApplied((LivingEntity) (Object) this, mobEffectInstance)) { + original.call(mobEffectInstance, entity); + } } @Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At(value = "JUMP", opcode = Opcodes.IFNONNULL)) @@ -299,4 +312,55 @@ private void onEffectAdded(MobEffectInstance newEffect, Entity entity, CallbackI private boolean onEffectExpired(boolean original, @Local(index = 3) MobEffectInstance effect) { return !(!original && !new MobEffectEvent.Expired((LivingEntity) (Object) this, effect).post()); } + + @Override + public boolean removeEffectsCuredBy(EffectCure cure) { + if (this.level().isClientSide) + return false; + boolean ret = false; + Iterator itr = this.activeEffects.values().iterator(); + while (itr.hasNext()) { + MobEffectInstance effect = itr.next(); + if (effect.getCures().contains(cure) && !EntityHooks.onEffectRemoved((LivingEntity) (Object) this, effect, cure)) { + this.onEffectRemoved(effect); + itr.remove(); + ret = true; + this.effectsDirty = true; + } + } + return ret; + } + + @ModifyExpressionValue(method = "checkTotemDeathProtection", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z")) + private boolean onLivingUseTotem(boolean original, DamageSource source, @Local(index = 3) ItemStack item, @Local(index = 7) InteractionHand hand) { + return original && EntityHooks.onLivingUseTotem((LivingEntity) (Object) this, source, item, hand); + } + + @Inject(method = "startUsingItem", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/LivingEntity;useItem:Lnet/minecraft/world/item/ItemStack;")) + private void cacheLastUseItem(InteractionHand interactionHand, CallbackInfo ci, @Share("use_item") LocalRef lastItem) { + lastItem.set(this.useItem); + } + + @WrapOperation(method = "startUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getUseDuration(Lnet/minecraft/world/entity/LivingEntity;)I")) + private int onStartUsingItem(ItemStack instance, LivingEntity livingEntity, Operation original, @Share("old_duration") LocalIntRef oldDuration) { + oldDuration.set(this.useItemRemaining); + return EntityHooks.onItemUseStart(livingEntity, instance, original.call(instance, livingEntity)); + } + + @Inject(method = "startUsingItem", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/Level;isClientSide:Z"), cancellable = true) + private void cancelIfDurationLessThenZero(InteractionHand interactionHand, CallbackInfo ci, @Share("old_duration") LocalIntRef oldDuration) { + if (this.useItemRemaining < 0) { + // Restore old useItemRemaining since we fire the event later then neo + this.useItemRemaining = oldDuration.get(); + ci.cancel(); // Early return for negative values, as that indicates event cancellation. + } + } + @WrapWithCondition(method = "updateUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;onUseTick(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;I)V")) + private boolean onItemUseTick(ItemStack instance, Level level, LivingEntity livingEntity, int useItemRemainingTicks) { + if (!instance.isEmpty()) { + this.useItemRemaining = EntityHooks.onItemUseTick(livingEntity, instance, useItemRemainingTicks); + return getUseItemRemainingTicks() > 0; + } + return true; + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LlamaSpitMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LlamaSpitMixin.java index 3adcc8215..e98dc2882 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LlamaSpitMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/LlamaSpitMixin.java @@ -1,22 +1,19 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; - -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; import net.minecraft.world.entity.projectile.LlamaSpit; import net.minecraft.world.phys.HitResult; @Mixin(LlamaSpit.class) public class LlamaSpitMixin { - @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/LlamaSpit;onHit(Lnet/minecraft/world/phys/HitResult;)V")) - private boolean onImpact(LlamaSpit projectile, HitResult result) { - if (result.getType() == HitResult.Type.MISS) - return true; // NeoForge prevents any misses here, however vanilla doesn't so we keep vanilla behavior - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); + @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/LlamaSpit;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;")) + private boolean onProjectileImpact(LlamaSpit projectile, HitResult result) { + return result.getType() != HitResult.Type.MISS && !EntityHooks.onProjectileImpact(projectile, result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MagmaCubeMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MagmaCubeMixin.java index 75e117e88..9b825060f 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MagmaCubeMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MagmaCubeMixin.java @@ -1,7 +1,7 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.world.entity.LivingEntity; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.world.entity.monster.MagmaCube; import org.spongepowered.asm.mixin.Mixin; @@ -13,6 +13,6 @@ public class MagmaCubeMixin { @Inject(method = "jumpFromGround", at = @At("TAIL")) public void onJump(CallbackInfo ci) { - new LivingEntityEvents.LivingJumpEvent((LivingEntity) (Object) this).sendEvent(); + EntityHooks.onLivingJump(MixinHelper.cast(this)); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectInstanceMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectInstanceMixin.java new file mode 100644 index 000000000..681cfafd0 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectInstanceMixin.java @@ -0,0 +1,40 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import com.google.common.collect.Sets; + +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EffectCure; +import io.github.fabricators_of_create.porting_lib.entity.ext.MobEffectInstanceExt; +import net.minecraft.core.Holder; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Set; + +@Mixin(MobEffectInstance.class) +public class MobEffectInstanceMixin implements MobEffectInstanceExt { + @Shadow + @Final + private Holder effect; + + private final Set porting_lib$cures = Sets.newIdentityHashSet(); + + /** + * {@return the {@link EffectCure}s which can cure the {@link MobEffect} held by this {@link MobEffectInstance}} + */ + public Set getCures() { + return porting_lib$cures; + } + + @Inject(method = "(Lnet/minecraft/core/Holder;IIZZZLnet/minecraft/world/effect/MobEffectInstance;)V", at = @At("TAIL")) + private void addEffects(Holder holder, int duration, int amplifier, boolean ambient, boolean visible, boolean showIcon, MobEffectInstance hiddenEffect, CallbackInfo ci) { + this.effect.value().fillEffectCures(this.porting_lib$cures, MixinHelper.cast(this)); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectMixin.java index f61e75014..5681886ee 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobEffectMixin.java @@ -1,10 +1,10 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.extensions.MobEffectExtensions; +import io.github.fabricators_of_create.porting_lib.entity.ext.MobEffectExt; import net.minecraft.world.effect.MobEffect; import org.spongepowered.asm.mixin.Mixin; @Mixin(MobEffect.class) -public class MobEffectMixin implements MobEffectExtensions { +public class MobEffectMixin implements MobEffectExt { } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobMixin.java index 89afd44a3..91b1e9cea 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/MobMixin.java @@ -1,30 +1,31 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingChangeTargetEvent; + +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents.ChangeTarget.ChangeTargetEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents.ChangeTarget.ChangeTargetEvent.LivingTargetType; -import io.github.fabricators_of_create.porting_lib.entity.events.MobEntitySetTargetCallback; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; @Mixin(Mob.class) public abstract class MobMixin { + @Shadow + @Nullable + private LivingEntity target; + @ModifyVariable(method = "setTarget", at = @At("HEAD"), argsOnly = true) private LivingEntity port_lib$onChangeTarget(LivingEntity value) { - ChangeTargetEvent changeTargetEvent = new ChangeTargetEvent((Mob) (Object) this, value, LivingTargetType.MOB_TARGET); - changeTargetEvent.sendEvent(); - if (changeTargetEvent.isCanceled()) - return null; - return changeTargetEvent.getNewTarget(); - } - - @Inject(method = "setTarget", at = @At("TAIL")) - private void port_lib$setTarget(LivingEntity target, CallbackInfo ci) { - MobEntitySetTargetCallback.EVENT.invoker().onMobEntitySetTarget((Mob) (Object) this, target); + LivingChangeTargetEvent changeTargetEvent = EntityHooks.onLivingChangeTarget(MixinHelper.cast(this), value, LivingChangeTargetEvent.LivingTargetType.MOB_TARGET); + if(!changeTargetEvent.isCanceled()) { + return changeTargetEvent.getNewTarget(); + } + return this.target; } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/NaturalSpawnerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/NaturalSpawnerMixin.java deleted file mode 100644 index c0e8e5f14..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/NaturalSpawnerMixin.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; - -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.MobCategory; -import net.minecraft.world.entity.MobSpawnType; -import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.NaturalSpawner; - -import net.minecraft.world.level.StructureManager; -import net.minecraft.world.level.biome.MobSpawnSettings; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(NaturalSpawner.class) -public abstract class NaturalSpawnerMixin { - @Unique - private static double x, y, z; - @Unique - private static Mob mob; - @Unique - private static ServerLevel level; - - @Inject( - method = "spawnCategoryForPosition(Lnet/minecraft/world/entity/MobCategory;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/NaturalSpawner$SpawnPredicate;Lnet/minecraft/world/level/NaturalSpawner$AfterSpawnCallback;)V", - at = @At( - value = "INVOKE", target = "Lnet/minecraft/world/entity/Mob;moveTo(DDDFF)V" - ), - locals = LocalCapture.CAPTURE_FAILHARD - ) - private static void port_lib$captureLocals(MobCategory mobCategory, ServerLevel serverLevel, ChunkAccess chunkAccess, BlockPos blockPos, NaturalSpawner.SpawnPredicate spawnPredicate, NaturalSpawner.AfterSpawnCallback afterSpawnCallback, CallbackInfo ci, StructureManager structureManager, ChunkGenerator chunkGenerator, int i, BlockState blockState, BlockPos.MutableBlockPos mutableBlockPos, int j, int k, int l, int m, int n, MobSpawnSettings.SpawnerData spawnerData, SpawnGroupData spawnGroupData, int o, int p, int q, double d, double e, Player player, double f, Mob capturedMob) { - mob = capturedMob; - level = serverLevel; - x = d; - y = e; - z = f; - } - - @ModifyExpressionValue( - method = "spawnCategoryForPosition(Lnet/minecraft/world/entity/MobCategory;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/NaturalSpawner$SpawnPredicate;Lnet/minecraft/world/level/NaturalSpawner$AfterSpawnCallback;)V", - at = @At( - value = "INVOKE", target = "Lnet/minecraft/world/level/NaturalSpawner;isValidPositionForMob(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Mob;D)Z" - ) - ) - private static boolean port_lib$canSpawnEvent(boolean original) { - if (LivingEntityEvents.CHECK_SPAWN.invoker().onCheckSpawn(mob, level, x, y, z, null, MobSpawnType.NATURAL)) - return false; - return original; - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PatrolSpawnerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PatrolSpawnerMixin.java deleted file mode 100644 index 4018194f7..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PatrolSpawnerMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.MobSpawnType; -import net.minecraft.world.entity.monster.PatrollingMonster; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.PatrolSpawner; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(PatrolSpawner.class) -public class PatrolSpawnerMixin { - @Inject(method = "spawnPatrolMember", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/PatrollingMonster;setPos(DDD)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) - public void port_lib$checkSpawn(ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource, boolean bl, CallbackInfoReturnable cir, BlockState blockState, PatrollingMonster patrollingMonster) { - if (LivingEntityEvents.CHECK_SPAWN.invoker().onCheckSpawn(patrollingMonster, serverLevel, blockPos.getX(), blockPos.getY(), blockPos.getZ(), null, MobSpawnType.PATROL)) - cir.setReturnValue(false); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManager$CallbackMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManager$CallbackMixin.java index d4fc5f8b9..e05e5a83b 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManager$CallbackMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManager$CallbackMixin.java @@ -4,23 +4,18 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalLongRef; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.entity.EntityAccess; -import net.minecraft.world.level.entity.EntitySection; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(targets = "net/minecraft/world/level/entity/PersistentEntitySectionManager$Callback") public abstract class PersistentEntitySectionManager$CallbackMixin { @@ -54,7 +49,7 @@ public void afterSectionChange(CallbackInfo ci, @Local(ordinal = 0) BlockPos pos @Local(ordinal = 0) long newKey, @Share("oldKey") LocalLongRef oldKey) { if (this.entity instanceof Entity realEntity) { - EntityEvents.ENTERING_SECTION.invoker().onEntityEnterSection(realEntity, oldKey.get(), newKey); + EntityHooks.onEntityEnterSection(realEntity, oldKey.get(), newKey); } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManagerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManagerMixin.java index e6554aa2f..8ffa26dec 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManagerMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PersistentEntitySectionManagerMixin.java @@ -1,6 +1,6 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityJoinLevelEvent; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.entity.EntityAccess; import net.minecraft.world.level.entity.PersistentEntitySectionManager; @@ -14,7 +14,11 @@ public class PersistentEntitySectionManagerMixin { @Inject(method = "addEntity", at = @At("HEAD"), cancellable = true) public void port_lib$addEntityEvent(T entityAccess, boolean loadedFromDisk, CallbackInfoReturnable cir) { - if (entityAccess instanceof Entity entity && EntityEvents.ON_JOIN_WORLD.invoker().onJoinWorld(entity, entity.level(), loadedFromDisk)) - cir.setReturnValue(false); + if (entityAccess instanceof Entity entity) { + EntityJoinLevelEvent event = new EntityJoinLevelEvent(entity, entity.level(), loadedFromDisk); + event.sendEvent(); + if (event.isCanceled()) + cir.setReturnValue(false); + } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PhantomSpawnerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PhantomSpawnerMixin.java deleted file mode 100644 index 0fe6af0f7..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PhantomSpawnerMixin.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.ServerStatsCounter; -import net.minecraft.util.RandomSource; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.MobSpawnType; -import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.monster.Phantom; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.PhantomSpawner; -import net.minecraft.world.level.material.FluidState; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Iterator; - -@Mixin(PhantomSpawner.class) -public class PhantomSpawnerMixin { - @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/Phantom;moveTo(Lnet/minecraft/core/BlockPos;FF)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) - public void port_lib$checkSpawn(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals, CallbackInfoReturnable cir, RandomSource randomSource, int i, Iterator var6, ServerPlayer serverPlayer, BlockPos blockPos, DifficultyInstance difficultyInstance, ServerStatsCounter serverStatsCounter, int j, int k, BlockPos blockPos2, BlockState blockState, FluidState fluidState, SpawnGroupData spawnGroupData, int l, int m, Phantom phantom) { - if (LivingEntityEvents.CHECK_SPAWN.invoker().onCheckSpawn(phantom, world, blockPos2.getX(), blockPos2.getY(), blockPos2.getZ(), null, MobSpawnType.NATURAL)) - cir.setReturnValue(0); - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerDataStorageMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerDataStorageMixin.java new file mode 100644 index 000000000..558c5c7f8 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerDataStorageMixin.java @@ -0,0 +1,33 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.storage.PlayerDataStorage; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.io.File; + +@Mixin(PlayerDataStorage.class) +public class PlayerDataStorageMixin { + @Shadow + @Final + private File playerDir; + + @Inject(method = "save", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;safeReplaceFile(Ljava/nio/file/Path;Ljava/nio/file/Path;Ljava/nio/file/Path;)V", shift = At.Shift.AFTER)) + private void onPlayerSaving(Player player, CallbackInfo ci) { + EntityHooks.firePlayerSavingEvent(player, this.playerDir, player.getStringUUID()); + } + + @Inject(method = "method_55788", at = @At("RETURN")) + private void onPlayerLoading(Player player, CompoundTag tag, CallbackInfoReturnable cir) { + EntityHooks.firePlayerLoadingEvent(player, this.playerDir, player.getStringUUID()); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerListMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerListMixin.java index e2b579989..f5cf8b6d7 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerListMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerListMixin.java @@ -1,20 +1,32 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import io.github.fabricators_of_create.porting_lib.entity.events.OnDatapackSyncCallback; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerEvents; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerEvent; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.Connection; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.players.PlayerList; +import net.minecraft.world.level.storage.PlayerDataStorage; + +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.Optional; + @Mixin(PlayerList.class) public abstract class PlayerListMixin { + @Shadow + @Final + private PlayerDataStorage playerIo; + @Inject( method = "placeNewPlayer", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/network/protocol/game/ClientboundSetCarriedItemPacket;(I)V") @@ -33,11 +45,16 @@ public abstract class PlayerListMixin { @Inject(method = "placeNewPlayer", at = @At("TAIL")) private void onPlayerLoggedIn(Connection connection, ServerPlayer serverPlayer, CommonListenerCookie cookie, CallbackInfo ci) { - PlayerEvents.LOGGED_IN.invoker().handleConnection(serverPlayer); + EntityHooks.firePlayerLoggedIn(serverPlayer); + } + + @Inject(method = "remove", at = @At("HEAD")) + private void onPlayerLoggedOut(ServerPlayer serverPlayer, CallbackInfo ci) { + EntityHooks.firePlayerLoggedOut(serverPlayer); } - @Inject(method = "respawn", at = @At("HEAD")) - private void onPlayerLoggedOut(ServerPlayer serverPlayer, boolean bl, CallbackInfoReturnable cir) { - PlayerEvents.LOGGED_OUT.invoker().handleConnection(serverPlayer); + @Inject(method = "load", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;debug(Ljava/lang/String;)V", shift = At.Shift.AFTER)) + private void onPlayerLoad(ServerPlayer player, CallbackInfoReturnable> cir) { + EntityHooks.firePlayerLoadingEvent(player, this.playerIo, player.getUUID().toString()); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerMixin.java index 160022f1b..1d0194c21 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PlayerMixin.java @@ -9,17 +9,15 @@ import com.llamalad7.mixinextras.sugar.ref.LocalRef; import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.CriticalHitEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityInteractCallback; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingAttackEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingDeathEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingEntityEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerEvents; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerTickEvents; +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.player.CriticalHitEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerEvent; import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingDamageEvent; import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingHurtEvent; import io.github.fabricators_of_create.porting_lib.entity.events.player.AttackEntityEvent; -import io.github.fabricators_of_create.porting_lib.entity.extensions.PlayerExtension; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerXpEvent; +import io.github.fabricators_of_create.porting_lib.entity.ext.PlayerExt; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -44,77 +42,106 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(value = Player.class, priority = 500) -public abstract class PlayerMixin extends LivingEntity implements PlayerExtension { +public abstract class PlayerMixin extends LivingEntity implements PlayerExt { protected PlayerMixin(EntityType entityType, Level level) { super(entityType, level); } @Inject(method = "tick", at = @At("HEAD")) - public void port_lib$playerStartTickEvent(CallbackInfo ci) { - PlayerTickEvents.START.invoker().onStartOfPlayerTick((Player) (Object) this); + public void playerStartTickEvent(CallbackInfo ci) { + EntityHooks.firePlayerTickPre(MixinHelper.cast(this)); } @Inject(method = "tick", at = @At("TAIL")) - public void port_lib$playerEndTickEvent(CallbackInfo ci) { - PlayerTickEvents.END.invoker().onEndOfPlayerTick((Player) (Object) this); + public void playerEndTickEvent(CallbackInfo ci) { + EntityHooks.firePlayerTickPost(MixinHelper.cast(this)); } - @Inject(method = "interactOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;interact(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;"), cancellable = true) - public void port_lib$onEntityInteract(Entity entityToInteractOn, InteractionHand hand, CallbackInfoReturnable cir) { - InteractionResult cancelResult = EntityInteractCallback.EVENT.invoker().onEntityInteract((Player) (Object) this, hand, entityToInteractOn); + @Inject(method = "interactOn", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/player/Player;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;", + ordinal = 0 + ), cancellable = true) + public void onEntityInteract(Entity entityToInteractOn, InteractionHand hand, CallbackInfoReturnable cir) { + InteractionResult cancelResult = EntityHooks.onInteractEntity(MixinHelper.cast(this), entityToInteractOn, hand); if (cancelResult != null) cir.setReturnValue(cancelResult); } @Inject(method = "hurt", at = @At("HEAD"), cancellable = true) - public void port_lib$attackEvent(DamageSource source, float amount, CallbackInfoReturnable cir) { - LivingAttackEvent event = new LivingAttackEvent(this, source, amount); - event.sendEvent(); - if (event.isCanceled()) + public void onPlayerAttack(DamageSource source, float amount, CallbackInfoReturnable cir) { + if (!EntityHooks.onPlayerAttack(this, source, amount)) cir.setReturnValue(false); } - @ModifyVariable(method = "hurt", at = @At("HEAD"), argsOnly = true) - private float port_lib$onHurt(float amount, DamageSource source, float amount2) { - return LivingEntityEvents.HURT.invoker().onHurt(source, this, amount); + @ModifyVariable(method = "giveExperiencePoints", at = @At("HEAD"), index = 1, argsOnly = true) + private int xpChange(int experience, @Share("event") LocalRef eventRef) { + PlayerXpEvent.XpChange event = new PlayerXpEvent.XpChange((Player) (Object) this, experience); + eventRef.set(event); + event.sendEvent(); + return event.getAmount(); } - @ModifyVariable(method = "giveExperiencePoints", at = @At("HEAD")) - private int port_lib$xpChange(int experience) { - PlayerEvents.XpChange xpChange = new PlayerEvents.XpChange((Player) (Object) this, experience); - xpChange.sendEvent(); - return xpChange.getAmount(); + @Inject(method = "giveExperiencePoints", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;increaseScore(I)V"), cancellable = true) + private void cancelPoints(int experience, CallbackInfo ci, @Share("event") LocalRef eventRef) { + if (eventRef.get().isCanceled()) + ci.cancel(); + } + + @ModifyVariable(method = "giveExperienceLevels", at = @At("HEAD"), index = 1, argsOnly = true) + private int levelChange(int level, @Share("event") LocalRef eventRef) { + PlayerXpEvent.LevelChange event = new PlayerXpEvent.LevelChange((Player) (Object) this, level); + eventRef.set(event); + event.sendEvent(); + return event.getLevels(); + } + + @Inject(method = "giveExperienceLevels", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;experienceLevel:I", ordinal = 0), cancellable = true) + private void cancelLevels(int levels, CallbackInfo ci, @Share("event") LocalRef eventRef) { + if (eventRef.get().isCanceled()) + ci.cancel(); + } + + @Inject(method = "attack", at = @At("HEAD"), cancellable = true) + private void onPlayerAttackTarget(Entity target, CallbackInfo ci) { + if (!EntityHooks.onPlayerAttackTarget((Player) (Object) this, target)) + ci.cancel(); } @ModifyVariable( method = "attack", slice = @Slice( - from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 1), - to = @At(value = "CONSTANT", args = "floatValue=1.5F") + from = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isSprinting()Z", ordinal = 1), + to = @At(value = "CONSTANT", args = "floatValue=1.5F") ), - at = @At(value = "STORE", opcode = Opcodes.ISTORE), index = 8 + at = @At(value = "STORE", opcode = Opcodes.ISTORE), index = 9 ) private boolean modifyResult(boolean value, @Share("original") LocalBooleanRef vanilla) { vanilla.set(value); return true; } - @ModifyVariable(method = "attack", at = @At(value = "CONSTANT", args = "floatValue=1.5F"), index = 8) + @ModifyVariable(method = "attack", at = @At(value = "CONSTANT", args = "floatValue=1.5F"), index = 9) private boolean modifyVanillaResult(boolean value, @Share("original") LocalBooleanRef vanilla) { return vanilla.get(); } @ModifyExpressionValue(method = "attack", at = @At(value = "CONSTANT", args = "floatValue=1.5F")) - private float getCriticalDamageMultiplier(float original, Entity target, @Share("original") LocalBooleanRef vanilla) { + private float getCriticalDamageMultiplier(float original, Entity target, @Share("original") LocalBooleanRef vanilla, @Share("event") LocalRef eventRef) { boolean vanillaCritical = vanilla.get(); - CriticalHitEvent hitResult = new CriticalHitEvent((Player) (Object) this, target, original, vanillaCritical); - hitResult.sendEvent(); - if (hitResult.getResult() == BaseEvent.Result.ALLOW || (vanillaCritical && hitResult.getResult() == BaseEvent.Result.DEFAULT)) { + var critEvent = EntityHooks.fireCriticalHit((Player) (Object) this, target, vanillaCritical, vanillaCritical ? original : 1.0F); + eventRef.set(critEvent); + if (critEvent.isCriticalHit()) { vanilla.set(true); - return hitResult.getDamageModifier(); + return critEvent.getDamageMultiplier(); } return 1.0F; } + @ModifyVariable(method = "attack", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Player;walkDist:F"), index = 9) + private boolean isCriticalHit(boolean value, @Share("event") LocalRef eventRef) { + return eventRef.get().isCriticalHit(); + } + @Inject(method = "attack", at = @At("HEAD"), cancellable = true) private void playerAttackEntityEvent(Entity target, CallbackInfo ci) { AttackEntityEvent event = new AttackEntityEvent((Player) (Object) this, target); @@ -125,36 +152,29 @@ private void playerAttackEntityEvent(Entity target, CallbackInfo ci) { @Inject(method = "die", at = @At("HEAD"), cancellable = true) private void onLivingDeath(DamageSource cause, CallbackInfo ci) { - LivingDeathEvent event = new LivingDeathEvent(this, cause); - event.sendEvent(); - if (event.isCanceled()) + if (EntityHooks.onLivingDeath(this, cause)) ci.cancel(); } - @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 0), index = 2) - private float livingHurtEvent(float value, DamageSource pDamageSource, @Share("hurt") LocalRef eventRef) { - LivingHurtEvent event = new LivingHurtEvent(this, pDamageSource, value); - eventRef.set(event); - event.sendEvent(); - if (event.isCanceled()) - return 0; - return event.getAmount(); + @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 0), index = 2, argsOnly = true) + private float livingHurtEvent(float amount, DamageSource pDamageSource) { + return EntityHooks.onLivingHurt(this, pDamageSource, amount); } @Inject(method = "actuallyHurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getDamageAfterArmorAbsorb(Lnet/minecraft/world/damagesource/DamageSource;F)F"), cancellable = true) - private void shouldCancelHurt(DamageSource damageSource, float f, CallbackInfo ci, @Share("hurt") LocalRef eventRef) { - if (eventRef.get().getAmount() <= 0) + private void shouldCancelHurt(DamageSource damageSource, float amount, CallbackInfo ci) { + if (amount <= 0) ci.cancel(); } - @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 5), index = 2) - private float livingDamageEvent(float value, DamageSource pDamageSource) { - LivingDamageEvent event = new LivingDamageEvent(this, pDamageSource, value); - event.sendEvent(); - if (event.isCanceled()) - return 0; - return event.getAmount(); - } +// @ModifyVariable(method = "actuallyHurt", at = @At(value = "LOAD", ordinal = 5), index = 2) TODO: PORT +// private float livingDamageEvent(float value, DamageSource pDamageSource) { +// LivingDamageEvent event = new LivingDamageEvent(this, pDamageSource, value); +// event.sendEvent(); +// if (event.isCanceled()) +// return 0; +// return event.getAmount(); +// } private final ThreadLocal pl$destroySpeedContext = new ThreadLocal<>(); @@ -165,9 +185,6 @@ public void setDigSpeedContext(@Nullable BlockPos pos) { @ModifyReturnValue(method = "getDestroySpeed", at = @At("RETURN")) private float breakspeedEvent(float original, BlockState state) { - PlayerEvents.BreakSpeed breakSpeed = new PlayerEvents.BreakSpeed((Player) (Object) this, state, original, pl$destroySpeedContext.get()); - breakSpeed.sendEvent(); - pl$destroySpeedContext.remove(); - return breakSpeed.getNewSpeed(); + return EntityHooks.getBreakSpeed((Player) (Object) this, state, original, pl$destroySpeedContext.get()); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PortalForcerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PortalForcerMixin.java deleted file mode 100644 index 2c33bf0ac..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/PortalForcerMixin.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.entity.ITeleporter; - -import org.spongepowered.asm.mixin.Mixin; - -import net.minecraft.world.level.portal.PortalForcer; - -@Mixin(PortalForcer.class) -public class PortalForcerMixin implements ITeleporter { - // no need to do anything, all methods are defaulted. -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ProjectileMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ProjectileMixin.java deleted file mode 100644 index cc3fb4c8d..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ProjectileMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactCallback; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.phys.HitResult; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Projectile.class) -public abstract class ProjectileMixin { - @Inject(method = "onHit", at = @At("HEAD"), cancellable = true) - private void port_lib$onProjectileHit(HitResult result, CallbackInfo ci) { - if (ProjectileImpactCallback.EVENT.invoker().onImpact((Projectile) (Object) this, result)) { - ci.cancel(); - } - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ResultSlotMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ResultSlotMixin.java new file mode 100644 index 000000000..1bac7ee5f --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ResultSlotMixin.java @@ -0,0 +1,35 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.inventory.ResultSlot; + +import net.minecraft.world.item.ItemStack; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ResultSlot.class) +public class ResultSlotMixin { + @Shadow + @Final + private Player player; + + @Shadow + @Final + private CraftingContainer craftSlots; + + @Inject(method = "checkTakeAchievements", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;onCraftedBy(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;I)V", + shift = At.Shift.AFTER + )) + private void onItemCrafted(ItemStack itemStack, CallbackInfo ci) { + EntityHooks.firePlayerCraftingEvent(this.player, itemStack, this.craftSlots); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerEntityMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerEntityMixin.java index 8cf11d7f6..3feae3395 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerEntityMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerEntityMixin.java @@ -1,6 +1,9 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvent; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; @@ -12,6 +15,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.function.Consumer; + @Mixin(ServerEntity.class) public abstract class ServerEntityMixin { @Shadow @@ -19,7 +24,22 @@ public abstract class ServerEntityMixin { private Entity entity; @Inject(method = "addPairing", at = @At("TAIL")) - private void port_lib$addPairing(ServerPlayer player, CallbackInfo ci) { - EntityEvents.START_TRACKING_TAIL.invoker().onTrackingStart(entity, player); + private void addPairing(ServerPlayer player, CallbackInfo ci) { + EntityHooks.onStartEntityTracking(this.entity, player); + } + + @Inject(method = "removePairing", at = @At("TAIL")) + private void onStopEntityTracking(ServerPlayer player, CallbackInfo ci) { + EntityHooks.onStopEntityTracking(this.entity, player); + } + + @Inject(method = "sendPairingData", at = @At( + value = "INVOKE", + target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V", + shift = At.Shift.AFTER, + ordinal = 0 + )) + private void sendComplexSpawnData(ServerPlayer serverPlayer, Consumer> consumer, CallbackInfo ci) { + this.entity.sendPairingData(serverPlayer, customPacketPayload -> consumer.accept(new ClientboundCustomPayloadPacket(customPacketPayload))); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerGamePacketListenerImpl$1Mixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerGamePacketListenerImpl$1Mixin.java new file mode 100644 index 000000000..bf4661ae3 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerGamePacketListenerImpl$1Mixin.java @@ -0,0 +1,24 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(targets = "net/minecraft/server/network/ServerGamePacketListenerImpl$1") +public class ServerGamePacketListenerImpl$1Mixin { + @Inject(method = "method_33898", at = @At("HEAD")) + private static void onInteractEntityAt(Vec3 vec3, ServerPlayer player, Entity entity, InteractionHand interactionHand, CallbackInfoReturnable cir) { + InteractionResult onInteractEntityAtResult = EntityHooks.onInteractEntityAt(player, entity, vec3, interactionHand); + if (onInteractEntityAtResult != null) cir.setReturnValue(onInteractEntityAtResult); + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerLevelMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerLevelMixin.java index 322b94277..222b3bbe8 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerLevelMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerLevelMixin.java @@ -2,22 +2,40 @@ import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import io.github.fabricators_of_create.porting_lib.entity.PartEntity; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; -import io.github.fabricators_of_create.porting_lib.entity.extensions.LevelExtensions; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityJoinLevelEvent; +import io.github.fabricators_of_create.porting_lib.entity.events.tick.EntityTickEvent; +import io.github.fabricators_of_create.porting_lib.entity.ext.LevelExt; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.storage.WritableLevelData; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.function.Supplier; + @Mixin(ServerLevel.class) -public abstract class ServerLevelMixin implements LevelExtensions { +public abstract class ServerLevelMixin extends Level implements LevelExt { + + protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey resourceKey, RegistryAccess registryAccess, Holder holder, Supplier supplier, boolean bl, boolean bl2, long l, int i) { + super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i); + } @ModifyReturnValue(method = "getEntityOrPart", at = @At("RETURN")) public Entity port_lib$getMultipart(Entity entity, int id) { @@ -32,7 +50,17 @@ public abstract class ServerLevelMixin implements LevelExtensions { @Inject(method = "addPlayer", at = @At("HEAD"), cancellable = true) public void port_lib$addEntityEvent(ServerPlayer serverPlayer, CallbackInfo ci) { - if (EntityEvents.ON_JOIN_WORLD.invoker().onJoinWorld(serverPlayer, (Level) (Object) this, false)) + EntityJoinLevelEvent event = new EntityJoinLevelEvent(serverPlayer, this); + event.sendEvent(); + if (event.isCanceled()) ci.cancel(); } + + @WrapOperation(method = "tickNonPassenger", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;tick()V")) + private void preEntityTick(Entity instance, Operation original) { + if (!EntityHooks.fireEntityTickPre(instance).isCanceled()) { + original.call(instance); + EntityHooks.fireEntityTickPost(instance); + } + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerGameModeMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerGameModeMixin.java index 79bde0a4d..2837c8a61 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerGameModeMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerGameModeMixin.java @@ -1,19 +1,40 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerInteractionEvents; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.sugar.Local; + +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.player.PlayerInteractEvent; +import net.fabricmc.fabric.api.util.TriState; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ServerPlayerGameMode.class) public abstract class ServerPlayerGameModeMixin { @@ -25,11 +46,45 @@ public abstract class ServerPlayerGameModeMixin { protected ServerPlayer player; @Inject(method = "handleBlockBreakAction", at = @At("HEAD"), cancellable = true) - public void port_lib$blockBreak(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int i, CallbackInfo ci) { - PlayerInteractionEvents.LeftClickBlock event = new PlayerInteractionEvents.LeftClickBlock(player, pos, direction); - event.sendEvent(); - if (event.isCanceled() || (!this.isCreative() && event.getResult() == BaseEvent.Result.DENY)) { + public void port_lib$blockBreak(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int i, CallbackInfo ci, @Share("event")LocalRef eventRef) { + PlayerInteractEvent.LeftClickBlock event = EntityHooks.onLeftClickBlock(player, pos, direction, action); + eventRef.set(event); + if (event.isCanceled()) { ci.cancel(); } } + + @WrapWithCondition(method = "handleBlockBreakAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;attack(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;)V")) + private boolean canAttack(BlockState instance, Level level, BlockPos blockPos, Player player, @Share("event")LocalRef eventRef) { + return eventRef.get().getUseBlock() != TriState.FALSE; + } + + @Inject(method = "useItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getCount()I", ordinal = 0), cancellable = true) + private void onItemRightClick(ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand, CallbackInfoReturnable cir) { + InteractionResult cancelResult = EntityHooks.onItemRightClick(player, hand); + if (cancelResult != null) + cir.setReturnValue(cancelResult); + } + + @ModifyExpressionValue(method = "useItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;isEnabled(Lnet/minecraft/world/flag/FeatureFlagSet;)Z")) + private boolean onRightClickBlock( + boolean original, ServerPlayer player, Level level, ItemStack itemStack, InteractionHand hand, BlockHitResult hitResult, @Local(index = 6) BlockPos pos, + @Share("event") LocalRef eventRef + ) { + if (original) { + PlayerInteractEvent.RightClickBlock event = EntityHooks.onRightClickBlock(player, hand, pos, hitResult); + eventRef.set(event); + if (event.isCanceled()) + return false; + } + return original; + } + + @ModifyReturnValue(method = "useItemOn", at = @At(value = "RETURN", ordinal = 0)) + private InteractionResult changeRightClickResult(InteractionResult original, @Share("event") LocalRef eventRef) { + var event = eventRef.get(); + if (event.isCanceled()) + return event.getCancellationResult(); + return original; + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerMixin.java index 92aaf1980..18d9e7fc0 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ServerPlayerMixin.java @@ -2,39 +2,19 @@ import com.mojang.authlib.GameProfile; -import io.github.fabricators_of_create.porting_lib.entity.ITeleporter; -import io.github.fabricators_of_create.porting_lib.entity.events.LivingDeathEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.PlayerTickEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import io.github.fabricators_of_create.porting_lib.entity.events.ServerPlayerCreationCallback; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; -import net.minecraft.network.protocol.game.ClientboundGameEventPacket; -import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; -import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; -import net.minecraft.network.protocol.game.ClientboundRespawnPacket; -import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket; -import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.server.network.ServerGamePacketListenerImpl; -import net.minecraft.server.players.PlayerList; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.level.storage.LevelData; - -import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -43,144 +23,23 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import javax.annotation.Nullable; - @Mixin(ServerPlayer.class) public abstract class ServerPlayerMixin extends Player { - @Shadow - private boolean isChangingDimension; - public ServerPlayerMixin(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { super(world, pos, yaw, gameProfile); } - @Shadow - public abstract ServerLevel serverLevel(); - - @Shadow - public ServerGamePacketListenerImpl connection; - @Shadow @Final public MinecraftServer server; - @Shadow - public boolean wonGame; - - @Shadow - private boolean seenCredits; - - @Shadow - @Final - public ServerPlayerGameMode gameMode; - - @Shadow - protected abstract void triggerDimensionChangeTriggers(ServerLevel origin); - - @Shadow - private int lastSentExp; - - @Shadow - private float lastSentHealth; - - @Shadow - private int lastSentFood; - - @Shadow - @org.jetbrains.annotations.Nullable - private Vec3 enteredNetherPosition; - - @Shadow - protected abstract void createEndPlatform(ServerLevel world, BlockPos centerPos); - @Inject(method = "", at = @At("RETURN")) - private void port_lib$init(MinecraftServer server, ServerLevel world, GameProfile gameProfile, ClientInformation clientInformation, CallbackInfo ci) { + private void init(MinecraftServer server, ServerLevel world, GameProfile gameProfile, ClientInformation clientInformation, CallbackInfo ci) { ServerPlayerCreationCallback.EVENT.invoker().onCreate((ServerPlayer) (Object) this); } - @Inject(method = "tick", at = @At("HEAD")) - public void port_lib$clientStartTickEvent(CallbackInfo ci) { - PlayerTickEvents.START.invoker().onStartOfPlayerTick(this); - } - - @Inject(method = "tick", at = @At("TAIL")) - public void port_lib$clientEndTickEvent(CallbackInfo ci) { - PlayerTickEvents.END.invoker().onEndOfPlayerTick(this); - } - - @Nullable - @Override - public Entity changeDimension(ServerLevel p_9180_, ITeleporter teleporter) { -// if (!net.minecraftforge.common.ForgeHooks.onTravelToDimension(this, p_9180_.dimension())) return null; - this.isChangingDimension = true; - ServerLevel serverlevel = this.serverLevel(); - ResourceKey resourcekey = serverlevel.dimension(); - if (resourcekey == Level.END && p_9180_.dimension() == Level.OVERWORLD && teleporter.isVanilla()) { //Forge: Fix non-vanilla teleporters triggering end credits - this.unRide(); - this.serverLevel().removePlayerImmediately((ServerPlayer) (Object) this, Entity.RemovalReason.CHANGED_DIMENSION); - if (!this.wonGame) { - this.wonGame = true; - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F)); - this.seenCredits = true; - } - - return this; - } else { - LevelData leveldata = p_9180_.getLevelData(); - CommonPlayerSpawnInfo info = new CommonPlayerSpawnInfo( - p_9180_.dimensionTypeId(), p_9180_.dimension(), BiomeManager.obfuscateSeed(p_9180_.getSeed()), - this.gameMode.getGameModeForPlayer(), this.gameMode.getPreviousGameModeForPlayer(), - p_9180_.isDebug(), p_9180_.isFlat(), this.getLastDeathLocation(), getPortalCooldown() - ); - this.connection.send(new ClientboundRespawnPacket(info, ClientboundRespawnPacket.KEEP_ALL_DATA)); - this.connection.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked())); - PlayerList playerlist = this.server.getPlayerList(); - playerlist.sendPlayerPermissionLevel((ServerPlayer) (Object) this); - serverlevel.removePlayerImmediately((ServerPlayer) (Object) this, Entity.RemovalReason.CHANGED_DIMENSION); - this.unsetRemoved(); - PortalInfo portalinfo = teleporter.getPortalInfo(this, p_9180_, this::findDimensionEntryPoint); - if (portalinfo != null) { - Entity e = teleporter.placeEntity(this, serverlevel, p_9180_, this.getYRot(), spawnPortal -> {//Forge: Start vanilla logic - serverlevel.getProfiler().push("moving"); - if (resourcekey == Level.OVERWORLD && p_9180_.dimension() == Level.NETHER) { - this.enteredNetherPosition = this.position(); - } else if (spawnPortal && p_9180_.dimension() == Level.END) { - this.createEndPlatform(p_9180_, BlockPos.containing(portalinfo.pos)); - } - - serverlevel.getProfiler().pop(); - serverlevel.getProfiler().push("placing"); - this.setLevel(p_9180_); - p_9180_.addDuringPortalTeleport((ServerPlayer) (Object) this); - this.setRot(portalinfo.yRot, portalinfo.xRot); - this.moveTo(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z); - serverlevel.getProfiler().pop(); - this.triggerDimensionChangeTriggers(serverlevel); - return this;//forge: this is part of the ITeleporter patch - });//Forge: End vanilla logic - if (e != this) throw new java.lang.IllegalArgumentException(String.format(java.util.Locale.ENGLISH, "Teleporter %s returned not the player entity but instead %s, expected PlayerEntity %s", teleporter, e, this)); - this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities())); - playerlist.sendLevelInfo((ServerPlayer) (Object) this, p_9180_); - playerlist.sendAllPlayerInfo((ServerPlayer) (Object) this); - - for(MobEffectInstance mobeffectinstance : this.getActiveEffects()) { - this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), mobeffectinstance)); - } - - if (teleporter.playTeleportSound((ServerPlayer) (Object) this, serverlevel, p_9180_)) - this.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false)); - this.lastSentExp = -1; - this.lastSentHealth = -1.0F; - this.lastSentFood = -1; -// net.minecraftforge.event.ForgeEventFactory.firePlayerChangedDimensionEvent(this, resourcekey, p_9180_.dimension()); - } - - return this; - } - } - @Inject(method = "restoreFrom", at = @At("TAIL")) - private void port_lib$copyPersistentData(ServerPlayer oldPlayer, boolean alive, CallbackInfo ci) { + private void copyPersistentData(ServerPlayer oldPlayer, boolean alive, CallbackInfo ci) { CompoundTag oldData = oldPlayer.getCustomData(); CompoundTag persistent = oldData.getCompound("PlayerPersisted"); if (persistent != null) { @@ -189,11 +48,9 @@ public Entity changeDimension(ServerLevel p_9180_, ITeleporter teleporter) { } } - @Inject(method = "die", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;gameEvent(Lnet/minecraft/world/level/gameevent/GameEvent;)V", shift = At.Shift.AFTER), cancellable = true) + @Inject(method = "die", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;gameEvent(Lnet/minecraft/core/Holder;)V", shift = At.Shift.AFTER), cancellable = true) private void onPlayerDie(DamageSource cause, CallbackInfo ci) { - LivingDeathEvent event = new LivingDeathEvent((ServerPlayer) (Object) this, cause); - event.sendEvent(); - if (event.isCanceled()) + if (EntityHooks.onLivingDeath(this, cause)) ci.cancel(); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerBulletMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerBulletMixin.java index 5f124f924..b11a99024 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerBulletMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerBulletMixin.java @@ -1,20 +1,19 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; - -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; import net.minecraft.world.entity.projectile.ShulkerBullet; import net.minecraft.world.phys.HitResult; @Mixin(ShulkerBullet.class) public class ShulkerBulletMixin { - @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ShulkerBullet;onHit(Lnet/minecraft/world/phys/HitResult;)V")) - private boolean onImpact(ShulkerBullet projectile, HitResult result) { - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); + @WrapWithCondition(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ShulkerBullet;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;")) + private boolean onProjectileImpact(ShulkerBullet projectile, HitResult result) { + return !EntityHooks.onProjectileImpact(projectile, result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerMixin.java new file mode 100644 index 000000000..7455a41e2 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ShulkerMixin.java @@ -0,0 +1,41 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import com.llamalad7.mixinextras.sugar.Local; + +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.monster.Shulker; + +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(Shulker.class) +public class ShulkerMixin { + @ModifyVariable(method = "teleportSomewhere", at = @At(value = "JUMP", opcode = Opcodes.IFNULL), index = 4) + private Direction onEnderTeleport(Direction direction, @Local(index = 3) BlockPos pos, @Share("event") LocalRef eventRef) { + if (direction != null) { + EntityTeleportEvent.EnderEntity event = EntityHooks.onEnderTeleport((Shulker) (Object) this, pos.getX(), pos.getY(), pos.getZ()); + eventRef.set(event); + if (event.isCanceled()) + return null; + } + return direction; + } + + @ModifyVariable(method = "teleportSomewhere", at = @At(value = "JUMP", opcode = Opcodes.IFNULL, by = 1), index = 3) // Shift by 1 so we apply after the above code + private BlockPos changeTeleportTarget(BlockPos pos, @Local(index = 4) Direction direction, @Share("event") LocalRef eventRef) { + if (direction != null) { + EntityTeleportEvent.EnderEntity event = eventRef.get(); + return BlockPos.containing(event.getTargetX(), event.getTargetY(), event.getTargetZ()); + } + return pos; + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SlimeMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SlimeMixin.java index 1f20ec04a..b019f8365 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SlimeMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SlimeMixin.java @@ -1,6 +1,8 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.extensions.SlimeExtension; +import io.github.fabricators_of_create.porting_lib.entity.ext.SlimeExt; + +import net.minecraft.world.entity.EntityDimensions; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -11,11 +13,11 @@ import net.minecraft.world.entity.monster.Slime; @Mixin(Slime.class) -public class SlimeMixin implements SlimeExtension { - @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/monster/Slime;getSize()I")) - private int handleParticles(Slime slime, Operation operation) { +public class SlimeMixin implements SlimeExt { + @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityDimensions;width()F")) + private float handleParticles(EntityDimensions instance, Operation original) { if (!spawnCustomParticles()) - return operation.call(slime); + return original.call(instance); return 0; // Return 0 to prevent adding particles } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpiderMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpiderMixin.java deleted file mode 100644 index eab69f892..000000000 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpiderMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.entity.mixin.common; - -import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; -import io.github.fabricators_of_create.porting_lib.entity.events.living.MobEffectEvent; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.monster.Spider; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(Spider.class) -public class SpiderMixin { - @Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true) - private void isEffectApplicable(MobEffectInstance effectInstance, CallbackInfoReturnable cir) { - if (effectInstance.getEffect() == MobEffects.POISON) { - MobEffectEvent.Applicable event = new MobEffectEvent.Applicable((LivingEntity) (Object) this, effectInstance); - event.sendEvent(); - if (event.getResult() != BaseEvent.Result.DEFAULT) - cir.setReturnValue(event.getResult() == BaseEvent.Result.ALLOW); - } - } -} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpreadPlayersCommandMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpreadPlayersCommandMixin.java index f4ff6051f..ae0d315f3 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpreadPlayersCommandMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/SpreadPlayersCommandMixin.java @@ -1,8 +1,10 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; import net.minecraft.server.commands.SpreadPlayersCommand; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -15,10 +17,21 @@ @Mixin(SpreadPlayersCommand.class) public abstract class SpreadPlayersCommandMixin { - @WrapWithCondition(method = "setPlayerPositions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;teleportTo(Lnet/minecraft/server/level/ServerLevel;DDDLjava/util/Set;FF)Z")) - private static boolean port_lib$setPlayerPositions(Entity instance, ServerLevel level, double x, double y, double z, Set set, float g, float h) { - EntityEvents.Teleport.EntityTeleportEvent event = new EntityEvents.Teleport.EntityTeleportEvent(instance, x, y, z); - event.sendEvent(); + @WrapOperation(method = "setPlayerPositions", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;teleportTo(Lnet/minecraft/server/level/ServerLevel;DDDLjava/util/Set;FF)Z")) + private static boolean onSpreadPlayers(Entity instance, ServerLevel serverLevel, double x, double y, double z, Set set, float yRot, float xRot, Operation original) { + EntityTeleportEvent.SpreadPlayersCommand event = EntityHooks.onEntityTeleportSpreadPlayersCommand(instance, x, y, z); + + if (!event.isCanceled()) { + return original.call(instance, + serverLevel, + event.getTargetX(), + event.getTargetY(), + event.getTargetZ(), + set, + yRot, + xRot + ); + } return !event.isCanceled(); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/StartAttackingMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/StartAttackingMixin.java new file mode 100644 index 000000000..01a322f48 --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/StartAttackingMixin.java @@ -0,0 +1,48 @@ +package io.github.fabricators_of_create.porting_lib.entity.mixin.common; + +import com.llamalad7.mixinextras.sugar.Local; + +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.living.LivingChangeTargetEvent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.behavior.StartAttacking; + +import net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.function.Function; +import java.util.function.Predicate; + +@Mixin(StartAttacking.class) +public class StartAttackingMixin { + @Inject(method = "method_47123", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;set(Ljava/lang/Object;)V"), cancellable = true) + private static void onLivingChangeTarget( + Predicate predicate, Function function, MemoryAccessor memoryAccessor, MemoryAccessor memoryAccessor2, ServerLevel level, Mob mob, long l, CallbackInfoReturnable cir, + @Local(index = 9) LivingEntity target, @Share("event") LocalRef eventRef + ) { + LivingChangeTargetEvent changeTargetEvent = EntityHooks.onLivingChangeTarget(mob, target, LivingChangeTargetEvent.LivingTargetType.BEHAVIOR_TARGET); + eventRef.set(changeTargetEvent); + if (changeTargetEvent.isCanceled()) + cir.setReturnValue(false); + } + + @ModifyArg(method = "method_47123", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;set(Ljava/lang/Object;)V")) + private static Object changeTarget(Object object, @Share("event") LocalRef eventRef) { + LivingChangeTargetEvent event = eventRef.get(); + // Only pass the new target if we know the target was changed. + if (event.changedTarget()) + return event.getNewTarget(); + return object; + } +} diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TeleportCommandMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TeleportCommandMixin.java index 7c4a4ad4e..934c6c720 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TeleportCommandMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TeleportCommandMixin.java @@ -2,12 +2,15 @@ import java.util.Set; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; + +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.commands.TeleportCommand; import net.minecraft.server.level.ServerLevel; @@ -17,11 +20,9 @@ @Mixin(TeleportCommand.class) public abstract class TeleportCommandMixin { @Inject(method = "performTeleport", at = @At("HEAD"), cancellable = true) - private static void port_lib$performTeleport(CommandSourceStack source, Entity target, ServerLevel world, double x, double y, double z, Set movementFlags, float yaw, float pitch, TeleportCommand.LookAt facingLocation, CallbackInfo ci) { - EntityEvents.Teleport.EntityTeleportEvent event = new EntityEvents.Teleport.EntityTeleportEvent(target, x, y, z); - event.sendEvent(); - if (event.isCanceled()) { + private static void onEntityTeleportCommand(CommandSourceStack source, Entity target, ServerLevel world, double x, double y, double z, Set movementFlags, float yaw, float pitch, TeleportCommand.LookAt facingLocation, CallbackInfo ci) { + EntityTeleportEvent.TeleportCommand event = EntityHooks.onEntityTeleportCommand(target, x, y, z); + if (event.isCanceled()) ci.cancel(); - } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrowableProjectileMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrowableProjectileMixin.java index 0cfba077f..c88a8de33 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrowableProjectileMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrowableProjectileMixin.java @@ -2,7 +2,7 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; -import io.github.fabricators_of_create.porting_lib.entity.events.ProjectileImpactEvent; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.world.entity.projectile.ThrowableProjectile; import net.minecraft.world.phys.HitResult; @@ -16,12 +16,10 @@ public class ThrowableProjectileMixin { method = "tick", at = @At( value = "INVOKE", - target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;onHit(Lnet/minecraft/world/phys/HitResult;)V" + target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;hitTargetOrDeflectSelf(Lnet/minecraft/world/phys/HitResult;)Lnet/minecraft/world/entity/projectile/ProjectileDeflection;" ) ) - private boolean onImpact(ThrowableProjectile projectile, HitResult result) { - ProjectileImpactEvent event = new ProjectileImpactEvent(projectile, result); - event.sendEvent(); - return !event.isCanceled(); + private boolean onProjectileImpact(ThrowableProjectile projectile, HitResult result) { + return !EntityHooks.onProjectileImpact(projectile, result); } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrownEnderpearlMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrownEnderpearlMixin.java index a5877bf22..f5264b4c9 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrownEnderpearlMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/ThrownEnderpearlMixin.java @@ -1,15 +1,25 @@ package io.github.fabricators_of_create.porting_lib.entity.mixin.common; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import com.llamalad7.mixinextras.sugar.Share; + +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +import io.github.fabricators_of_create.porting_lib.core.util.MixinHelper; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import io.github.fabricators_of_create.porting_lib.entity.events.EntityTeleportEvent; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.projectile.ThrowableItemProjectile; import net.minecraft.world.entity.projectile.ThrownEnderpearl; import net.minecraft.world.level.Level; import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ThrownEnderpearl.class) @@ -19,12 +29,25 @@ public ThrownEnderpearlMixin(EntityType entit } @Inject(method = "onHit", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/RandomSource;nextFloat()F"), cancellable = true) - private void port_lib$onHit(HitResult result, CallbackInfo ci) { - EntityEvents.Teleport.EntityTeleportEvent event = new EntityEvents.Teleport.EntityTeleportEvent(getOwner(), getX(), getY(), getZ()); - event.sendEvent(); + private void onEnderPearlLand(HitResult result, CallbackInfo ci, @Share("teleport") LocalRef eventRef) { + EntityTeleportEvent.EnderPearl event = EntityHooks.onEnderPearlLand((ServerPlayer) getOwner(), this.getX(), this.getY(), this.getZ(), MixinHelper.cast(this), 5.0F, result); + eventRef.set(event); if (event.isCanceled()) { discard(); ci.cancel(); } } + + @ModifyArg(method = "onHit", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/portal/DimensionTransition;(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;FFLnet/minecraft/world/level/portal/DimensionTransition$PostDimensionTransition;)V", ordinal = 0), index = 1) + private Vec3 modifyTarget(Vec3 vec3, @Share("teleport") LocalRef eventRef) { + return eventRef.get().getTarget(); + } + + @ModifyArg(method = "onHit", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z"), index = 1) + private float modifyAttackDamage(float damage, @Share("teleport") LocalRef eventRef) { + // If damage isn't 5 then another mod has changed it (this isn't a great workaround the only proper solution for this is to use asm to check if another mod has modified this and check those modified conditions). + if (damage != 5.0F) + return damage; + return eventRef.get().getAttackDamage(); + } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TransientEntitySectionManager$CallbackMixin.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TransientEntitySectionManager$CallbackMixin.java index aca72e387..53027cf5c 100644 --- a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TransientEntitySectionManager$CallbackMixin.java +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/mixin/common/TransientEntitySectionManager$CallbackMixin.java @@ -6,17 +6,15 @@ import com.llamalad7.mixinextras.sugar.ref.LocalLongRef; -import io.github.fabricators_of_create.porting_lib.entity.events.EntityEvents; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.entity.EntityAccess; -import net.minecraft.world.level.entity.TransientEntitySectionManager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -42,17 +40,14 @@ public void grabOldKey(CallbackInfo ci, @Share("oldKey") LocalLongRef oldKey) { @Inject( method = "onMove", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/level/entity/EntityAccess;isAlwaysTicking()Z", - shift = Shift.AFTER - ) + at = @At("TAIL") ) public void afterSectionChange(CallbackInfo ci, @Local(ordinal = 0) BlockPos pos, @Local(ordinal = 0) long newKey, @Share("oldKey") LocalLongRef oldKey) { - - if (this.entity instanceof Entity realEntity) { - EntityEvents.ENTERING_SECTION.invoker().onEntityEnterSection(realEntity, oldKey.get(), newKey); + if (newKey != this.currentSectionKey) { + if (this.entity instanceof Entity realEntity) { + EntityHooks.onEntityEnterSection(realEntity, oldKey.get(), newKey); + } } } } diff --git a/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/network/AdvancedAddEntityPayload.java b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/network/AdvancedAddEntityPayload.java new file mode 100644 index 000000000..1b361418b --- /dev/null +++ b/modules/entity/src/main/java/io/github/fabricators_of_create/porting_lib/entity/network/AdvancedAddEntityPayload.java @@ -0,0 +1,52 @@ +package io.github.fabricators_of_create.porting_lib.entity.network; + +import io.github.fabricators_of_create.porting_lib.core.PortingLib; +import io.github.fabricators_of_create.porting_lib.entity.IEntityWithComplexSpawn; +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.ApiStatus; + +/** + * Payload that can be sent from the server to the client to add an entity to the world, with custom data. + * + * @param entityId The id of the entity to add. + * @param customPayload The custom data of the entity to add. + */ +@ApiStatus.Internal +public record AdvancedAddEntityPayload(int entityId, byte[] customPayload) implements CustomPacketPayload { + + public static final Type TYPE = new Type<>(PortingLib.id("advanced_add_entity")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + AdvancedAddEntityPayload::entityId, + ByteBufCodecs.BYTE_ARRAY, + AdvancedAddEntityPayload::customPayload, + AdvancedAddEntityPayload::new); + public AdvancedAddEntityPayload(Entity e) { + this(e.getId(), writeCustomData(e)); + } + + private static byte[] writeCustomData(final Entity entity) { + if (!(entity instanceof IEntityWithComplexSpawn additionalSpawnData)) { + return new byte[0]; + } + + final RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), entity.registryAccess()); + try { + additionalSpawnData.writeSpawnData(buf); + return buf.array(); + } finally { + buf.release(); + } + } + + @Override + public Type type() { + return TYPE; + } +} diff --git a/modules/entity/src/main/resources/assets/porting_lib_entity/lang/en_us.json b/modules/entity/src/main/resources/assets/porting_lib_entity/lang/en_us.json new file mode 100644 index 000000000..5c02fdb96 --- /dev/null +++ b/modules/entity/src/main/resources/assets/porting_lib_entity/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "porting_lib.network.advanced_add_entity.failed": "Failed to process advanced entity spawn data: %s" +} diff --git a/modules/entity/src/main/resources/fabric.mod.json b/modules/entity/src/main/resources/fabric.mod.json index a425bca1d..07f8a4f7b 100644 --- a/modules/entity/src/main/resources/fabric.mod.json +++ b/modules/entity/src/main/resources/fabric.mod.json @@ -14,13 +14,14 @@ }, "custom": { "loom:injected_interfaces": { - "net/minecraft/class_1291": ["io/github/fabricators_of_create/porting_lib/entity/extensions/MobEffectExtensions"], - "net/minecraft/class_1297": ["io/github/fabricators_of_create/porting_lib/entity/extensions/EntityExtensions"], - "net/minecraft/class_1621": ["io/github/fabricators_of_create/porting_lib/entity/extensions/SlimeExtension"], - "net/minecraft/class_1657": ["io/github/fabricators_of_create/porting_lib/entity/extensions/PlayerExtension"], - "net/minecraft/class_1688": ["io/github/fabricators_of_create/porting_lib/entity/extensions/AbstractMinecartExtensions"], - "net/minecraft/class_1792": ["io/github/fabricators_of_create/porting_lib/entity/extensions/ItemExtensions"], - "net/minecraft/class_1937": ["io/github/fabricators_of_create/porting_lib/entity/extensions/LevelExtensions"] + "net/minecraft/class_1291": ["io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectExt"], + "net/minecraft/class_1293": ["io/github/fabricators_of_create/porting_lib/entity/ext/MobEffectInstanceExt"], + "net/minecraft/class_1297": ["io/github/fabricators_of_create/porting_lib/entity/ext/EntityExt"], + "net/minecraft/class_1621": ["io/github/fabricators_of_create/porting_lib/entity/ext/SlimeExt"], + "net/minecraft/class_1657": ["io/github/fabricators_of_create/porting_lib/entity/ext/PlayerExt"], + "net/minecraft/class_1688": ["io/github/fabricators_of_create/porting_lib/entity/ext/AbstractMinecartExt"], + "net/minecraft/class_1792": ["io/github/fabricators_of_create/porting_lib/entity/ext/ItemExt"], + "net/minecraft/class_1937": ["io/github/fabricators_of_create/porting_lib/entity/ext/LevelExt"] } } } diff --git a/modules/entity/src/main/resources/porting_lib_entity.mixins.json b/modules/entity/src/main/resources/porting_lib_entity.mixins.json index 7eaf0687a..9411d4d7c 100644 --- a/modules/entity/src/main/resources/porting_lib_entity.mixins.json +++ b/modules/entity/src/main/resources/porting_lib_entity.mixins.json @@ -4,6 +4,7 @@ "package": "io.github.fabricators_of_create.porting_lib.entity.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "accessor.PlayerDataStorageAccessor", "common.AbstractArrowMixin", "common.AbstractHorseMixin", "common.AbstractHurtingProjectileMixin", @@ -11,40 +12,39 @@ "common.BlockableEventLoopAccessor", "common.BlockBehaviourMixin", "common.BundlePacketMixin", - "common.CatSpawnerMixin", "common.ChorusFruitItemMixin", "common.EnderManMixin", - "common.EntityAccessor", "common.EntityMixin", "common.ExperienceOrbMixin", "common.FireworkRocketEntityMixin", "common.FishingHookMixin", + "common.FurnaceResultSlotMixin", "common.ItemMixin", "common.LevelMixin", "common.LightningBoltMixin", "common.LivingEntityMixin", "common.LlamaSpitMixin", "common.MagmaCubeMixin", + "common.MobEffectInstanceMixin", "common.MobEffectMixin", "common.MobMixin", - "common.NaturalSpawnerMixin", - "common.PatrolSpawnerMixin", "common.PersistentEntitySectionManager$CallbackMixin", "common.PersistentEntitySectionManagerMixin", - "common.PhantomSpawnerMixin", + "common.PlayerDataStorageMixin", "common.PlayerListMixin", "common.PlayerMixin", - "common.PortalForcerMixin", - "common.ProjectileMixin", "common.ProjectileUtilMixin", + "common.ResultSlotMixin", "common.ServerEntityMixin", + "common.ServerGamePacketListenerImpl$1Mixin", "common.ServerLevelMixin", "common.ServerPlayerGameModeMixin", "common.ServerPlayerMixin", "common.ShulkerBulletMixin", + "common.ShulkerMixin", "common.SlimeMixin", - "common.SpiderMixin", "common.SpreadPlayersCommandMixin", + "common.StartAttackingMixin", "common.TeleportCommandMixin", "common.ThrowableProjectileMixin", "common.ThrownEnderpearlMixin", diff --git a/modules/entity/src/testmod/java/io/github/fabricators_of_create/porting_lib/entity/testmod/CustomSlime.java b/modules/entity/src/testmod/java/io/github/fabricators_of_create/porting_lib/entity/testmod/CustomSlime.java index 1b78bacd6..084d3f564 100644 --- a/modules/entity/src/testmod/java/io/github/fabricators_of_create/porting_lib/entity/testmod/CustomSlime.java +++ b/modules/entity/src/testmod/java/io/github/fabricators_of_create/porting_lib/entity/testmod/CustomSlime.java @@ -1,12 +1,15 @@ package io.github.fabricators_of_create.porting_lib.entity.testmod; -import io.github.fabricators_of_create.porting_lib.entity.PortingLibEntity; +import io.github.fabricators_of_create.porting_lib.entity.EntityHooks; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.server.level.ServerEntity; + import org.jetbrains.annotations.NotNull; -import io.github.fabricators_of_create.porting_lib.entity.IEntityAdditionalSpawnData; +import io.github.fabricators_of_create.porting_lib.entity.IEntityWithComplexSpawn; import io.github.fabricators_of_create.porting_lib.entity.MultiPartEntity; import io.github.fabricators_of_create.porting_lib.entity.PartEntity; import net.minecraft.nbt.CompoundTag; @@ -21,7 +24,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -public class CustomSlime extends Slime implements IEntityAdditionalSpawnData, MultiPartEntity { +public class CustomSlime extends Slime implements IEntityWithComplexSpawn, MultiPartEntity { public final OrbitingItem item; public final PartEntity[] parts; @@ -33,20 +36,15 @@ public CustomSlime(EntityType entityType, Level level) { } @Override - public void writeSpawnData(FriendlyByteBuf buf) { + public void writeSpawnData(RegistryFriendlyByteBuf buf) { buf.writeItem(item.stack); } @Override - public void readSpawnData(FriendlyByteBuf buf) { + public void readSpawnData(RegistryFriendlyByteBuf buf) { item.stack = buf.readItem(); } - @Override - public Packet getAddEntityPacket() { - return PortingLibEntity.getEntitySpawningPacket(this); - } - @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); diff --git a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/BlockEntityExtensions.java b/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/BlockEntityExtensions.java index 2089d9ede..7c045dad7 100644 --- a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/BlockEntityExtensions.java +++ b/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/BlockEntityExtensions.java @@ -1,20 +1,27 @@ package io.github.fabricators_of_create.porting_lib.extensions.extensions; +import io.github.fabricators_of_create.porting_lib.core.PortingLib; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; public interface BlockEntityExtensions { - default CompoundTag getCustomData() { - throw new RuntimeException("this should be overridden via mixin. what?"); - } - - default void deserializeNBT(BlockState state, CompoundTag nbt) { - throw new RuntimeException("this should be overridden via mixin. what?"); + /** + * Gets a {@link CompoundTag} that can be used to store custom data for this block entity. + * It will be written, and read from disc, so it persists over world saves. + * + * @return A compound tag for custom persistent data + */ + default CompoundTag getPersistentData() { + throw PortingLib.createMixinException("getPersistentData()"); } + /** + * Called when this is first added to the world (by {@link LevelChunk#addAndRegisterBlockEntity(BlockEntity)}) + * or right before the first tick when the chunk is generated or loaded from disk. + * Override instead of adding {@code if (firstTick)} stuff in update. + */ default void onLoad() { } - - default void invalidateCaps() { - } } diff --git a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/ItemExtensions.java b/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/ItemExtensions.java index 3e1d5ccba..fe18e5121 100644 --- a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/ItemExtensions.java +++ b/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/ItemExtensions.java @@ -1,12 +1,13 @@ package io.github.fabricators_of_create.porting_lib.extensions.extensions; import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.Item; @@ -15,12 +16,16 @@ import net.minecraft.world.item.SpawnEggItem; import net.minecraft.world.item.TippedArrowItem; import net.minecraft.world.item.alchemy.Potion; -import net.minecraft.world.item.alchemy.PotionUtils; -import net.minecraft.world.level.Level; +import net.minecraft.world.item.alchemy.PotionContents; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.ItemEnchantments; import javax.annotation.Nonnull; import org.jetbrains.annotations.Nullable; +import java.util.Optional; +import java.util.Set; + public interface ItemExtensions { /** * Called before a block is broken. Return true to prevent default block @@ -37,20 +42,6 @@ default boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, Player play return false; } - /** - * Called when the player Left Clicks (attacks) an entity. Processed before - * damage is done, if return value is true further processing is canceled and - * the entity is not attacked. - * - * @param stack The Item being used - * @param player The player that is attacking - * @param entity The entity being attacked - * @return True to cancel the rest of the interaction. - */ - default boolean onLeftClickEntity(ItemStack stack, Player player, Entity entity) { - return false; - } - /** * Called to get the Mod ID of the mod that *created* the ItemStack, instead of * the real Mod ID that *registered* it. @@ -72,37 +63,28 @@ default String getCreatorModId(ItemStack itemStack) { String modId = registryName == null ? null : registryName.getNamespace(); if ("minecraft".equals(modId)) { if (item instanceof EnchantedBookItem) { - ListTag enchantmentsNbt = EnchantedBookItem.getEnchantments(itemStack); - if (enchantmentsNbt.size() == 1) { - CompoundTag nbttagcompound = enchantmentsNbt.getCompound(0); - ResourceLocation resourceLocation = ResourceLocation.tryParse(nbttagcompound.getString("id")); - if (resourceLocation != null && BuiltInRegistries.ENCHANTMENT.containsKey(resourceLocation)) { - return resourceLocation.getNamespace(); + Set> enchantments = itemStack.getOrDefault(DataComponents.STORED_ENCHANTMENTS, ItemEnchantments.EMPTY).keySet(); + if (enchantments.size() == 1) { + Holder enchantmentHolder = enchantments.iterator().next(); + Optional> key = enchantmentHolder.unwrapKey(); + if (key.isPresent()) { + return key.get().location().getNamespace(); } } } else if (item instanceof PotionItem || item instanceof TippedArrowItem) { - Potion potionType = PotionUtils.getPotion(itemStack); - ResourceLocation resourceLocation = BuiltInRegistries.POTION.getKey(potionType); - if (resourceLocation != null) { - return resourceLocation.getNamespace(); + PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + Optional> potionType = potionContents.potion(); + Optional> key = potionType.flatMap(Holder::unwrapKey); + if (key.isPresent()) { + return key.get().location().getNamespace(); } - } else if (item instanceof SpawnEggItem) { - ResourceLocation resourceLocation = BuiltInRegistries.ENTITY_TYPE.getKey(((SpawnEggItem) item).getType(null)); - if (resourceLocation != null) { - return resourceLocation.getNamespace(); + } else if (item instanceof SpawnEggItem spawnEggItem) { + Optional>> key = BuiltInRegistries.ENTITY_TYPE.getResourceKey(spawnEggItem.getType(itemStack)); + if (key.isPresent()) { + return key.get().location().getNamespace(); } } } return modId; } - - /** - * Get the tooltip parts that should be hidden by default on the given stack if the {@code HideFlags} tag is not set. - * @see ItemStack.TooltipPart - * @param stack the stack - * @return the default hide flags - */ - default int getDefaultTooltipHideFlags(@Nonnull ItemStack stack) { - return 0; - } } diff --git a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectInstanceExtensions.java b/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectInstanceExtensions.java deleted file mode 100644 index 8b7158af3..000000000 --- a/modules/extensions/src/main/java/io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectInstanceExtensions.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.extensions.extensions; - -import java.util.List; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.world.item.ItemStack; - -public interface MobEffectInstanceExtensions { - /*** - * Returns a list of curative items for the potion effect - * By default, this list is initialized using {@link MobEffectInstanceExtensions#getCurativeItems()} - * - * @return The list (ItemStack) of curative items for the potion effect - */ - List getCurativeItems(); - - /*** - * Checks the given ItemStack to see if it is in the list of curative items for the potion effect - * @param stack The ItemStack being checked against the list of curative items for this PotionEffect - * @return true if the given ItemStack is in the list of curative items for this PotionEffect, false otherwise - */ - default boolean isCurativeItem(ItemStack stack) { - return this.getCurativeItems().stream().anyMatch(e -> ItemStack.isSameItem(e, stack)); - } - - /*** - * Sets the list of curative items for this potion effect, overwriting any already present - * @param curativeItems The list of ItemStacks being set to the potion effect - */ - void setCurativeItems(List curativeItems); - - /*** - * Adds the given stack to the list of curative items for this PotionEffect - * @param stack The ItemStack being added to the curative item list - */ - default void addCurativeItem(ItemStack stack) { - if (!this.isCurativeItem(stack)) - this.getCurativeItems().add(stack); - } - - default void writeCurativeItems(CompoundTag nbt) { - ListTag list = new ListTag(); - getCurativeItems().forEach(s -> list.add(s.save(new CompoundTag()))); - nbt.put("CurativeItems", list); - } -} diff --git a/modules/extensions/src/main/resources/fabric.mod.json b/modules/extensions/src/main/resources/fabric.mod.json index 20e6f6a11..1b17d1cc5 100644 --- a/modules/extensions/src/main/resources/fabric.mod.json +++ b/modules/extensions/src/main/resources/fabric.mod.json @@ -14,7 +14,6 @@ "net/minecraft/class_804": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/ItemTransformExtensions"], "net/minecraft/class_1044": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/AbstractTextureExtensions"], "net/minecraft/class_1291": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectExtensions"], - "net/minecraft/class_1293": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/MobEffectInstanceExtensions"], "net/minecraft/class_1297": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/INBTSerializableCompound"], "net/minecraft/class_1438": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/IShearable"], "net/minecraft/class_1472": ["io/github/fabricators_of_create/porting_lib/extensions/extensions/IShearable"], diff --git a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/FluidStack.java b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/FluidStack.java index 57cf16ed2..375ada617 100644 --- a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/FluidStack.java +++ b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/FluidStack.java @@ -14,6 +14,10 @@ import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; + +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +import net.fabricmc.fabric.api.transfer.v1.storage.base.ResourceAmount; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderSet; @@ -32,6 +36,7 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.tags.TagKey; import net.minecraft.util.ExtraCodecs; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; @@ -58,7 +63,7 @@ public final class FluidStack implements MutableDataComponentHolder { () -> RecordCodecBuilder.create( instance -> instance.group( FLUID_NON_EMPTY_CODEC.fieldOf("id").forGetter(FluidStack::getFluidHolder), - ExtraCodecs.POSITIVE_INT.fieldOf("amount").forGetter(FluidStack::getAmount), // note: no .orElse(1) compared to ItemStack + PortingLibFluids.POSITIVE_LONG.fieldOf("amount").forGetter(FluidStack::getAmount), // note: no .orElse(1) compared to ItemStack DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY) .forGetter(stack -> stack.components.asPatch())) .apply(instance, FluidStack::new))); @@ -69,7 +74,7 @@ public final class FluidStack implements MutableDataComponentHolder { * *

Fluid equivalent of {@link ItemStack#SINGLE_ITEM_CODEC}. */ - public static Codec fixedAmountCodec(int amount) { + public static Codec fixedAmountCodec(long amount) { return Codec.lazyInitialized( () -> RecordCodecBuilder.create( instance -> instance.group( @@ -92,7 +97,7 @@ public static Codec fixedAmountCodec(int amount) { @Override public FluidStack decode(RegistryFriendlyByteBuf buf) { - int amount = buf.readVarInt(); + long amount = buf.readVarLong(); if (amount <= 0) { return FluidStack.EMPTY; } else { @@ -107,7 +112,7 @@ public void encode(RegistryFriendlyByteBuf buf, FluidStack stack) { if (stack.isEmpty()) { buf.writeVarInt(0); } else { - buf.writeVarInt(stack.getAmount()); + buf.writeVarLong(stack.getAmount()); FLUID_STREAM_CODEC.encode(buf, stack.getFluidHolder()); DataComponentPatch.STREAM_CODEC.encode(buf, stack.components.asPatch()); } @@ -137,8 +142,8 @@ public void encode(RegistryFriendlyByteBuf buf, FluidStack stack) { } }; private static final Logger LOGGER = LogUtils.getLogger(); - public static final FluidStack EMPTY = new FluidStack(null); - private int amount; + public static final FluidStack EMPTY = new FluidStack(null, null); + private long amount; private final Fluid fluid; private final PatchedDataComponentMap components; @@ -155,25 +160,37 @@ public boolean isComponentsPatchEmpty() { return !this.isEmpty() ? ((PatchedDataComponentMapAccessor) (Object) this.components).getPatch().isEmpty() : true; } - public FluidStack(Holder fluid, int amount, DataComponentPatch patch) { + public FluidStack(Holder fluid, long amount, DataComponentPatch patch) { this(fluid.value(), amount, PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, patch)); } - public FluidStack(Holder fluid, int amount) { + public FluidStack(Holder fluid, long amount) { this(fluid.value(), amount); } - public FluidStack(Fluid fluid, int amount) { + public FluidStack(Fluid fluid, long amount) { this(fluid, amount, new PatchedDataComponentMap(DataComponentMap.EMPTY)); } - private FluidStack(Fluid fluid, int amount, PatchedDataComponentMap components) { + public FluidStack(FluidVariant variant, long amount) { + this(variant.getFluid(), amount, PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, variant.getComponents())); + } + + public FluidStack(StorageView view) { + this(view.getResource(), view.getAmount()); + } + + public FluidStack(ResourceAmount resourceAmount) { + this(resourceAmount.resource(), resourceAmount.amount()); + } + + private FluidStack(Fluid fluid, long amount, PatchedDataComponentMap components) { this.fluid = fluid; this.amount = amount; this.components = components; } - private FluidStack(@Nullable Void unused) { + private FluidStack(@Nullable Void unused, @Nullable Void unused1) { this.fluid = null; this.components = new PatchedDataComponentMap(DataComponentMap.EMPTY); } @@ -203,8 +220,8 @@ public boolean isEmpty() { /** * Splits off a stack of the given amount of this stack and reduces this stack by the amount. */ - public FluidStack split(int amount) { - int i = Math.min(amount, this.amount); + public FluidStack split(long amount) { + long i = Math.min(amount, this.amount); FluidStack fluidStack = this.copyWithAmount(i); this.shrink(i); return fluidStack; @@ -305,7 +322,7 @@ public FluidStack copy() { /** * Creates a copy of this fluid stack with the given amount. */ - public FluidStack copyWithAmount(int amount) { + public FluidStack copyWithAmount(long amount) { if (this.isEmpty()) { return EMPTY; } else { @@ -423,21 +440,21 @@ public Component getHoverName() { /** * Returns the amount of this stack. */ - public int getAmount() { + public long getAmount() { return this.isEmpty() ? 0 : this.amount; } /** * Sets the amount of this stack. */ - public void setAmount(int amount) { + public void setAmount(long amount) { this.amount = amount; } /** * Limits the amount of this stack is at most the given amount. */ - public void limitSize(int amount) { + public void limitSize(long amount) { if (!this.isEmpty() && this.getAmount() > amount) { this.setAmount(amount); } @@ -446,14 +463,14 @@ public void limitSize(int amount) { /** * Adds the given amount to this stack. */ - public void grow(int addedAmount) { + public void grow(long addedAmount) { this.setAmount(this.getAmount() + addedAmount); } /** * Removes the given amount from this stack. */ - public void shrink(int removedAmount) { + public void shrink(long removedAmount) { this.grow(-removedAmount); } @@ -466,6 +483,10 @@ public FluidType getFluidType() { return getFluid().getFluidType(); } + public FluidVariant getVariant() { + return FluidVariant.of(this.fluid, this.components.asPatch()); + } + /** * Check if the fluid type of this stack is equal to the given fluid type. */ diff --git a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/PortingLibFluids.java b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/PortingLibFluids.java index bd8ec82d5..bba68f318 100644 --- a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/PortingLibFluids.java +++ b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/PortingLibFluids.java @@ -1,5 +1,8 @@ package io.github.fabricators_of_create.porting_lib.fluids; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; + import org.jetbrains.annotations.Nullable; import io.github.fabricators_of_create.porting_lib.core.PortingLib; @@ -18,7 +21,12 @@ import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.phys.Vec3; +import java.util.function.Function; + public class PortingLibFluids implements ModInitializer { + public static final Codec POSITIVE_LONG = longRangeWithMessage(1, Long.MAX_VALUE, (integer) -> { + return "Value must be positive: " + integer; + }); public static final ResourceKey> FLUID_TYPE_REGISTRY = ResourceKey.createRegistryKey(PortingLib.id("fluid_type")); public static final Registry FLUID_TYPES = FabricRegistryBuilder.createDefaulted(FLUID_TYPE_REGISTRY, PortingLib.id("empty")).buildAndRegister(); @@ -164,4 +172,12 @@ public void onInitialize() { Registry.register(FLUID_TYPES, PortingLib.id("water"), WATER_TYPE); Registry.register(FLUID_TYPES, PortingLib.id("lava"), LAVA_TYPE); } + + private static Codec longRangeWithMessage(long min, long max, Function messageFunction) { + return Codec.LONG.validate((value) -> { + return value.compareTo(min) >= 0 && value.compareTo(max) <= 0 ? DataResult.success(value) : DataResult.error(() -> { + return messageFunction.apply(value); + }); + }); + } } diff --git a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/FluidAttributeFluidType.java b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/FluidAttributeFluidType.java index bb5740fff..993c7072f 100644 --- a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/FluidAttributeFluidType.java +++ b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/FluidAttributeFluidType.java @@ -34,12 +34,12 @@ public Component getDescription() { @Override public int getTemperature(FluidStack stack) { - return handler.getTemperature(stack.getType()); + return handler.getTemperature(stack.getVariant()); } @Override public int getViscosity(FluidStack stack) { - return handler.getViscosity(stack.getType(), null); + return handler.getViscosity(stack.getVariant(), null); } @Override @@ -51,6 +51,6 @@ public int getViscosity(FluidState state, BlockAndTintGetter getter, BlockPos po @Override public int getLightLevel(FluidStack stack) { - return handler.getLuminance(stack.getType()); + return handler.getLuminance(stack.getVariant()); } } diff --git a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/MergingFluidAttributeFluidType.java b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/MergingFluidAttributeFluidType.java index 1af548858..a5b8c9a84 100644 --- a/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/MergingFluidAttributeFluidType.java +++ b/modules/fluids/src/main/java/io/github/fabricators_of_create/porting_lib/fluids/wrapper/MergingFluidAttributeFluidType.java @@ -57,12 +57,12 @@ public Component getDescription() { @Override public int getTemperature(FluidStack stack) { - return handler.getTemperature(stack.getType()); + return handler.getTemperature(stack.getVariant()); } @Override public int getViscosity(FluidStack stack) { - return handler.getViscosity(stack.getType(), null); + return handler.getViscosity(stack.getVariant(), null); } @Override @@ -74,7 +74,7 @@ public int getViscosity(FluidState state, BlockAndTintGetter getter, BlockPos po @Override public int getLightLevel(FluidStack stack) { - return handler.getLuminance(stack.getType()); + return handler.getLuminance(stack.getVariant()); } @Override diff --git a/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/events/GatherComponentsEvent.java b/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/events/GatherComponentsEvent.java index 21c05a454..dd5834b6e 100644 --- a/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/events/GatherComponentsEvent.java +++ b/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/events/GatherComponentsEvent.java @@ -3,6 +3,8 @@ import com.mojang.datafixers.util.Either; import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.network.chat.FormattedText; @@ -13,7 +15,16 @@ import java.util.List; -public class GatherComponentsEvent extends BaseEvent { +/** + * Fired when a tooltip gathers the {@link TooltipComponent}s to be rendered, before any text wrapping or processing. + * The list of components and the maximum width of the tooltip can be modified through this event. + * + *

This event is {@linkplain CancellableEvent cancellable}. + * If this event is cancelled, then the list of components will be empty. + * + *

This event is fired only on the {@linkplain EnvType#CLIENT logical client}.

+ */ +public class GatherComponentsEvent extends BaseEvent implements CancellableEvent { public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { for (Callback c : callbacks) c.onGatherComponents(event); diff --git a/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/extensions/GuiGraphicsExtension.java b/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/extensions/GuiGraphicsExtension.java index dee3ea492..24df169a9 100644 --- a/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/extensions/GuiGraphicsExtension.java +++ b/modules/gui_utils/src/main/java/io/github/fabricators_of_create/porting_lib/gui/extensions/GuiGraphicsExtension.java @@ -1,13 +1,209 @@ package io.github.fabricators_of_create.porting_lib.gui.extensions; import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import java.util.List; +/** + * Extension interface for {@link GuiGraphics}. + */ public interface GuiGraphicsExtension { default void renderComponentTooltip(Font font, List tooltips, int mouseX, int mouseY, ItemStack stack) { throw new RuntimeException("Mixin failed!"); } + + private GuiGraphics self() { + return (GuiGraphics) this; + } + + int DEFAULT_BACKGROUND_COLOR = 0xF0100010; + int DEFAULT_BORDER_COLOR_START = 0x505000FF; + int DEFAULT_BORDER_COLOR_END = (DEFAULT_BORDER_COLOR_START & 0xFEFEFE) >> 1 | DEFAULT_BORDER_COLOR_START & 0xFF000000; + String UNDO_CHAR = "\u21B6"; + String RESET_CHAR = "\u2604"; + String VALID = "\u2714"; + String INVALID = "\u2715"; + int[] TEXT_COLOR_CODES = new int[]{0, 170, 43520, 43690, 11141120, 11141290, 16755200, 11184810, 5592405, 5592575, 5635925, 5636095, 16733525, 16733695, 16777045, 16777215, + 0, 42, 10752, 10794, 2752512, 2752554, 2763264, 2763306, 1381653, 1381695, 1392405, 1392447, 4134165, 4134207, 4144917, 4144959}; + + default int getColorFromFormattingCharacter(char c, boolean isLighter) { + return TEXT_COLOR_CODES[isLighter ? "0123456789abcdef".indexOf(c) : "0123456789abcdef".indexOf(c) + 16]; + } + + /** + * Draws a left-aligned string, with a scrolling effect if the string is too long. + * + * @return the rendered width of the string, never more than {@code maxX - minX} + */ + default int drawScrollingString(Font font, Component text, int minX, int maxX, int y, int color) { + int maxWidth = maxX - minX; + int textWidth = font.width(text.getVisualOrderText()); + if (textWidth <= maxWidth) { + return self().drawString(font, text, minX, y, color); + } else { + AbstractWidget.renderScrollingString(self(), font, text, minX, y, maxX, y + font.lineHeight, color); + return maxWidth; + } + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) + * based on a fixed size textured box with continuous borders and filler. + * + * @param texture the ResourceLocation object that contains the desired image + * @param x x-axis offset + * @param y y-axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param borderSize the size of the box's borders + */ + default void blitWithBorder(ResourceLocation texture, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, int borderSize) { + this.blitWithBorder(texture, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize); + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) + * based on a fixed size textured box with continuous borders and filler. + * + * @param texture the ResourceLocation object that contains the desired image + * @param x x-axis offset + * @param y y-axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param topBorder the size of the box's top border + * @param bottomBorder the size of the box's bottom border + * @param leftBorder the size of the box's left border + * @param rightBorder the size of the box's right border + */ + default void blitWithBorder(ResourceLocation texture, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, int topBorder, int bottomBorder, int leftBorder, int rightBorder) { + int fillerWidth = textureWidth - leftBorder - rightBorder; + int fillerHeight = textureHeight - topBorder - bottomBorder; + int canvasWidth = width - leftBorder - rightBorder; + int canvasHeight = height - topBorder - bottomBorder; + int xPasses = canvasWidth / fillerWidth; + int remainderWidth = canvasWidth % fillerWidth; + int yPasses = canvasHeight / fillerHeight; + int remainderHeight = canvasHeight % fillerHeight; + + // Draw Border + // Top Left + self().blit(texture, x, y, u, v, leftBorder, topBorder); + // Top Right + self().blit(texture, x + leftBorder + canvasWidth, y, u + leftBorder + fillerWidth, v, rightBorder, topBorder); + // Bottom Left + self().blit(texture, x, y + topBorder + canvasHeight, u, v + topBorder + fillerHeight, leftBorder, bottomBorder); + // Bottom Right + self().blit(texture, x + leftBorder + canvasWidth, y + topBorder + canvasHeight, u + leftBorder + fillerWidth, v + topBorder + fillerHeight, rightBorder, bottomBorder); + + for (int i = 0; i < xPasses + (remainderWidth > 0 ? 1 : 0); i++) { + // Top Border + self().blit(texture, x + leftBorder + (i * fillerWidth), y, u + leftBorder, v, (i == xPasses ? remainderWidth : fillerWidth), topBorder); + // Bottom Border + self().blit(texture, x + leftBorder + (i * fillerWidth), y + topBorder + canvasHeight, u + leftBorder, v + topBorder + fillerHeight, (i == xPasses ? remainderWidth : fillerWidth), bottomBorder); + + // Throw in some filler for good measure + for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) + self().blit(texture, x + leftBorder + (i * fillerWidth), y + topBorder + (j * fillerHeight), u + leftBorder, v + topBorder, (i == xPasses ? remainderWidth : fillerWidth), (j == yPasses ? remainderHeight : fillerHeight)); + } + + // Side Borders + for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) { + // Left Border + self().blit(texture, x, y + topBorder + (j * fillerHeight), u, v + topBorder, leftBorder, (j == yPasses ? remainderHeight : fillerHeight)); + // Right Border + self().blit(texture, x + leftBorder + canvasWidth, y + topBorder + (j * fillerHeight), u + leftBorder + fillerWidth, v + topBorder, rightBorder, (j == yPasses ? remainderHeight : fillerHeight)); + } + } + + default void blitInscribed(ResourceLocation texture, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight) { + this.blitInscribed(texture, x, y, boundsWidth, boundsHeight, rectWidth, rectHeight, true, true); + } + + default void blitInscribed(ResourceLocation texture, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight, boolean centerX, boolean centerY) { + if (rectWidth * boundsHeight > rectHeight * boundsWidth) { + int h = boundsHeight; + boundsHeight = (int) (boundsWidth * ((double) rectHeight / rectWidth)); + if (centerY) y += (h - boundsHeight) / 2; + } else { + int w = boundsWidth; + boundsWidth = (int) (boundsHeight * ((double) rectWidth / rectHeight)); + if (centerX) x += (w - boundsWidth) / 2; + } + + self().blit(texture, x, y, boundsWidth, boundsHeight, 0.0f, 0.0f, rectWidth, rectHeight, rectWidth, rectHeight); + } + + // TODO: 1.20.2: do we need to fix these or can we just remove them? + /** + * Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size. + */ + /*default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int sliceSize, int uWidth, int vHeight, int uOffset, int vOffset, + int textureWidth, int textureHeight) + { + blitNineSlicedSized(texture, x, y, width, height, sliceSize, sliceSize, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight); + }*/ + + /** + * Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size. + */ + /*default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int sliceWidth, int sliceHeight, int uWidth, int vHeight, + int uOffset, int vOffset, int textureWidth, int textureHeight) + { + blitNineSlicedSized(texture, x, y, width, height, sliceWidth, sliceHeight, sliceWidth, sliceHeight, uWidth, vHeight, uOffset, vOffset, textureWidth, textureHeight); + }*/ + + /** + * Version of {@link GuiGraphics#blitNineSliced(ResourceLocation, int, int, int, int, int, int, int, int, int, int, int, int)} that supports specifying the texture's size. + */ + /*default void blitNineSlicedSized(ResourceLocation texture, int x, int y, int width, int height, int cornerWidth, int cornerHeight, int edgeWidth, int edgeHeight, + int uWidth, int vHeight, int uOffset, int vOffset, int textureWidth, int textureHeight) + { + cornerWidth = Math.min(cornerWidth, width / 2); + edgeWidth = Math.min(edgeWidth, width / 2); + cornerHeight = Math.min(cornerHeight, height / 2); + edgeHeight = Math.min(edgeHeight, height / 2); + GuiGraphics self = self(); + if (width == uWidth && height == vHeight) + { + self.blit(texture, x, y, uOffset, vOffset, width, height, textureWidth, textureHeight); + } + else if (height == vHeight) + { + self.blit(texture, x, y, uOffset, vOffset, cornerWidth, height, textureWidth, textureHeight); + self.blitRepeating(texture, x + cornerWidth, y, width - edgeWidth - cornerWidth, height, uOffset + cornerWidth, vOffset, uWidth - edgeWidth - cornerWidth, vHeight, textureWidth, textureHeight); + self.blit(texture, x + width - edgeWidth, y, uOffset + uWidth - edgeWidth, vOffset, edgeWidth, height, textureWidth, textureHeight); + } + else if (width == uWidth) + { + self.blit(texture, x, y, uOffset, vOffset, width, cornerHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x, y + cornerHeight, width, height - edgeHeight - cornerHeight, uOffset, vOffset + cornerHeight, uWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight); + self.blit(texture, x, y + height - edgeHeight, uOffset, vOffset + vHeight - edgeHeight, width, edgeHeight, textureWidth, textureHeight); + } + else + { + self.blit(texture, x, y, uOffset, vOffset, cornerWidth, cornerHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x + cornerWidth, y, width - edgeWidth - cornerWidth, cornerHeight, uOffset + cornerWidth, vOffset, uWidth - edgeWidth - cornerWidth, cornerHeight, textureWidth, textureHeight); + self.blit(texture, x + width - edgeWidth, y, uOffset + uWidth - edgeWidth, vOffset, edgeWidth, cornerHeight, textureWidth, textureHeight); + self.blit(texture, x, y + height - edgeHeight, uOffset, vOffset + vHeight - edgeHeight, cornerWidth, edgeHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x + cornerWidth, y + height - edgeHeight, width - edgeWidth - cornerWidth, edgeHeight, uOffset + cornerWidth, vOffset + vHeight - edgeHeight, uWidth - edgeWidth - cornerWidth, edgeHeight, textureWidth, textureHeight); + self.blit(texture, x + width - edgeWidth, y + height - edgeHeight, uOffset + uWidth - edgeWidth, vOffset + vHeight - edgeHeight, edgeWidth, edgeHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x, y + cornerHeight, cornerWidth, height - edgeHeight - cornerHeight, uOffset, vOffset + cornerHeight, cornerWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x + cornerWidth, y + cornerHeight, width - edgeWidth - cornerWidth, height - edgeHeight - cornerHeight, uOffset + cornerWidth, vOffset + cornerHeight, uWidth - edgeWidth - cornerWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight); + self.blitRepeating(texture, x + width - edgeWidth, y + cornerHeight, cornerWidth, height - edgeHeight - cornerHeight, uOffset + uWidth - edgeWidth, vOffset + cornerHeight, edgeWidth, vHeight - edgeHeight - cornerHeight, textureWidth, textureHeight); + } + }*/ } diff --git a/modules/gui_utils/src/main/resources/porting_lib_gui_utils.accesswidener b/modules/gui_utils/src/main/resources/porting_lib_gui_utils.accesswidener index a6505a7ea..f84a7446a 100644 --- a/modules/gui_utils/src/main/resources/porting_lib_gui_utils.accesswidener +++ b/modules/gui_utils/src/main/resources/porting_lib_gui_utils.accesswidener @@ -7,3 +7,5 @@ accessible field net/minecraft/client/gui/components/Button$Builder y I accessible field net/minecraft/client/gui/components/Button$Builder width I accessible field net/minecraft/client/gui/components/Button$Builder height I accessible field net/minecraft/client/gui/components/Button$Builder createNarration Lnet/minecraft/client/gui/components/Button$CreateNarration; + +transitive-accessible method net/minecraft/client/gui/components/AbstractWidget renderScrollingString (Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/gui/Font;Lnet/minecraft/network/chat/Component;IIIII)V diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/BlockSnapshot.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/BlockSnapshot.java new file mode 100644 index 000000000..282e18341 --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/BlockSnapshot.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package io.github.fabricators_of_create.porting_lib.level; + +import java.lang.ref.WeakReference; +import java.util.Objects; + +import io.github.fabricators_of_create.porting_lib.core.util.ServerLifecycleHooks; +import io.github.fabricators_of_create.porting_lib.level.events.BlockEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a captured snapshot of a block, including the level, position, state, BE data, and setBlock flags. + *

+ * Used to record the prior state and unwind changes if the change was denied, such as during {@link BlockEvent.BreakEvent}. + */ +public class BlockSnapshot { + private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("porting-lib.debugBlockSnapshot", "false")); + private static final Logger LOGGER = LogManager.getLogger(); + + private final ResourceKey dim; + private final BlockPos pos; + private final int flags; + private final BlockState state; + @Nullable + private final CompoundTag nbt; + + private WeakReference level; + @Nullable + private String toString = null; + + private BlockSnapshot(ResourceKey dim, LevelAccessor level, BlockPos pos, BlockState state, @Nullable CompoundTag nbt, int flags) { + this.dim = dim; + this.pos = pos.immutable(); + this.state = state; + this.flags = flags; + this.nbt = nbt; + + this.level = new WeakReference<>(level); + + if (DEBUG) { + LOGGER.debug("Created " + this.toString()); + } + } + + /** + * Creates a new snapshot of the data at the given position. + * + * @param dim The dimension of the changed block + * @param level The level of the changed block + * @param pos The position of the changed block + * @param flag The {@link Level#setBlock(BlockPos, BlockState, int)} flags that the block was changed with. + * @return A captured block snapshot, containing the state and BE data from the given position. + */ + public static BlockSnapshot create(ResourceKey dim, LevelAccessor level, BlockPos pos, int flag) { + return new BlockSnapshot(dim, level, pos, level.getBlockState(pos), getBlockEntityTag(level, pos), flag); + } + + /** + * Creates a new snapshot with the default block flags ({@link Block#UPDATE_NEIGHBORS and Block#UPDATE_CLIENTS}. + * + * @see #create(ResourceKey, LevelAccessor, BlockPos, int) + */ + public static BlockSnapshot create(ResourceKey dim, LevelAccessor level, BlockPos pos) { + return create(dim, level, pos, 3); + } + + /** + * {@return the recorded dimension key} + */ + public ResourceKey getDimension() { + return this.dim; + } + + /** + * {@return the recorded position} + */ + public BlockPos getPos() { + return pos; + } + + /** + * @return the recorded {@link Level#setBlock(BlockPos, BlockState, int)} flags + */ + public int getFlags() { + return flags; + } + + /** + * {@return the recorded block entity NBT data, if one was present} + */ + @Nullable + public CompoundTag getTag() { + return nbt; + } + + /** + * {@return the snapshot's recorded block state} + */ + public BlockState getState() { + return this.state; + } + + /** + * {@return the stored level, attempting to resolve it from the current server if it has gone out of scope} + */ + @Nullable + public LevelAccessor getLevel() { + LevelAccessor level = this.level.get(); + if (level == null) { + level = ServerLifecycleHooks.getCurrentServer().getLevel(this.dim); + this.level = new WeakReference<>(level); + } + return level; + } + + /** + * {@return the current (live) block state at the recorded position, not the snapshot's recorded state} + */ + public BlockState getCurrentState() { + LevelAccessor level = this.getLevel(); + return level == null ? Blocks.AIR.defaultBlockState() : level.getBlockState(this.pos); + } + + /** + * Recreates a block entity from the stored data (pos/state/NBT) of this block snapshot. + * + * @return The newly created block entity, or null if no NBT data was present, or it was invalid. + */ + @Nullable + public BlockEntity recreateBlockEntity(HolderLookup.Provider provider) { + return getTag() != null ? BlockEntity.loadStatic(getPos(), getState(), getTag(), provider) : null; + } + + /** + * Restores this block snapshot to the target level and position with the specified flags. + * + * @return true if the block was successfully updated, false otherwise. + */ + public boolean restoreToLocation(LevelAccessor level, BlockPos pos, int flags) { + BlockState replaced = getState(); + + if (!level.setBlock(pos, replaced, flags)) { + return false; + } + + if (level instanceof Level realLevel) { + BlockState current = getCurrentState(); + realLevel.sendBlockUpdated(pos, current, replaced, flags); + } + + restoreBlockEntity(level, pos); + + if (DEBUG) { + LOGGER.debug("Restored " + this.toString()); + } + + return true; + } + + /** + * Calls {@link #restoreToLocation} with the stored level, position, but custom block flags. + */ + public boolean restore(int flags) { + return restoreToLocation(getLevel(), getPos(), flags); + } + + /** + * Calls {@link #restoreToLocation} with the stored level, position, and block flags. + */ + public boolean restore() { + return restore(this.getFlags()); + } + + /** + * Loads the stored {@link BlockEntity} data if one exists at the given position. + * + * @return true if any data was loaded + */ + public boolean restoreBlockEntity(LevelAccessor level, BlockPos pos) { + BlockEntity be = null; + if (getTag() != null) { + be = level.getBlockEntity(pos); + if (be != null) { + be.loadWithComponents(getTag(), level.registryAccess()); + be.setChanged(); + return true; + } + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + + final BlockSnapshot other = (BlockSnapshot) obj; + return this.dim.equals(other.dim) && + this.pos.equals(other.pos) && + this.state == other.state && + this.flags == other.flags && + Objects.equals(this.nbt, other.nbt); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 73 * hash + this.dim.hashCode(); + hash = 73 * hash + this.pos.hashCode(); + hash = 73 * hash + this.state.hashCode(); + hash = 73 * hash + this.flags; + hash = 73 * hash + Objects.hashCode(this.getTag()); + return hash; + } + + @Override + public String toString() { + if (toString == null) { + this.toString = "BlockSnapshot[" + + "Level:" + this.dim.location() + ',' + + "Pos: " + this.pos + ',' + + "State: " + this.state + ',' + + "Flags: " + this.flags + ',' + + "NBT: " + (this.nbt == null ? "null" : this.nbt.toString()) + + ']'; + } + return this.toString; + } + + /** + * Checks for a block entity at a given position, and saves it to NBT with full metadata if it exists. + */ + @Nullable + private static CompoundTag getBlockEntityTag(LevelAccessor level, BlockPos pos) { + BlockEntity be = level.getBlockEntity(pos); + return be == null ? null : be.saveWithFullMetadata(level.registryAccess()); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/LevelHooks.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/LevelHooks.java new file mode 100644 index 000000000..bfb882f1d --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/LevelHooks.java @@ -0,0 +1,117 @@ +package io.github.fabricators_of_create.porting_lib.level; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; + +import io.github.fabricators_of_create.porting_lib.level.events.BlockEvent; +import io.github.fabricators_of_create.porting_lib.level.events.LevelEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.block.GameMasterBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.ServerLevelData; + +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; +import java.util.List; + +public class LevelHooks { + public static boolean onCreateWorldSpawn(Level level, ServerLevelData settings) { + return new LevelEvent.CreateSpawnPosition(level, settings).post(); + } + + private static final WeightedRandomList NO_SPAWNS = WeightedRandomList.create(); + + public static WeightedRandomList getPotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList oldList) { + LevelEvent.PotentialSpawns event = new LevelEvent.PotentialSpawns(level, category, pos, oldList); + if (event.post()) + return NO_SPAWNS; + else if (event.getSpawnerDataList() == oldList.unwrap()) + return oldList; + return WeightedRandomList.create(event.getSpawnerDataList()); + } + + /** + * Fires {@link BlockEvent.BreakEvent}, pre-emptively canceling the event based on the conditions that will cause the block to not be broken anyway. + *

+ * Note that undoing the pre-cancel will not permit breaking the block, since the vanilla conditions will always be checked. + * + * @param level The level + * @param gameType The game type of the breaking player + * @param player The breaking player + * @param pos The position of the block being broken + * @param state The state of the block being broken + * @return The event + */ + public static BlockEvent.BreakEvent fireBlockBreak(Level level, GameType gameType, ServerPlayer player, BlockPos pos, BlockState state) { + return fireBlockBreak(level, gameType, player, pos, state, args -> { + return ((Item) args[0]).canAttackBlock((BlockState) args[1], (Level) args[2], (BlockPos) args[3], (Player) args[4]); + }); + } + + public static BlockEvent.BreakEvent fireBlockBreak(Level level, GameType gameType, ServerPlayer player, BlockPos pos, BlockState state, Operation original) { + boolean preCancelEvent = false; + + ItemStack itemstack = player.getMainHandItem(); + if (!itemstack.isEmpty() && !original.call(itemstack.getItem(), state, level, pos, player)) { + preCancelEvent = true; + } + + if (player.blockActionRestricted(level, pos, gameType)) { + preCancelEvent = true; + } + + if (state.getBlock() instanceof GameMasterBlock && !player.canUseGameMasterBlocks()) { + preCancelEvent = true; + } + + // Post the block break event + BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(level, pos, state, player); + event.setCanceled(preCancelEvent); + event.sendEvent(); + + // If the event is canceled, let the client know the block still exists + if (event.isCanceled()) { + player.connection.send(new ClientboundBlockUpdatePacket(pos, state)); + } + + return event; + } + + public static boolean onMultiBlockPlace(@Nullable Entity entity, List blockSnapshots, Direction direction) { + BlockSnapshot snap = blockSnapshots.get(0); + BlockState placedAgainst = snap.getLevel().getBlockState(snap.getPos().relative(direction.getOpposite())); + BlockEvent.EntityMultiPlaceEvent event = new BlockEvent.EntityMultiPlaceEvent(blockSnapshots, placedAgainst, entity); + return event.post(); + } + + public static boolean onBlockPlace(@Nullable Entity entity, BlockSnapshot blockSnapshot, Direction direction) { + BlockState placedAgainst = blockSnapshot.getLevel().getBlockState(blockSnapshot.getPos().relative(direction.getOpposite())); + BlockEvent.EntityPlaceEvent event = new BlockEvent.EntityPlaceEvent(blockSnapshot, placedAgainst, entity); + return event.post(); + } + + public static BlockEvent.NeighborNotifyEvent onNeighborNotify(Level level, BlockPos pos, BlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { + BlockEvent.NeighborNotifyEvent event = new BlockEvent.NeighborNotifyEvent(level, pos, state, notifiedSides, forceRedstoneUpdate); + event.sendEvent(); + return event; + } + + public static BlockState fireFluidPlaceBlockEvent(LevelAccessor level, BlockPos pos, BlockPos liquidPos, BlockState state) { + BlockEvent.FluidPlaceBlockEvent event = new BlockEvent.FluidPlaceBlockEvent(level, pos, liquidPos, state); + event.sendEvent(); + return event.getNewState(); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockDropsEvent.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockDropsEvent.java new file mode 100644 index 000000000..aad56f682 --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockDropsEvent.java @@ -0,0 +1,122 @@ +package io.github.fabricators_of_create.porting_lib.level.events; + +import com.google.common.base.Preconditions; +import java.util.List; + +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +/** + * Fired when a block is broken and the drops have been determined, but before they have been added to the world. This event can be used to manipulate the dropped items and experience. + *

+ * No guarantees can be made about the block. It will either have already been removed from the world, or will be removed after the event terminates. + *

+ * If you wish to edit the state of the block in-world, use {@link BreakEvent}. + */ +public class BlockDropsEvent extends BlockEvent implements CancellableEvent { + @Nullable + private final BlockEntity blockEntity; + private final List drops; + @Nullable + private final Entity breaker; + private final ItemStack tool; + private int experience; + + /** + * Constructs a new BlockDropsEvent + * + * @param level The level of the broken block + * @param pos The position of the broken block + * @param state The state of the broken block + * @param blockEntity The block entity of the broken block, if available + * @param drops The list of drops from {@link Block#getDrops} + * @param breaker The entity who broke the block, if any + * @param tool The tool used to break the block. May be empty + */ + public BlockDropsEvent(ServerLevel level, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, List drops, @Nullable Entity breaker, ItemStack tool) { + super(level, pos, state); + this.blockEntity = blockEntity; + this.drops = drops; + this.breaker = breaker; + this.tool = tool; + + this.experience = EnchantmentHelper.processBlockExperience(level, tool, state.getExpDrop(level, pos, blockEntity, breaker, tool)); + } + + /** + * Returns a mutable list of item entities that will be dropped by this block. + *

+ * When this event completes successfully, all entities in this list will be added to the world. + * + * @return A mutable list of item entities. + * @apiNote Prefer using {@link LootModifier}s to add additional loot drops. + */ + public List getDrops() { + return this.drops; + } + + /** + * {@return the block entity from the current position, if available} + */ + @Nullable + public BlockEntity getBlockEntity() { + return blockEntity; + } + + /** + * {@return the entity that broke the block, or null if unknown} + */ + @Nullable + public Entity getBreaker() { + return this.breaker; + } + + /** + * {@return the tool used when breaking this block; may be empty} + */ + public ItemStack getTool() { + return this.tool; + } + + /** + * Cancels this event, preventing any drops from being spawned and preventing {@link Block#spawnAfterBreak} from being called. + *

+ * Also prevents experience from being spawned. + */ + @Override + public void setCanceled(boolean canceled) { + CancellableEvent.super.setCanceled(canceled); + } + + @Override + public ServerLevel getLevel() { + return (ServerLevel) super.getLevel(); + } + + /** + * {@return the amount of experience points that will be dropped by the block} + */ + public int getDroppedExperience() { + return experience; + } + + /** + * Set the amount of experience points that will be dropped by the block. This is the true value, after enchantments have been applied. + * + * @param experience The new amount. Must not be negative. + * @apiNote When cancelled, no experience is dropped, regardless of this value. + */ + public void setDroppedExperience(int experience) { + Preconditions.checkArgument(experience >= 0, "May not set a negative experience drop."); + this.experience = experience; + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockEvent.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockEvent.java new file mode 100644 index 000000000..67e983c6b --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/BlockEvent.java @@ -0,0 +1,465 @@ +package io.github.fabricators_of_create.porting_lib.level.events; + +import com.google.common.collect.ImmutableList; +import java.util.EnumSet; +import java.util.List; + +import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import io.github.fabricators_of_create.porting_lib.level.BlockSnapshot; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.BaseFireBlock; +import net.minecraft.world.level.block.GameMasterBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.portal.PortalShape; +import org.jetbrains.annotations.Nullable; + +public abstract class BlockEvent extends BaseEvent { + private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("porting-lib.debugBlockEvent", "false")); + + private final LevelAccessor level; + private final BlockPos pos; + private final BlockState state; + + public BlockEvent(LevelAccessor level, BlockPos pos, BlockState state) { + this.pos = pos; + this.level = level; + this.state = state; + } + + public LevelAccessor getLevel() { + return level; + } + + public BlockPos getPos() { + return pos; + } + + public BlockState getState() { + return state; + } + + /** + * This event is fired on the server when a player attempts to break a block, upon receipt of a block break packet. + * + * The following conditions may cause this event to fire in a cancelled state: + *

    + *
  • If {@link Player#blockActionRestricted} is true.
  • + *
  • If the target block is a {@link GameMasterBlock} and {@link Player#canUseGameMasterBlocks()} is false.
  • + *
  • If the the player is holding an item, and {@link Item#canAttackBlock} is false.
  • + *
+ * + * In the first two cases, un-cancelling the event will not permit the block to be broken. + * In the third case, un-cancelling will allow the break, bypassing the behavior of {@link Item#canAttackBlock}. + */ + public static class BreakEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onBlockBreak(event); + }); + + private final Player player; + + public BreakEvent(Level level, BlockPos pos, BlockState state, Player player) { + super(level, pos, state); + this.player = player; + } + + /** + * {@return the player who is attempting to break the block} + */ + public Player getPlayer() { + return player; + } + + /** + * Cancelling this event will prevent the block from being broken, and notifies the client of the refusal. + */ + @Override + public void setCanceled(boolean canceled) { + CancellableEvent.super.setCanceled(canceled); + } + + @Override + public void sendEvent() { + EVENT.invoker().onBlockBreak(this); + } + + public interface Callback { + void onBlockBreak(BlockEvent event); + } + } + + /** + * Called when a block is placed. + * + * If a Block Place event is cancelled, the block will not be placed. + */ + public static class EntityPlaceEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onEntityPlace(event); + }); + + private final Entity entity; + private final BlockSnapshot blockSnapshot; + private final BlockState placedBlock; + private final BlockState placedAgainst; + + public EntityPlaceEvent(BlockSnapshot blockSnapshot, BlockState placedAgainst, @Nullable Entity entity) { + super(blockSnapshot.getLevel(), blockSnapshot.getPos(), !(entity instanceof Player) ? blockSnapshot.getState() : blockSnapshot.getCurrentState()); + this.entity = entity; + this.blockSnapshot = blockSnapshot; + this.placedBlock = !(entity instanceof Player) ? blockSnapshot.getState() : blockSnapshot.getCurrentState(); + this.placedAgainst = placedAgainst; + + if (DEBUG) { + System.out.printf("Created EntityPlaceEvent - [PlacedBlock: %s ][PlacedAgainst: %s ][Entity: %s ]\n", getPlacedBlock(), placedAgainst, entity); + } + } + + @Nullable + public Entity getEntity() { + return entity; + } + + public BlockSnapshot getBlockSnapshot() { + return blockSnapshot; + } + + public BlockState getPlacedBlock() { + return placedBlock; + } + + public BlockState getPlacedAgainst() { + return placedAgainst; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityPlace(this); + } + + public interface Callback { + void onEntityPlace(EntityPlaceEvent event); + } + } + + /** + * Fired when a single block placement triggers the + * creation of multiple blocks(e.g. placing a bed block). The block returned + * by {@link #state} and its related methods is the block where + * the placed block would exist if the placement only affected a single + * block. + */ + public static class EntityMultiPlaceEvent extends EntityPlaceEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onEntityMultiPlace(event); + }); + + private final List blockSnapshots; + + public EntityMultiPlaceEvent(List blockSnapshots, BlockState placedAgainst, @Nullable Entity entity) { + super(blockSnapshots.get(0), placedAgainst, entity); + this.blockSnapshots = ImmutableList.copyOf(blockSnapshots); + if (DEBUG) { + System.out.printf("Created EntityMultiPlaceEvent - [PlacedAgainst: %s ][Entity: %s ]\n", placedAgainst, entity); + } + } + + /** + * Gets a list of BlockSnapshots for all blocks which were replaced by the + * placement of the new blocks. Most of these blocks will just be of type AIR. + * + * @return immutable list of replaced BlockSnapshots + */ + public List getReplacedBlockSnapshots() { + return blockSnapshots; + } + + @Override + public void sendEvent() { + EVENT.invoker().onEntityMultiPlace(this); + } + + public interface Callback { + void onEntityMultiPlace(EntityMultiPlaceEvent event); + } + } + + /** + * Fired when a physics update occurs on a block. This event acts as + * a way for mods to detect physics updates, in the same way a BUD switch + * does. This event is only called on the server. + */ + public static class NeighborNotifyEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onNeighborNotify(event); + }); + + private final EnumSet notifiedSides; + private final boolean forceRedstoneUpdate; + + public NeighborNotifyEvent(Level level, BlockPos pos, BlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { + super(level, pos, state); + this.notifiedSides = notifiedSides; + this.forceRedstoneUpdate = forceRedstoneUpdate; + } + + /** + * Gets a list of directions from the base block that updates will occur upon. + * + * @return list of notified directions + */ + public EnumSet getNotifiedSides() { + return notifiedSides; + } + + /** + * Get if redstone update was forced during setBlock call (0x16 to flags) + * + * @return if the flag was set + */ + public boolean getForceRedstoneUpdate() { + return forceRedstoneUpdate; + } + + @Override + public void sendEvent() { + EVENT.invoker().onNeighborNotify(this); + } + + public interface Callback { + void onNeighborNotify(NeighborNotifyEvent event); + } + } + + /** + * Fired when a liquid places a block. Use {@link #setNewState(BlockState)} to change the result of + * a cobblestone generator or add variants of obsidian. Alternatively, you could execute + * arbitrary code when lava sets blocks on fire, even preventing it. + * + * {@link #getState()} will return the block that was originally going to be placed. + * {@link #getPos()} will return the position of the block to be changed. + */ + public static class FluidPlaceBlockEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onFluidPlaceBlock(event); + }); + + private final BlockPos liquidPos; + private BlockState newState; + private BlockState origState; + + public FluidPlaceBlockEvent(LevelAccessor level, BlockPos pos, BlockPos liquidPos, BlockState state) { + super(level, pos, state); + this.liquidPos = liquidPos; + this.newState = state; + this.origState = level.getBlockState(pos); + } + + /** + * @return The position of the liquid this event originated from. This may be the same as {@link #getPos()}. + */ + public BlockPos getLiquidPos() { + return liquidPos; + } + + /** + * @return The block state that will be placed after this event resolves. + */ + public BlockState getNewState() { + return newState; + } + + public void setNewState(BlockState state) { + this.newState = state; + } + + /** + * @return The state of the block to be changed before the event was fired. + */ + public BlockState getOriginalState() { + return origState; + } + + @Override + public void sendEvent() { + EVENT.invoker().onFluidPlaceBlock(this); + } + + public interface Callback { + void onFluidPlaceBlock(FluidPlaceBlockEvent event); + } + } + + /** + * Fired when when farmland gets trampled + * This event is {@link CancellableEvent} + */ + public static class FarmlandTrampleEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onFarmlandTrample(event); + }); + + private final Entity entity; + private final float fallDistance; + + public FarmlandTrampleEvent(Level level, BlockPos pos, BlockState state, float fallDistance, Entity entity) { + super(level, pos, state); + this.entity = entity; + this.fallDistance = fallDistance; + } + + public Entity getEntity() { + return entity; + } + + public float getFallDistance() { + return fallDistance; + } + + @Override + public void sendEvent() { + EVENT.invoker().onFarmlandTrample(this); + } + + public interface Callback { + void onFarmlandTrample(FarmlandTrampleEvent event); + } + } + + /** + * Fired when an attempt is made to spawn a nether portal from + * {@link BaseFireBlock#onPlace(BlockState, Level, BlockPos, BlockState, boolean)}. + * + * If cancelled, the portal will not be spawned. + */ + public static class PortalSpawnEvent extends BlockEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onPortalSpawn(event); + }); + + private final PortalShape size; + + public PortalSpawnEvent(LevelAccessor level, BlockPos pos, BlockState state, PortalShape size) { + super(level, pos, state); + this.size = size; + } + + public PortalShape getPortalSize() { + return size; + } + + @Override + public void sendEvent() { + EVENT.invoker().onPortalSpawn(this); + } + + public interface Callback { + void onPortalSpawn(PortalSpawnEvent event); + } + } + +// /** +// * Fired when a block is right-clicked by a tool to change its state. +// * For example: Used to determine if {@link ToolActions#AXE_STRIP an axe can strip}, +// * {@link ToolActions#SHOVEL_FLATTEN a shovel can path}, or {@link ToolActions#HOE_TILL a hoe can till}. +// *

+// * Care must be taken to ensure level-modifying events are only performed if {@link #isSimulated()} returns {@code false}. +// *

+// * This event is {@link CancellableEvent}. If canceled, this will prevent the tool +// * from changing the block's state. +// */ +// public static class BlockToolModificationEvent extends BlockEvent implements CancellableEvent { +// private final UseOnContext context; +// private final ToolAction toolAction; +// private final boolean simulate; +// private BlockState state; +// +// public BlockToolModificationEvent(BlockState originalState, UseOnContext context, ToolAction toolAction, boolean simulate) { +// super(context.getLevel(), context.getClickedPos(), originalState); +// this.context = context; +// this.state = originalState; +// this.toolAction = toolAction; +// this.simulate = simulate; +// } +// +// /** +// * @return the player using the tool. +// * May be null based on what was provided by {@link #getContext() the use on context}. +// */ +// @Nullable +// public Player getPlayer() { +// return this.context.getPlayer(); +// } +// +// /** +// * @return the tool being used +// */ +// public ItemStack getHeldItemStack() { +// return this.context.getItemInHand(); +// } +// +// /** +// * @return the action being performed +// */ +// public ToolAction getToolAction() { +// return this.toolAction; +// } +// +// /** +// * Returns {@code true} if this event should not perform any actions that modify the level. +// * If {@code false}, then level-modifying actions can be performed. +// * +// * @return {@code true} if this event should not perform any actions that modify the level. +// * If {@code false}, then level-modifying actions can be performed. +// */ +// public boolean isSimulated() { +// return this.simulate; +// } +// +// /** +// * Returns the nonnull use on context that this event was performed in. +// * +// * @return the nonnull use on context that this event was performed in +// */ +// public UseOnContext getContext() { +// return context; +// } +// +// /** +// * Sets the state to transform the block into after tool use. +// * +// * @param finalState the state to transform the block into after tool use +// * @see #getFinalState() +// */ +// public void setFinalState(@Nullable BlockState finalState) { +// this.state = finalState; +// } +// +// /** +// * Returns the state to transform the block into after tool use. +// * If {@link #setFinalState(BlockState)} is not called, this will return the original state. +// * If {@link #isCanceled()} is {@code true}, this value will be ignored and the tool action will be canceled. +// * +// * @return the state to transform the block into after tool use +// */ +// public BlockState getFinalState() { +// return state; +// } +// } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/LevelEvent.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/LevelEvent.java index c954a31d1..7e02e039b 100644 --- a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/LevelEvent.java +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/LevelEvent.java @@ -1,7 +1,31 @@ package io.github.fabricators_of_create.porting_lib.level.events; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import io.github.fabricators_of_create.porting_lib.core.event.BaseEvent; +import io.github.fabricators_of_create.porting_lib.core.event.CancellableEvent; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.ReceivingLevelScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ProgressListener; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.storage.ServerLevelData; +import org.jetbrains.annotations.Nullable; /** * This event is fired whenever an event involving a {@link LevelAccessor} occurs. @@ -9,16 +33,232 @@ public abstract class LevelEvent extends BaseEvent { private final LevelAccessor level; - public LevelEvent(LevelAccessor level) - { + public LevelEvent(LevelAccessor level) { this.level = level; } /** * {@return the level this event is affecting} */ - public LevelAccessor getLevel() - { + public LevelAccessor getLevel() { return level; } + + /** + * This event is fired whenever a level loads. + * This event is fired whenever a level loads in ClientLevel's constructor and + * {@literal MinecraftServer#createLevels(ChunkProgressListener)}. + *

+ * This event is not {@linkplain CancellableEvent cancellable}. + *

+ * This event is fired on both logical sides. + **/ + public static class Load extends LevelEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onLoad(event); + }); + + public Load(LevelAccessor level) { + super(level); + } + + @Override + public void sendEvent() { + EVENT.invoker().onLoad(this); + } + + public interface Callback { + void onLoad(Load event); + } + } + + /** + * This event is fired whenever a level unloads. + * This event is fired whenever a level unloads in + * {@link Minecraft#setLevel(ClientLevel, ReceivingLevelScreen.Reason)}, + * {@link MinecraftServer#stopServer()}, + * {@link Minecraft#disconnect(Screen, boolean)}. + *

+ * This event is not {@linkplain CancellableEvent cancellable}. + *

+ * This event is fired on both logical sides. + **/ + public static class Unload extends LevelEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onUnload(event); + }); + + public Unload(LevelAccessor level) { + super(level); + } + + @Override + public void sendEvent() { + EVENT.invoker().onUnload(this); + } + + public interface Callback { + void onUnload(Unload event); + } + } + + /** + * This event fires whenever a level is saved. + * This event is fired when a level is saved in + * {@link ServerLevel#save(ProgressListener, boolean, boolean)}. + *

+ * This event is not {@linkplain CancellableEvent cancellable}. + *

+ * This event is fired only on the {@linkplain EnvType#SERVER logical server}. + **/ + public static class Save extends LevelEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onSave(event); + }); + + public Save(LevelAccessor level) { + super(level); + } + + @Override + public void sendEvent() { + EVENT.invoker().onSave(this); + } + + public interface Callback { + void onSave(Save event); + } + } + + /** + * This event fires whenever a {@link ServerLevel} is initialized for the first time + * and a spawn position needs to be chosen. + *

+ * This event is {@linkplain CancellableEvent cancellable}. + * If the event is canceled, the vanilla logic to choose a spawn position will be skipped. + *

+ * This event is fired only on the {@linkplain EnvType#SERVER logical server}. + * + * @see ServerLevelData#isInitialized() + */ + public static class CreateSpawnPosition extends LevelEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onCreateSpawnPosition(event); + }); + + private final ServerLevelData settings; + + public CreateSpawnPosition(LevelAccessor level, ServerLevelData settings) { + super(level); + this.settings = settings; + } + + public ServerLevelData getSettings() { + return settings; + } + + @Override + public void sendEvent() { + EVENT.invoker().onCreateSpawnPosition(this); + } + + public interface Callback { + void onCreateSpawnPosition(CreateSpawnPosition event); + } + } + + /** + * Fired when building a list of all possible entities that can spawn at the specified location. + * + *

If an entry is added to the list, it needs to be a globally unique instance.

+ * + * The event is called in {@link net.minecraft.world.level.NaturalSpawner#mobsAt(ServerLevel, + * StructureManager, ChunkGenerator, MobCategory, BlockPos, Holder)}.

+ * + *

This event is {@linkplain CancellableEvent cancellable},. + * Canceling the event will result in an empty list, meaning no entity will be spawned.

+ */ + public static class PotentialSpawns extends LevelEvent implements CancellableEvent { + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback callback : callbacks) + callback.onPotentialSpawn(event); + }); + + private final MobCategory mobcategory; + private final BlockPos pos; + @Nullable + private List list; + private List view; + + public PotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList oldList) { + super(level); + this.pos = pos; + this.mobcategory = category; + this.list = null; + this.view = oldList.unwrap(); + } + + /** + * {@return the category of the mobs in the spawn list.} + */ + public MobCategory getMobCategory() { + return mobcategory; + } + + /** + * {@return the block position where the chosen mob will be spawned.} + */ + public BlockPos getPos() { + return pos; + } + + /** + * {@return the list of mobs that can potentially be spawned.} + */ + public List getSpawnerDataList() { + return view; + } + + private void makeList() { + if (list == null) { + list = new ArrayList<>(view); + view = Collections.unmodifiableList(list); + } + } + + /** + * Appends a SpawnerData entry to the spawn list. + * + * @param data SpawnerData entry to be appended to the spawn list. + */ + public void addSpawnerData(MobSpawnSettings.SpawnerData data) { + makeList(); + list.add(data); + } + + /** + * Removes a SpawnerData entry from the spawn list. + * + * @param data SpawnerData entry to be removed from the spawn list. + * + * {@return {@code true} if the spawn list contained the specified element.} + */ + public boolean removeSpawnerData(MobSpawnSettings.SpawnerData data) { + makeList(); + return list.remove(data); + } + + @Override + public void sendEvent() { + EVENT.invoker().onPotentialSpawn(this); + } + + public interface Callback { + void onPotentialSpawn(PotentialSpawns event); + } + } } diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/SleepFinishedTimeEvent.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/SleepFinishedTimeEvent.java index 345af29d9..4c5455ce5 100644 --- a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/SleepFinishedTimeEvent.java +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/events/SleepFinishedTimeEvent.java @@ -10,8 +10,8 @@ * setTimeAddition(wakeUpTime) sets a new time that will be added to the dayTime.
*/ public class SleepFinishedTimeEvent extends LevelEvent { - public static final Event SLEEP_FINISHED = EventFactory.createArrayBacked(SleepFinishedCallback.class, callbacks -> event -> { - for (SleepFinishedCallback e : callbacks) + public static final Event EVENT = EventFactory.createArrayBacked(Callback.class, callbacks -> event -> { + for (Callback e : callbacks) e.onSleepFinished(event); }); private long newTime; @@ -45,11 +45,11 @@ public boolean setTimeAddition(long newTimeIn) { @Override public void sendEvent() { - SLEEP_FINISHED.invoker().onSleepFinished(this); + EVENT.invoker().onSleepFinished(this); } @FunctionalInterface - public interface SleepFinishedCallback { + public interface Callback { void onSleepFinished(SleepFinishedTimeEvent event); } } diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/ServerLevelMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/ServerLevelMixin.java deleted file mode 100644 index aac239ce8..000000000 --- a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/ServerLevelMixin.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.fabricators_of_create.porting_lib.level.mixin; - -import io.github.fabricators_of_create.porting_lib.level.events.SleepFinishedTimeEvent; -import net.minecraft.core.Holder; -import net.minecraft.core.RegistryAccess; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; - -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.world.level.Level; - -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.storage.WritableLevelData; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArg; - -import java.util.function.Supplier; - -@Mixin(ServerLevel.class) -public abstract class ServerLevelMixin extends Level { - protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey resourceKey, RegistryAccess registryAccess, Holder holder, Supplier supplier, boolean bl, boolean bl2, long l, int i) { - super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i); - } - - @ModifyArg(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;setDayTime(J)V")) - private long sleepFinishedEvent(long newTime) { - SleepFinishedTimeEvent event = new SleepFinishedTimeEvent((ServerLevel) (Object) this, newTime, getDayTime()); - event.sendEvent(); - return event.getNewTime(); - } -} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/ClientLevelMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/ClientLevelMixin.java new file mode 100644 index 000000000..3c93c83fc --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/ClientLevelMixin.java @@ -0,0 +1,35 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.client; + +import io.github.fabricators_of_create.porting_lib.level.events.LevelEvent; +import net.minecraft.client.multiplayer.ClientLevel; + +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; + +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; + +import net.minecraft.world.level.storage.WritableLevelData; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.Supplier; + +@Mixin(ClientLevel.class) +public abstract class ClientLevelMixin extends Level { + protected ClientLevelMixin(WritableLevelData writableLevelData, ResourceKey resourceKey, RegistryAccess registryAccess, Holder holder, Supplier supplier, boolean bl, boolean bl2, long l, int i) { + super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i); + } + + @Inject(method = "", at = @At("TAIL")) + private void onLoad(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, Holder holder, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) { + new LevelEvent.Load(this).sendEvent(); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/MinecraftMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/MinecraftMixin.java new file mode 100644 index 000000000..13d82bc80 --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/client/MinecraftMixin.java @@ -0,0 +1,37 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.client; + +import io.github.fabricators_of_create.porting_lib.level.events.LevelEvent; +import net.minecraft.client.Minecraft; + +import net.minecraft.client.gui.screens.ReceivingLevelScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.multiplayer.ClientLevel; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Shadow + @Nullable + public ClientLevel level; + + @Inject(method = "setLevel", at = @At("HEAD")) + private void onUnload(ClientLevel clientLevel, ReceivingLevelScreen.Reason reason, CallbackInfo ci) { + if (this.level != null) new LevelEvent.Unload(this.level).sendEvent(); + } + + @Inject(method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;Z)V", at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;level:Lnet/minecraft/client/multiplayer/ClientLevel;", + ordinal = 0, + shift = At.Shift.AFTER + )) + private void onDisconnect(Screen screen, boolean bl, CallbackInfo ci) { + new LevelEvent.Unload(this.level).sendEvent(); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DiodeBlockMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/DiodeBlockMixin.java similarity index 73% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DiodeBlockMixin.java rename to modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/DiodeBlockMixin.java index b19970d5c..afca12b9f 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/DiodeBlockMixin.java +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/DiodeBlockMixin.java @@ -1,11 +1,10 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; +package io.github.fabricators_of_create.porting_lib.level.mixin.common; -import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; +import io.github.fabricators_of_create.porting_lib.level.events.BlockEvent; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.DiodeBlock; - import net.minecraft.world.level.block.HorizontalDirectionalBlock; import net.minecraft.world.level.block.state.BlockState; @@ -19,7 +18,7 @@ public class DiodeBlockMixin { @Inject(method = "updateNeighborsInFront", at = @At("HEAD"), cancellable = true) private void notifyNeighborsEvent(Level pLevel, BlockPos pPos, BlockState blockState, CallbackInfo ci) { Direction direction = blockState.getValue(HorizontalDirectionalBlock.FACING); - BlockEvents.NeighborNotifyEvent event = new BlockEvents.NeighborNotifyEvent(pLevel, pPos, pLevel.getBlockState(pPos), java.util.EnumSet.of(direction.getOpposite()), false); + BlockEvent.NeighborNotifyEvent event = new BlockEvent.NeighborNotifyEvent(pLevel, pPos, pLevel.getBlockState(pPos), java.util.EnumSet.of(direction.getOpposite()), false); event.sendEvent(); if (event.isCanceled()) ci.cancel(); diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LavaFluidMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LavaFluidMixin.java new file mode 100644 index 000000000..aced0acbd --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LavaFluidMixin.java @@ -0,0 +1,27 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.common; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import io.github.fabricators_of_create.porting_lib.level.LevelHooks; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.LavaFluid; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(LavaFluid.class) +public class LavaFluidMixin { + @WrapOperation(method = "randomTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;setBlockAndUpdate(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)Z")) + private boolean onFluidPlace(Level instance, BlockPos blockPos, BlockState blockState, Operation original, Level p_230572_, BlockPos p_230573_) { + return original.call(instance, blockPos, LevelHooks.fireFluidPlaceBlockEvent(instance, blockPos, p_230573_, blockState)); + } + + @WrapOperation(method = "spreadTo", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/LevelAccessor;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z")) + private boolean onFluidPlaceSpread(LevelAccessor instance, BlockPos blockPos, BlockState blockState, int updateType, Operation original) { + return original.call(instance, blockPos, LevelHooks.fireFluidPlaceBlockEvent(instance, blockPos, blockPos, blockState), updateType); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LevelMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LevelMixin.java new file mode 100644 index 000000000..793b17c8c --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/LevelMixin.java @@ -0,0 +1,30 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.common; + +import io.github.fabricators_of_create.porting_lib.level.events.BlockEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; + +import net.minecraft.world.level.block.Block; + +import net.minecraft.world.level.block.state.BlockState; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.EnumSet; + +@Mixin(Level.class) +public abstract class LevelMixin { + @Shadow + public abstract BlockState getBlockState(BlockPos blockPos); + + @Inject(method = "updateNeighborsAt", at = @At("HEAD")) + private void neighborNotify(BlockPos pPos, Block block, CallbackInfo ci) { + BlockEvent.NeighborNotifyEvent event = new BlockEvent.NeighborNotifyEvent((Level) (Object) this, pPos, getBlockState(pPos), EnumSet.allOf(Direction.class), false); + event.sendEvent(); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/MinecraftServerMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/MinecraftServerMixin.java new file mode 100644 index 000000000..a6508c24d --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,57 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.common; + +import com.llamalad7.mixinextras.sugar.Local; + +import io.github.fabricators_of_create.porting_lib.level.LevelHooks; +import io.github.fabricators_of_create.porting_lib.level.events.LevelEvent; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; + +import net.minecraft.world.level.Level; + +import net.minecraft.world.level.storage.ServerLevelData; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + @Shadow + @Final + private Map, ServerLevel> levels; + + @Inject(method = "createLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/ServerLevelData;isInitialized()Z")) + private void onLoadOverworld(ChunkProgressListener chunkProgressListener, CallbackInfo ci) { + new LevelEvent.Load(this.levels.get(Level.OVERWORLD)).sendEvent(); + } + + @Inject(method = "createLevels", at = @At( + value = "INVOKE", + target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + ordinal = 1, + shift = At.Shift.AFTER + )) + private void onLoadWorld(ChunkProgressListener chunkProgressListener, CallbackInfo ci, @Local(index = 18) ResourceKey key) { + new LevelEvent.Load(levels.get(key)).sendEvent(); + } + + @Inject(method = "stopServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;close()V")) + private void onStopServer(CallbackInfo ci, @Local(index = 2) ServerLevel serverLevel) { + new LevelEvent.Unload(serverLevel).sendEvent(); + } + + @Inject(method = "setInitialSpawn", at = @At(value = "NEW", target = "(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/ChunkPos;"), cancellable = true) + private static void onCreateWorldSpawn(ServerLevel serverLevel, ServerLevelData serverLevelData, boolean bl, boolean bl2, CallbackInfo ci) { + if (LevelHooks.onCreateWorldSpawn(serverLevel, serverLevelData)) + ci.cancel(); + } +} diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/NaturalSpawnerMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/NaturalSpawnerMixin.java new file mode 100644 index 000000000..8debaa0db --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/NaturalSpawnerMixin.java @@ -0,0 +1,29 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.common; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + +import io.github.fabricators_of_create.porting_lib.level.LevelHooks; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.NaturalSpawner; + +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.MobSpawnSettings; + +import net.minecraft.world.level.chunk.ChunkGenerator; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(NaturalSpawner.class) +public class NaturalSpawnerMixin { + @ModifyReturnValue(method = "mobsAt", at = @At("RETURN")) + private static WeightedRandomList modifyMobs(WeightedRandomList original, ServerLevel serverLevel, StructureManager structureManager, ChunkGenerator chunkGenerator, MobCategory mobCategory, BlockPos blockPos, @Nullable Holder holder) { + return LevelHooks.getPotentialSpawns(serverLevel, mobCategory, blockPos, original); + } +} diff --git a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ServerLevelMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerLevelMixin.java similarity index 57% rename from modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ServerLevelMixin.java rename to modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerLevelMixin.java index a7474fafd..b2d74e151 100644 --- a/modules/base/src/main/java/io/github/fabricators_of_create/porting_lib/mixin/common/ServerLevelMixin.java +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerLevelMixin.java @@ -1,6 +1,8 @@ -package io.github.fabricators_of_create.porting_lib.mixin.common; +package io.github.fabricators_of_create.porting_lib.level.mixin.common; -import io.github.fabricators_of_create.porting_lib.event.common.BlockEvents; +import io.github.fabricators_of_create.porting_lib.level.events.BlockEvent; +import io.github.fabricators_of_create.porting_lib.level.events.LevelEvent; +import io.github.fabricators_of_create.porting_lib.level.events.SleepFinishedTimeEvent; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -8,16 +10,18 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ProgressListener; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.storage.WritableLevelData; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.EnumSet; @@ -29,9 +33,23 @@ protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey directions =EnumSet.allOf(Direction.class); directions.remove(pSkipSide); - BlockEvents.NeighborNotifyEvent event = new BlockEvents.NeighborNotifyEvent(this, pPos, this.getBlockState(pPos), directions, false); + BlockEvent.NeighborNotifyEvent event = new BlockEvent.NeighborNotifyEvent(this, pPos, this.getBlockState(pPos), directions, false); event.sendEvent(); if (event.isCanceled()) ci.cancel(); diff --git a/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerPlayerGameModeMixin.java b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerPlayerGameModeMixin.java new file mode 100644 index 000000000..9bc965efe --- /dev/null +++ b/modules/level_events/src/main/java/io/github/fabricators_of_create/porting_lib/level/mixin/common/ServerPlayerGameModeMixin.java @@ -0,0 +1,33 @@ +package io.github.fabricators_of_create.porting_lib.level.mixin.common; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import io.github.fabricators_of_create.porting_lib.level.LevelHooks; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ServerPlayerGameMode.class) +public class ServerPlayerGameModeMixin { + @Shadow + private GameType gameModeForPlayer; + + @WrapOperation(method = "destroyBlock", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/Item;canAttackBlock(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;)Z" + )) + private boolean onBlockBreak(Item instance, BlockState blockState, Level level, BlockPos blockPos, Player player, Operation original) { + return !LevelHooks.fireBlockBreak(level, this.gameModeForPlayer, (ServerPlayer) player, blockPos, blockState, original).isCanceled(); + } +} diff --git a/modules/level_events/src/main/resources/porting_lib_level_events.mixins.json b/modules/level_events/src/main/resources/porting_lib_level_events.mixins.json index 9743f50ff..529258b6c 100644 --- a/modules/level_events/src/main/resources/porting_lib_level_events.mixins.json +++ b/modules/level_events/src/main/resources/porting_lib_level_events.mixins.json @@ -7,6 +7,16 @@ "defaultRequire": 1 }, "mixins": [ - "ServerLevelMixin" + "client.ClientLevelMixin", + "common.DiodeBlockMixin", + "common.LavaFluidMixin", + "common.LevelMixin", + "common.MinecraftServerMixin", + "common.NaturalSpawnerMixin", + "common.ServerLevelMixin", + "common.ServerPlayerGameModeMixin" + ], + "client": [ + "client.MinecraftMixin" ] } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/Tags.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/Tags.java index fbb041e8b..56acec11c 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/Tags.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/Tags.java @@ -1,108 +1,115 @@ package io.github.fabricators_of_create.porting_lib.tags; -import java.util.Set; -import java.util.function.Supplier; - -import net.fabricmc.api.ModInitializer; - -import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; -import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags; -import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; -import net.minecraft.world.entity.EntityType; - -import net.minecraft.world.item.Tiers; - -import org.jetbrains.annotations.Nullable; - import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.FluidTags; +import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; +import net.minecraft.world.damagesource.DamageType; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.Item; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.material.Fluid; -public class Tags implements ModInitializer { - @Override - public void onInitialize() { - Blocks.init(); - EntityTypes.init(); - Items.init(); - Fluids.init(); - Biomes.init(); - } - +public class Tags { public static class Blocks { - private static void init() { - } + // `neoforge` tags for functional behavior provided by NeoForge + /** + * Controls what blocks Endermen cannot place blocks onto. + *

+ * This is patched into the following method: {@link net.minecraft.world.entity.monster.EnderMan.EndermanLeaveBlockGoal#canPlaceBlock(Level, BlockPos, BlockState, BlockState, BlockState, BlockPos)} + */ + public static final TagKey ENDERMAN_PLACE_ON_BLACKLIST = neoforgeTag("enderman_place_on_blacklist"); + public static final TagKey NEEDS_WOOD_TOOL = neoforgeTag("needs_wood_tool"); + public static final TagKey NEEDS_GOLD_TOOL = neoforgeTag("needs_gold_tool"); + public static final TagKey NEEDS_NETHERITE_TOOL = neoforgeTag("needs_netherite_tool"); + // `c` tags for common conventions public static final TagKey BARRELS = tag("barrels"); - public static final TagKey BARRELS_WOODEN = tag("wooden_barrels"); - public static final TagKey BOOKSHELVES = ConventionalBlockTags.BOOKSHELVES; - public static final TagKey CHESTS = ConventionalBlockTags.CHESTS; - public static final TagKey CHESTS_ENDER = tag("ender_chests"); - public static final TagKey CHESTS_TRAPPED = tag("trapped_chests"); - public static final TagKey CHESTS_WOODEN = tag("wooden_chests"); - public static final TagKey COBBLESTONE = tag("cobblestone"); - public static final TagKey COBBLESTONE_NORMAL = tag("normal_cobblestone"); - public static final TagKey COBBLESTONE_INFESTED = tag("infested_cobblestone"); - public static final TagKey COBBLESTONE_MOSSY = tag("mossy_cobblestone"); - public static final TagKey COBBLESTONE_DEEPSLATE = tag("deepslate_cobblestone"); + public static final TagKey BARRELS_WOODEN = tag("barrels/wooden"); + public static final TagKey BOOKSHELVES = tag("bookshelves"); + /** + * For blocks that are similar to amethyst where their budding block produces buds and cluster blocks + */ + public static final TagKey BUDDING_BLOCKS = tag("budding_blocks"); + /** + * For blocks that are similar to amethyst where they have buddings forming from budding blocks + */ + public static final TagKey BUDS = tag("buds"); + public static final TagKey CHAINS = tag("chains"); + public static final TagKey CHESTS = tag("chests"); + public static final TagKey CHESTS_ENDER = tag("chests/ender"); + public static final TagKey CHESTS_TRAPPED = tag("chests/trapped"); + public static final TagKey CHESTS_WOODEN = tag("chests/wooden"); + /** + * For blocks that are similar to amethyst where they have clusters forming from budding blocks + */ + public static final TagKey CLUSTERS = tag("clusters"); + public static final TagKey COBBLESTONES = tag("cobblestones"); + public static final TagKey COBBLESTONES_NORMAL = tag("cobblestones/normal"); + public static final TagKey COBBLESTONES_INFESTED = tag("cobblestones/infested"); + public static final TagKey COBBLESTONES_MOSSY = tag("cobblestones/mossy"); + public static final TagKey COBBLESTONES_DEEPSLATE = tag("cobblestones/deepslate"); + public static final TagKey CONCRETES = tag("concretes"); + + /** + * Tag that holds all blocks that can be dyed a specific color. + * (Does not include color blending blocks that would behave similar to leather armor item) + */ + public static final TagKey DYED = tag("dyed"); + public static final TagKey DYED_BLACK = tag("dyed/black"); + public static final TagKey DYED_BLUE = tag("dyed/blue"); + public static final TagKey DYED_BROWN = tag("dyed/brown"); + public static final TagKey DYED_CYAN = tag("dyed/cyan"); + public static final TagKey DYED_GRAY = tag("dyed/gray"); + public static final TagKey DYED_GREEN = tag("dyed/green"); + public static final TagKey DYED_LIGHT_BLUE = tag("dyed/light_blue"); + public static final TagKey DYED_LIGHT_GRAY = tag("dyed/light_gray"); + public static final TagKey DYED_LIME = tag("dyed/lime"); + public static final TagKey DYED_MAGENTA = tag("dyed/magenta"); + public static final TagKey DYED_ORANGE = tag("dyed/orange"); + public static final TagKey DYED_PINK = tag("dyed/pink"); + public static final TagKey DYED_PURPLE = tag("dyed/purple"); + public static final TagKey DYED_RED = tag("dyed/red"); + public static final TagKey DYED_WHITE = tag("dyed/white"); + public static final TagKey DYED_YELLOW = tag("dyed/yellow"); public static final TagKey END_STONES = tag("end_stones"); - public static final TagKey ENDERMAN_PLACE_ON_BLACKLIST = tag("enderman_place_on_blacklist"); public static final TagKey FENCE_GATES = tag("fence_gates"); - public static final TagKey FENCE_GATES_WOODEN = tag("wooden_fence_gates"); + public static final TagKey FENCE_GATES_WOODEN = tag("fence_gates/wooden"); public static final TagKey FENCES = tag("fences"); - public static final TagKey FENCES_NETHER_BRICK = tag("nether_brick_fences"); - public static final TagKey FENCES_WOODEN = tag("wooden_fences"); - - public static final TagKey GLASS = ConventionalBlockTags.GLASS_BLOCKS; - public static final TagKey GLASS_BLACK = tag("black_glass"); - public static final TagKey GLASS_BLUE = tag("blue_glass"); - public static final TagKey GLASS_BROWN = tag("brown_glass"); - public static final TagKey GLASS_COLORLESS = tag("colorless_glass"); - public static final TagKey GLASS_CYAN = tag("cyan_glass"); - public static final TagKey GLASS_GRAY = tag("gray_glass"); - public static final TagKey GLASS_GREEN = tag("green_glass"); - public static final TagKey GLASS_LIGHT_BLUE = tag("light_blue_glass"); - public static final TagKey GLASS_LIGHT_GRAY = tag("light_gray_glass"); - public static final TagKey GLASS_LIME = tag("lime_glass"); - public static final TagKey GLASS_MAGENTA = tag("magenta_glass"); - public static final TagKey GLASS_ORANGE = tag("orange_glass"); - public static final TagKey GLASS_PINK = tag("pink_glass"); - public static final TagKey GLASS_PURPLE = tag("purple_glass"); - public static final TagKey GLASS_RED = tag("red_glass"); - /** - * Glass which is made from sand and only minor additional ingredients like dyes - */ - public static final TagKey GLASS_SILICA = tag("silica_glass"); - public static final TagKey GLASS_TINTED = tag("tinted_glass"); - public static final TagKey GLASS_WHITE = tag("white_glass"); - public static final TagKey GLASS_YELLOW = tag("yellow_glass"); - - public static final TagKey GLASS_PANES = ConventionalBlockTags.GLASS_PANES; - public static final TagKey GLASS_PANES_BLACK = tag("black_glass_panes"); - public static final TagKey GLASS_PANES_BLUE = tag("blue_glass_panes"); - public static final TagKey GLASS_PANES_BROWN = tag("brown_glass_panes"); - public static final TagKey GLASS_PANES_COLORLESS = tag("colorless_glass_panes"); - public static final TagKey GLASS_PANES_CYAN = tag("cyan_glass_panes"); - public static final TagKey GLASS_PANES_GRAY = tag("gray_glass_panes"); - public static final TagKey GLASS_PANES_GREEN = tag("green_glass_panes"); - public static final TagKey GLASS_PANES_LIGHT_BLUE = tag("light_blue_glass_panes"); - public static final TagKey GLASS_PANES_LIGHT_GRAY = tag("light_gray_glass_panes"); - public static final TagKey GLASS_PANES_LIME = tag("lime_glass_panes"); - public static final TagKey GLASS_PANES_MAGENTA = tag("magenta_glass_panes"); - public static final TagKey GLASS_PANES_ORANGE = tag("orange_glass_panes"); - public static final TagKey GLASS_PANES_PINK = tag("pink_glass_panes"); - public static final TagKey GLASS_PANES_PURPLE = tag("purple_glass_panes"); - public static final TagKey GLASS_PANES_RED = tag("red_glass_panes"); - public static final TagKey GLASS_PANES_WHITE = tag("white_glass_panes"); - public static final TagKey GLASS_PANES_YELLOW = tag("yellow_glass_panes"); - - public static final TagKey GRAVEL = tag("gravel"); - public static final TagKey NETHERRACK = tag("netherrack"); - public static final TagKey OBSIDIAN = tag("obsidian"); + public static final TagKey FENCES_NETHER_BRICK = tag("fences/nether_brick"); + public static final TagKey FENCES_WOODEN = tag("fences/wooden"); + + public static final TagKey GLASS_BLOCKS = tag("glass_blocks"); + public static final TagKey GLASS_BLOCKS_COLORLESS = tag("glass_blocks/colorless"); + /** + * Glass which is made from cheap resources like sand and only minor additional ingredients like dyes + */ + public static final TagKey GLASS_BLOCKS_CHEAP = tag("glass_blocks/cheap"); + public static final TagKey GLASS_BLOCKS_TINTED = tag("glass_blocks/tinted"); + + public static final TagKey GLASS_PANES = tag("glass_panes"); + public static final TagKey GLASS_PANES_COLORLESS = tag("glass_panes/colorless"); + public static final TagKey GLAZED_TERRACOTTAS = tag("glazed_terracottas"); + + public static final TagKey GRAVELS = tag("gravels"); + /** + * Tag that holds all blocks that recipe viewers should not show to users. + * Recipe viewers may use this to automatically find the corresponding BlockItem to hide. + */ + public static final TagKey HIDDEN_FROM_RECIPE_VIEWERS = tag("hidden_from_recipe_viewers"); + public static final TagKey NETHERRACKS = tag("netherracks"); + public static final TagKey OBSIDIANS = tag("obsidians"); /** * Blocks which are often replaced by deepslate ores, i.e. the ores in the tag {@link #ORES_IN_GROUND_DEEPSLATE}, during world generation */ @@ -128,16 +135,16 @@ private static void init() { */ public static final TagKey ORE_RATES_SPARSE = tag("ore_rates/sparse"); public static final TagKey ORES = tag("ores"); - public static final TagKey ORES_COAL = tag("coal_ores"); - public static final TagKey ORES_COPPER = tag("copper_ores"); - public static final TagKey ORES_DIAMOND = tag("diamond_ores"); - public static final TagKey ORES_EMERALD = tag("emerald_ores"); - public static final TagKey ORES_GOLD = tag("gold_ores"); - public static final TagKey ORES_IRON = tag("iron_ores"); - public static final TagKey ORES_LAPIS = tag("lapis_ores"); - public static final TagKey ORES_NETHERITE_SCRAP = tag("netherite_scrap_ores"); - public static final TagKey ORES_QUARTZ = ConventionalBlockTags.QUARTZ_ORES; - public static final TagKey ORES_REDSTONE = tag("redstone_ores"); + public static final TagKey ORES_COAL = tag("ores/coal"); + public static final TagKey ORES_COPPER = tag("ores/copper"); + public static final TagKey ORES_DIAMOND = tag("ores/diamond"); + public static final TagKey ORES_EMERALD = tag("ores/emerald"); + public static final TagKey ORES_GOLD = tag("ores/gold"); + public static final TagKey ORES_IRON = tag("ores/iron"); + public static final TagKey ORES_LAPIS = tag("ores/lapis"); + public static final TagKey ORES_NETHERITE_SCRAP = tag("ores/netherite_scrap"); + public static final TagKey ORES_QUARTZ = tag("ores/quartz"); + public static final TagKey ORES_REDSTONE = tag("ores/redstone"); /** * Ores in deepslate (or in equivalent blocks in the tag {@link #ORE_BEARING_GROUND_DEEPSLATE}) which could logically use deepslate as recipe input or output */ @@ -150,67 +157,154 @@ private static void init() { * Ores in stone (or in equivalent blocks in the tag {@link #ORE_BEARING_GROUND_STONE}) which could logically use stone as recipe input or output */ public static final TagKey ORES_IN_GROUND_STONE = tag("ores_in_ground/stone"); + public static final TagKey PLAYER_WORKSTATIONS_CRAFTING_TABLES = tag("player_workstations/crafting_tables"); + public static final TagKey PLAYER_WORKSTATIONS_FURNACES = tag("player_workstations/furnaces"); + /** + * Blocks should be included in this tag if their movement/relocation can cause serious issues such + * as world corruption upon being moved or for balance reason where the block should not be able to be relocated. + * Example: Chunk loaders or pipes where other mods that move blocks do not respect + * {@link BlockBehaviour.BlockStateBase#getPistonPushReaction}. + */ + public static final TagKey RELOCATION_NOT_SUPPORTED = tag("relocation_not_supported"); + public static final TagKey ROPES = tag("ropes"); - public static final TagKey SAND = tag("sand"); - public static final TagKey SAND_COLORLESS = tag("colorless_sand"); - public static final TagKey SAND_RED = tag("red_sand"); + public static final TagKey SANDS = tag("sands"); + public static final TagKey SANDS_COLORLESS = tag("sands/colorless"); + public static final TagKey SANDS_RED = tag("sands/red"); - public static final TagKey SANDSTONE = tag("sandstone"); - public static final TagKey STAINED_GLASS = tag("stained_glass"); - public static final TagKey STAINED_GLASS_PANES = tag("stained_glass_panes"); - public static final TagKey STONE = tag("stone"); + public static final TagKey SANDSTONE_BLOCKS = tag("sandstone/blocks"); + public static final TagKey SANDSTONE_SLABS = tag("sandstone/slabs"); + public static final TagKey SANDSTONE_STAIRS = tag("sandstone/stairs"); + public static final TagKey SANDSTONE_RED_BLOCKS = tag("sandstone/red_blocks"); + public static final TagKey SANDSTONE_RED_SLABS = tag("sandstone/red_slabs"); + public static final TagKey SANDSTONE_RED_STAIRS = tag("sandstone/red_stairs"); + public static final TagKey SANDSTONE_UNCOLORED_BLOCKS = tag("sandstone/uncolored_blocks"); + public static final TagKey SANDSTONE_UNCOLORED_SLABS = tag("sandstone/uncolored_slabs"); + public static final TagKey SANDSTONE_UNCOLORED_STAIRS = tag("sandstone/uncolored_stairs"); + /** + * Tag that holds all head based blocks such as Skeleton Skull or Player Head. (Named skulls to match minecraft:skulls item tag) + */ + public static final TagKey SKULLS = tag("skulls"); + /** + * Natural stone-like blocks that can be used as a base ingredient in recipes that takes stone. + */ + public static final TagKey STONES = tag("stones"); + /** + * A storage block is generally a block that has a recipe to craft a bulk of 1 kind of resource to a block + * and has a mirror recipe to reverse the crafting with no loss in resources. + *

+ * Honey Block is special in that the reversing recipe is not a perfect mirror of the crafting recipe + * and so, it is considered a special case and not given a storage block tag. + */ public static final TagKey STORAGE_BLOCKS = tag("storage_blocks"); - public static final TagKey STORAGE_BLOCKS_AMETHYST = tag("amethyst_blocks"); - public static final TagKey STORAGE_BLOCKS_COAL = tag("coal_blocks"); - public static final TagKey STORAGE_BLOCKS_COPPER = tag("copper_blocks"); - public static final TagKey STORAGE_BLOCKS_DIAMOND = tag("diamond_blocks"); - public static final TagKey STORAGE_BLOCKS_EMERALD = tag("emerald_blocks"); - public static final TagKey STORAGE_BLOCKS_GOLD = tag("gold_blocks"); - public static final TagKey STORAGE_BLOCKS_IRON = tag("iron_blocks"); - public static final TagKey STORAGE_BLOCKS_LAPIS = tag("lapis_blocks"); - public static final TagKey STORAGE_BLOCKS_NETHERITE = tag("netherite_blocks"); - public static final TagKey STORAGE_BLOCKS_QUARTZ = tag("quartz_blocks"); - public static final TagKey STORAGE_BLOCKS_RAW_COPPER = tag("raw_copper_blocks"); - public static final TagKey STORAGE_BLOCKS_RAW_GOLD = tag("raw_gold_blocks"); - public static final TagKey STORAGE_BLOCKS_RAW_IRON = tag("raw_iron_blocks"); - public static final TagKey STORAGE_BLOCKS_REDSTONE = tag("redstone_blocks"); - - public static final TagKey NEEDS_WOOD_TOOL = tag("needs_wood_tool"); - public static final TagKey NEEDS_GOLD_TOOL = tag("needs_gold_tool"); - public static final TagKey NEEDS_NETHERITE_TOOL = MiningLevelManager.getBlockTag(Tiers.NETHERITE.getLevel()); + public static final TagKey STORAGE_BLOCKS_BONE_MEAL = tag("storage_blocks/bone_meal"); + public static final TagKey STORAGE_BLOCKS_COAL = tag("storage_blocks/coal"); + public static final TagKey STORAGE_BLOCKS_COPPER = tag("storage_blocks/copper"); + public static final TagKey STORAGE_BLOCKS_DIAMOND = tag("storage_blocks/diamond"); + public static final TagKey STORAGE_BLOCKS_DRIED_KELP = tag("storage_blocks/dried_kelp"); + public static final TagKey STORAGE_BLOCKS_EMERALD = tag("storage_blocks/emerald"); + public static final TagKey STORAGE_BLOCKS_GOLD = tag("storage_blocks/gold"); + public static final TagKey STORAGE_BLOCKS_IRON = tag("storage_blocks/iron"); + public static final TagKey STORAGE_BLOCKS_LAPIS = tag("storage_blocks/lapis"); + public static final TagKey STORAGE_BLOCKS_NETHERITE = tag("storage_blocks/netherite"); + public static final TagKey STORAGE_BLOCKS_RAW_COPPER = tag("storage_blocks/raw_copper"); + public static final TagKey STORAGE_BLOCKS_RAW_GOLD = tag("storage_blocks/raw_gold"); + public static final TagKey STORAGE_BLOCKS_RAW_IRON = tag("storage_blocks/raw_iron"); + public static final TagKey STORAGE_BLOCKS_REDSTONE = tag("storage_blocks/redstone"); + public static final TagKey STORAGE_BLOCKS_SLIME = tag("storage_blocks/slime"); + public static final TagKey STORAGE_BLOCKS_WHEAT = tag("storage_blocks/wheat"); + public static final TagKey VILLAGER_JOB_SITES = tag("villager_job_sites"); private static TagKey tag(String name) { return TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("c", name)); } + + private static TagKey neoforgeTag(String name) { + return TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("neoforge", name)); + } } public static class EntityTypes { - private static void init() {} - public static final TagKey> BOSSES = tag("bosses"); + public static final TagKey> MINECARTS = tag("minecarts"); + public static final TagKey> BOATS = tag("boats"); + + /** + * Entities should be included in this tag if they are not allowed to be picked up by items or grabbed in a way + * that a player can easily move the entity to anywhere they want. Ideal for special entities that should not + * be able to be put into a mob jar for example. + */ + public static final TagKey> CAPTURING_NOT_SUPPORTED = tag("capturing_not_supported"); + + /** + * Entities should be included in this tag if they are not allowed to be teleported in any way. + * This is more for mods that allow teleporting entities within the same dimension. Any mod that is + * teleporting entities to new dimensions should be checking canChangeDimensions method on the entity itself. + */ + public static final TagKey> TELEPORTING_NOT_SUPPORTED = tag("teleporting_not_supported"); private static TagKey> tag(String name) { - return TagKey.create(Registries.ENTITY_TYPE, new ResourceLocation("c", name)); + return TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath("c", name)); } } public static class Items { - private static void init() { - } + // `neoforge` tags for functional behavior provided by NeoForge + /** + * Controls what items can be consumed for enchanting such as Enchanting Tables. + * This tag defaults to {@link net.minecraft.world.item.Items#LAPIS_LAZULI} when not present in any datapacks, including forge client on vanilla server + */ + public static final TagKey ENCHANTING_FUELS = neoforgeTag("enchanting_fuels"); + // `c` tags for common conventions public static final TagKey BARRELS = tag("barrels"); - public static final TagKey BARRELS_WOODEN = tag("wooden_barrels"); + public static final TagKey BARRELS_WOODEN = tag("barrels/wooden"); public static final TagKey BONES = tag("bones"); public static final TagKey BOOKSHELVES = tag("bookshelves"); + public static final TagKey BRICKS = tag("bricks"); + public static final TagKey BRICKS_NORMAL = tag("bricks/normal"); + public static final TagKey BRICKS_NETHER = tag("bricks/nether"); + public static final TagKey BUCKETS = tag("buckets"); + public static final TagKey BUCKETS_EMPTY = tag("buckets/empty"); + /** + * Does not include entity water buckets. + * If checking for the fluid this bucket holds in code, please use {@link net.neoforged.neoforge.fluids.capability.wrappers.FluidBucketWrapper#getFluid} instead. + */ + public static final TagKey BUCKETS_WATER = tag("buckets/water"); + /** + * If checking for the fluid this bucket holds in code, please use {@link net.neoforged.neoforge.fluids.capability.wrappers.FluidBucketWrapper#getFluid} instead. + */ + public static final TagKey BUCKETS_LAVA = tag("buckets/lava"); + public static final TagKey BUCKETS_MILK = tag("buckets/milk"); + public static final TagKey BUCKETS_POWDER_SNOW = tag("buckets/powder_snow"); + public static final TagKey BUCKETS_ENTITY_WATER = tag("buckets/entity_water"); + /** + * For blocks that are similar to amethyst where their budding block produces buds and cluster blocks + */ + public static final TagKey BUDDING_BLOCKS = tag("budding_blocks"); + /** + * For blocks that are similar to amethyst where they have buddings forming from budding blocks + */ + public static final TagKey BUDS = tag("buds"); + public static final TagKey CHAINS = tag("chains"); public static final TagKey CHESTS = tag("chests"); - public static final TagKey CHESTS_ENDER = tag("ender_chests"); - public static final TagKey CHESTS_TRAPPED = tag("trapped_chests"); - public static final TagKey CHESTS_WOODEN = tag("wooden_chests"); - public static final TagKey COBBLESTONE = tag("cobblestone"); - public static final TagKey COBBLESTONE_NORMAL = tag("normal_cobblestone"); - public static final TagKey COBBLESTONE_INFESTED = tag("infested_cobblestone"); - public static final TagKey COBBLESTONE_MOSSY = tag("mossy_cobblestone"); - public static final TagKey COBBLESTONE_DEEPSLATE = tag("deepslate_cobblestone"); + public static final TagKey CHESTS_ENDER = tag("chests/ender"); + public static final TagKey CHESTS_TRAPPED = tag("chests/trapped"); + public static final TagKey CHESTS_WOODEN = tag("chests/wooden"); + public static final TagKey COBBLESTONES = tag("cobblestones"); + public static final TagKey COBBLESTONES_NORMAL = tag("cobblestones/normal"); + public static final TagKey COBBLESTONES_INFESTED = tag("cobblestones/infested"); + public static final TagKey COBBLESTONES_MOSSY = tag("cobblestones/mossy"); + public static final TagKey COBBLESTONES_DEEPSLATE = tag("cobblestones/deepslate"); + public static final TagKey CONCRETES = tag("concretes"); + /** + * Block tag equivalent is {@link BlockTags#CONCRETE_POWDER} + */ + public static final TagKey CONCRETE_POWDERS = tag("concrete_powders"); + /** + * For blocks that are similar to amethyst where they have clusters forming from budding blocks + */ + public static final TagKey CLUSTERS = tag("clusters"); public static final TagKey CROPS = tag("crops"); public static final TagKey CROPS_BEETROOT = tag("crops/beetroot"); public static final TagKey CROPS_CARROT = tag("crops/carrot"); @@ -218,10 +312,37 @@ private static void init() { public static final TagKey CROPS_POTATO = tag("crops/potato"); public static final TagKey CROPS_WHEAT = tag("crops/wheat"); public static final TagKey DUSTS = tag("dusts"); - public static final TagKey DUSTS_PRISMARINE = tag("dusts/prismarine"); public static final TagKey DUSTS_REDSTONE = tag("dusts/redstone"); public static final TagKey DUSTS_GLOWSTONE = tag("dusts/glowstone"); + /** + * Tag that holds all blocks and items that can be dyed a specific color. + * (Does not include color blending items like leather armor + * Use {@link net.minecraft.tags.ItemTags#DYEABLE} tag instead for color blending items) + *

+ * Note: Use custom ingredients in recipes to do tag intersections and/or tag exclusions + * to make more powerful recipes utilizing multiple tags such as dyed tags for an ingredient. + * See {@link net.neoforged.neoforge.common.crafting.DifferenceIngredient} and {@link net.neoforged.neoforge.common.crafting.CompoundIngredient} + * for various custom ingredients available that can also be used in data generation. + */ + public static final TagKey DYED = tag("dyed"); + public static final TagKey DYED_BLACK = tag("dyed/black"); + public static final TagKey DYED_BLUE = tag("dyed/blue"); + public static final TagKey DYED_BROWN = tag("dyed/brown"); + public static final TagKey DYED_CYAN = tag("dyed/cyan"); + public static final TagKey DYED_GRAY = tag("dyed/gray"); + public static final TagKey DYED_GREEN = tag("dyed/green"); + public static final TagKey DYED_LIGHT_BLUE = tag("dyed/light_blue"); + public static final TagKey DYED_LIGHT_GRAY = tag("dyed/light_gray"); + public static final TagKey DYED_LIME = tag("dyed/lime"); + public static final TagKey DYED_MAGENTA = tag("dyed/magenta"); + public static final TagKey DYED_ORANGE = tag("dyed/orange"); + public static final TagKey DYED_PINK = tag("dyed/pink"); + public static final TagKey DYED_PURPLE = tag("dyed/purple"); + public static final TagKey DYED_RED = tag("dyed/red"); + public static final TagKey DYED_WHITE = tag("dyed/white"); + public static final TagKey DYED_YELLOW = tag("dyed/yellow"); + public static final TagKey DYES = tag("dyes"); public static final TagKey DYES_BLACK = DyeColor.BLACK.getTag(); public static final TagKey DYES_RED = DyeColor.RED.getTag(); @@ -241,87 +362,96 @@ private static void init() { public static final TagKey DYES_WHITE = DyeColor.WHITE.getTag(); public static final TagKey EGGS = tag("eggs"); - /** - * This tag defaults to {@link net.minecraft.world.item.Items#LAPIS_LAZULI} when not present in any datapacks, including forge client on vanilla server - */ - public static final TagKey ENCHANTING_FUELS = tag("enchanting_fuels"); public static final TagKey END_STONES = tag("end_stones"); public static final TagKey ENDER_PEARLS = tag("ender_pearls"); public static final TagKey FEATHERS = tag("feathers"); public static final TagKey FENCE_GATES = tag("fence_gates"); - public static final TagKey FENCE_GATES_WOODEN = tag("wooden_fence_gates"); + public static final TagKey FENCE_GATES_WOODEN = tag("fence_gates/wooden"); public static final TagKey FENCES = tag("fences"); - public static final TagKey FENCES_NETHER_BRICK = tag("nether_brick_fences"); - public static final TagKey FENCES_WOODEN = tag("wooden_fences"); + public static final TagKey FENCES_NETHER_BRICK = tag("fences/nether_brick"); + public static final TagKey FENCES_WOODEN = tag("fences/wooden"); + public static final TagKey FOODS = tag("foods"); + /** + * Apples and other foods that are considered fruits in the culinary field belong in this tag. + * Cherries would go here as they are considered a "stone fruit" within culinary fields. + */ + public static final TagKey FOODS_FRUITS = tag("foods/fruits"); + /** + * Tomatoes and other foods that are considered vegetables in the culinary field belong in this tag. + */ + public static final TagKey FOODS_VEGETABLES = tag("foods/vegetables"); + /** + * Strawberries, raspberries, and other berry foods belong in this tag. + * Cherries would NOT go here as they are considered a "stone fruit" within culinary fields. + */ + public static final TagKey FOODS_BERRIES = tag("foods/berries"); + public static final TagKey FOODS_BREADS = tag("foods/breads"); + public static final TagKey FOODS_COOKIES = tag("foods/cookies"); + public static final TagKey FOODS_RAW_MEATS = tag("foods/raw_meats"); + public static final TagKey FOODS_COOKED_MEATS = tag("foods/cooked_meats"); + public static final TagKey FOODS_RAW_FISHES = tag("foods/raw_fishes"); + public static final TagKey FOODS_COOKED_FISHES = tag("foods/cooked_fishes"); + /** + * Soups, stews, and other liquid food in bowls belongs in this tag. + */ + public static final TagKey FOODS_SOUPS = tag("foods/soups"); + /** + * Sweets and candies like lollipops or chocolate belong in this tag. + */ + public static final TagKey FOODS_CANDIES = tag("foods/candies"); + /** + * Foods like cake that can be eaten when placed in the world belong in this tag. + */ + public static final TagKey FOODS_EDIBLE_WHEN_PLACED = tag("foods/edible_when_placed"); + /** + * For foods that inflict food poisoning-like effects. + * Examples are Rotten Flesh's Hunger or Pufferfish's Nausea, or Poisonous Potato's Poison. + */ + public static final TagKey FOODS_FOOD_POISONING = tag("foods/food_poisoning"); public static final TagKey GEMS = tag("gems"); - public static final TagKey GEMS_DIAMOND = ConventionalItemTags.DIAMONDS; - public static final TagKey GEMS_EMERALD = ConventionalItemTags.EMERALDS; - public static final TagKey GEMS_AMETHYST = tag("amethyst"); - public static final TagKey GEMS_LAPIS = ConventionalItemTags.LAPIS; - public static final TagKey GEMS_PRISMARINE = tag("prismarine"); - public static final TagKey GEMS_QUARTZ = ConventionalItemTags.QUARTZ; - - public static final TagKey GLASS = ConventionalItemTags.GLASS_BLOCKS; - public static final TagKey GLASS_BLACK = tag("black_glass"); - public static final TagKey GLASS_BLUE = tag("blue_glass"); - public static final TagKey GLASS_BROWN = tag("brown_glass"); - public static final TagKey GLASS_COLORLESS = tag("colorless_glass"); - public static final TagKey GLASS_CYAN = tag("cyan_glass"); - public static final TagKey GLASS_GRAY = tag("gray_glass"); - public static final TagKey GLASS_GREEN = tag("green_glass"); - public static final TagKey GLASS_LIGHT_BLUE = tag("light_blue_glass"); - public static final TagKey GLASS_LIGHT_GRAY = tag("light_gray_glass"); - public static final TagKey GLASS_LIME = tag("lime_glass"); - public static final TagKey GLASS_MAGENTA = tag("magenta_glass"); - public static final TagKey GLASS_ORANGE = tag("orange_glass"); - public static final TagKey GLASS_PINK = tag("pink_glass"); - public static final TagKey GLASS_PURPLE = tag("purple_glass"); - public static final TagKey GLASS_RED = tag("red_glass"); - /** - * Glass which is made from sand and only minor additional ingredients like dyes - */ - public static final TagKey GLASS_SILICA = tag("silica_glass"); - public static final TagKey GLASS_TINTED = tag("tinted_glass"); - public static final TagKey GLASS_WHITE = tag("white_glass"); - public static final TagKey GLASS_YELLOW = tag("yellow_glass"); - - public static final TagKey GLASS_PANES = ConventionalItemTags.GLASS_PANES; - public static final TagKey GLASS_PANES_BLACK = tag("black_glass_panes"); - public static final TagKey GLASS_PANES_BLUE = tag("blue_glass_panes"); - public static final TagKey GLASS_PANES_BROWN = tag("brown_glass_panes"); - public static final TagKey GLASS_PANES_COLORLESS = tag("colorless_glass_panes"); - public static final TagKey GLASS_PANES_CYAN = tag("cyan_glass_panes"); - public static final TagKey GLASS_PANES_GRAY = tag("gray_glass_panes"); - public static final TagKey GLASS_PANES_GREEN = tag("green_glass_panes"); - public static final TagKey GLASS_PANES_LIGHT_BLUE = tag("light_blue_glass_panes"); - public static final TagKey GLASS_PANES_LIGHT_GRAY = tag("light_gray_glass_panes"); - public static final TagKey GLASS_PANES_LIME = tag("lime_glass_panes"); - public static final TagKey GLASS_PANES_MAGENTA = tag("magenta_glass_panes"); - public static final TagKey GLASS_PANES_ORANGE = tag("orange_glass_panes"); - public static final TagKey GLASS_PANES_PINK = tag("pink_glass_panes"); - public static final TagKey GLASS_PANES_PURPLE = tag("purple_glass_panes"); - public static final TagKey GLASS_PANES_RED = tag("red_glass_panes"); - public static final TagKey GLASS_PANES_WHITE = tag("white_glass_panes"); - public static final TagKey GLASS_PANES_YELLOW = tag("yellow_glass_panes"); - - public static final TagKey GRAVEL = tag("gravel"); - public static final TagKey GUNPOWDER = tag("gunpowder"); - public static final TagKey HEADS = tag("heads"); + public static final TagKey GEMS_DIAMOND = tag("gems/diamond"); + public static final TagKey GEMS_EMERALD = tag("gems/emerald"); + public static final TagKey GEMS_AMETHYST = tag("gems/amethyst"); + public static final TagKey GEMS_LAPIS = tag("gems/lapis"); + public static final TagKey GEMS_PRISMARINE = tag("gems/prismarine"); + public static final TagKey GEMS_QUARTZ = tag("gems/quartz"); + + public static final TagKey GLASS_BLOCKS = tag("glass_blocks"); + public static final TagKey GLASS_BLOCKS_COLORLESS = tag("glass_blocks/colorless"); + /** + * Glass which is made from cheap resources like sand and only minor additional ingredients like dyes + */ + public static final TagKey GLASS_BLOCKS_CHEAP = tag("glass_blocks/cheap"); + public static final TagKey GLASS_BLOCKS_TINTED = tag("glass_blocks/tinted"); + + public static final TagKey GLASS_PANES = tag("glass_panes"); + public static final TagKey GLASS_PANES_COLORLESS = tag("glass_panes/colorless"); + public static final TagKey GLAZED_TERRACOTTAS = tag("glazed_terracottas"); + + public static final TagKey GRAVELS = tag("gravels"); + public static final TagKey GUNPOWDERS = tag("gunpowders"); + /** + * Tag that holds all items that recipe viewers should not show to users. + */ + public static final TagKey HIDDEN_FROM_RECIPE_VIEWERS = tag("hidden_from_recipe_viewers"); public static final TagKey INGOTS = tag("ingots"); - public static final TagKey INGOTS_BRICK = tag("brick_ingots"); - public static final TagKey INGOTS_COPPER = tag("copper_ingots"); - public static final TagKey INGOTS_GOLD = tag("gold_ingots"); - public static final TagKey INGOTS_IRON = ConventionalItemTags.IRON_INGOTS; - public static final TagKey INGOTS_NETHERITE = ConventionalItemTags.NETHERITE_INGOTS; - public static final TagKey INGOTS_NETHER_BRICK = tag("nether_brick_ingots"); - public static final TagKey LEATHER = tag("leather"); + public static final TagKey INGOTS_COPPER = tag("ingots/copper"); + public static final TagKey INGOTS_GOLD = tag("ingots/gold"); + public static final TagKey INGOTS_IRON = tag("ingots/iron"); + public static final TagKey INGOTS_NETHERITE = tag("ingots/netherite"); + public static final TagKey LEATHERS = tag("leathers"); public static final TagKey MUSHROOMS = tag("mushrooms"); + /** + * For music disc-like materials to be used in recipes. + * A pancake with a JUKEBOX_PLAYABLE component attached to play in Jukeboxes as an Easter Egg is not a music disc and would not go in this tag. + */ + public static final TagKey MUSIC_DISCS = tag("music_discs"); public static final TagKey NETHER_STARS = tag("nether_stars"); - public static final TagKey NETHERRACK = tag("netherrack"); + public static final TagKey NETHERRACKS = tag("netherracks"); public static final TagKey NUGGETS = tag("nuggets"); - public static final TagKey NUGGETS_GOLD = tag("gold_nuggets"); - public static final TagKey NUGGETS_IRON = tag("iron_nuggets"); - public static final TagKey OBSIDIAN = tag("obsidian"); + public static final TagKey NUGGETS_GOLD = tag("nuggets/gold"); + public static final TagKey NUGGETS_IRON = tag("nuggets/iron"); + public static final TagKey OBSIDIANS = tag("obsidians"); /** * Blocks which are often replaced by deepslate ores, i.e. the ores in the tag {@link #ORES_IN_GROUND_DEEPSLATE}, during world generation */ @@ -346,17 +476,17 @@ private static void init() { * Ores which on average result in less than one resource worth of materials */ public static final TagKey ORE_RATES_SPARSE = tag("ore_rates/sparse"); - public static final TagKey ORES = ConventionalItemTags.ORES; - public static final TagKey ORES_COAL = tag("coal_ores"); - public static final TagKey ORES_COPPER = tag("copper_ores"); - public static final TagKey ORES_DIAMOND = tag("diamond_ores"); - public static final TagKey ORES_EMERALD = tag("emerald_ores"); - public static final TagKey ORES_GOLD = tag("gold_ores"); - public static final TagKey ORES_IRON = tag("iron_ores"); - public static final TagKey ORES_LAPIS = tag("lapis_ores"); - public static final TagKey ORES_NETHERITE_SCRAP = tag("netherite_scrap_ores"); - public static final TagKey ORES_QUARTZ = ConventionalItemTags.QUARTZ_ORES; - public static final TagKey ORES_REDSTONE = tag("redstone_ores"); + public static final TagKey ORES = tag("ores"); + public static final TagKey ORES_COAL = tag("ores/coal"); + public static final TagKey ORES_COPPER = tag("ores/copper"); + public static final TagKey ORES_DIAMOND = tag("ores/diamond"); + public static final TagKey ORES_EMERALD = tag("ores/emerald"); + public static final TagKey ORES_GOLD = tag("ores/gold"); + public static final TagKey ORES_IRON = tag("ores/iron"); + public static final TagKey ORES_LAPIS = tag("ores/lapis"); + public static final TagKey ORES_NETHERITE_SCRAP = tag("ores/netherite_scrap"); + public static final TagKey ORES_QUARTZ = tag("ores/quartz"); + public static final TagKey ORES_REDSTONE = tag("ores/redstone"); /** * Ores in deepslate (or in equivalent blocks in the tag {@link #ORE_BEARING_GROUND_DEEPSLATE}) which could logically use deepslate as recipe input or output */ @@ -369,123 +499,180 @@ private static void init() { * Ores in stone (or in equivalent blocks in the tag {@link #ORE_BEARING_GROUND_STONE}) which could logically use stone as recipe input or output */ public static final TagKey ORES_IN_GROUND_STONE = tag("ores_in_ground/stone"); + public static final TagKey PLAYER_WORKSTATIONS_CRAFTING_TABLES = tag("player_workstations/crafting_tables"); + public static final TagKey PLAYER_WORKSTATIONS_FURNACES = tag("player_workstations/furnaces"); public static final TagKey RAW_MATERIALS = tag("raw_materials"); - public static final TagKey RAW_MATERIALS_COPPER = tag("copper_raw_materials"); - public static final TagKey RAW_MATERIALS_GOLD = tag("gold_raw_materials"); - public static final TagKey RAW_MATERIALS_IRON = tag("iron_raw_materials"); - public static final TagKey RODS = tag("rods"); - public static final TagKey RODS_BLAZE = tag("blaze_rods"); - public static final TagKey RODS_WOODEN = tag("wooden_rods"); - - public static final TagKey SAND = tag("sand"); - public static final TagKey SAND_COLORLESS = tag("colorless_sand"); - public static final TagKey SAND_RED = tag("red_sand"); - - public static final TagKey SANDSTONE = tag("sandstone"); - public static final TagKey SEEDS = tag("seeds"); - public static final TagKey SEEDS_BEETROOT = tag("beetroot_seeds"); - public static final TagKey SEEDS_MELON = tag("melon_seeds"); - public static final TagKey SEEDS_PUMPKIN = tag("pumpkin_seeds"); - public static final TagKey SEEDS_WHEAT = tag("wheat_seeds"); - public static final TagKey SHEARS = ConventionalItemTags.SHEARS; - public static final TagKey SLIMEBALLS = tag("slimeballs"); - public static final TagKey STAINED_GLASS = tag("stained_glass"); - public static final TagKey STAINED_GLASS_PANES = tag("stained_glass_panes"); - public static final TagKey STONE = tag("stone"); - public static final TagKey STORAGE_BLOCKS = tag("storage_blocks"); - public static final TagKey STORAGE_BLOCKS_AMETHYST = tag("amethyst_blocks"); - public static final TagKey STORAGE_BLOCKS_COAL = tag("coal_blocks"); - public static final TagKey STORAGE_BLOCKS_COPPER = tag("copper_blocks"); - public static final TagKey STORAGE_BLOCKS_DIAMOND = tag("diamond_blocks"); - public static final TagKey STORAGE_BLOCKS_EMERALD = tag("emerald_blocks"); - public static final TagKey STORAGE_BLOCKS_GOLD = tag("gold_blocks"); - public static final TagKey STORAGE_BLOCKS_IRON = tag("iron_blocks"); - public static final TagKey STORAGE_BLOCKS_LAPIS = tag("lapis_blocks"); - public static final TagKey STORAGE_BLOCKS_NETHERITE = tag("netherite_blocks"); - public static final TagKey STORAGE_BLOCKS_QUARTZ = tag("quartz_blocks"); - public static final TagKey STORAGE_BLOCKS_RAW_COPPER = ConventionalItemTags.RAW_COPPER_BLOCKS; - public static final TagKey STORAGE_BLOCKS_RAW_GOLD = ConventionalItemTags.RAW_GOLD_BLOCKS; - public static final TagKey STORAGE_BLOCKS_RAW_IRON = ConventionalItemTags.RAW_IRON_BLOCKS; - public static final TagKey STORAGE_BLOCKS_REDSTONE = tag("redstone_blocks"); - public static final TagKey STRING = tag("string"); - /** - * A tag containing all existing tools. - */ - public static final TagKey TOOLS = tag("tools"); + public static final TagKey RAW_MATERIALS_COPPER = tag("raw_materials/copper"); + public static final TagKey RAW_MATERIALS_GOLD = tag("raw_materials/gold"); + public static final TagKey RAW_MATERIALS_IRON = tag("raw_materials/iron"); /** - * A tag containing all existing swords. + * For rod-like materials to be used in recipes. */ - public static final TagKey TOOLS_SWORDS = ConventionalItemTags.SWORDS; + public static final TagKey RODS = tag("rods"); + public static final TagKey RODS_BLAZE = tag("rods/blaze"); + public static final TagKey RODS_BREEZE = tag("rods/breeze"); /** - * A tag containing all existing axes. + * For stick-like materials to be used in recipes. + * One example is a mod adds stick variants such as Spruce Sticks but would like stick recipes to be able to use it. */ - public static final TagKey TOOLS_AXES = ConventionalItemTags.AXES; + public static final TagKey RODS_WOODEN = tag("rods/wooden"); + public static final TagKey ROPES = tag("ropes"); + + public static final TagKey SANDS = tag("sands"); + public static final TagKey SANDS_COLORLESS = tag("sands/colorless"); + public static final TagKey SANDS_RED = tag("sands/red"); + + public static final TagKey SANDSTONE_BLOCKS = tag("sandstone/blocks"); + public static final TagKey SANDSTONE_SLABS = tag("sandstone/slabs"); + public static final TagKey SANDSTONE_STAIRS = tag("sandstone/stairs"); + public static final TagKey SANDSTONE_RED_BLOCKS = tag("sandstone/red_blocks"); + public static final TagKey SANDSTONE_RED_SLABS = tag("sandstone/red_slabs"); + public static final TagKey SANDSTONE_RED_STAIRS = tag("sandstone/red_stairs"); + public static final TagKey SANDSTONE_UNCOLORED_BLOCKS = tag("sandstone/uncolored_blocks"); + public static final TagKey SANDSTONE_UNCOLORED_SLABS = tag("sandstone/uncolored_slabs"); + public static final TagKey SANDSTONE_UNCOLORED_STAIRS = tag("sandstone/uncolored_stairs"); + + public static final TagKey SEEDS = tag("seeds"); + public static final TagKey SEEDS_BEETROOT = tag("seeds/beetroot"); + public static final TagKey SEEDS_MELON = tag("seeds/melon"); + public static final TagKey SEEDS_PUMPKIN = tag("seeds/pumpkin"); + public static final TagKey SEEDS_WHEAT = tag("seeds/wheat"); /** - * A tag containing all existing pickaxes. + * Block tag equivalent is {@link BlockTags#SHULKER_BOXES} */ - public static final TagKey TOOLS_PICKAXES = ConventionalItemTags.PICKAXES; + public static final TagKey SHULKER_BOXES = tag("shulker_boxes"); + public static final TagKey SLIMEBALLS = tag("slimeballs"); /** - * A tag containing all existing shovels. + * Natural stone-like blocks that can be used as a base ingredient in recipes that takes stone. */ - public static final TagKey TOOLS_SHOVELS = ConventionalItemTags.SHOVELS; + public static final TagKey STONES = tag("stones"); /** - * A tag containing all existing hoes. + * A storage block is generally a block that has a recipe to craft a bulk of 1 kind of resource to a block + * and has a mirror recipe to reverse the crafting with no loss in resources. + *

+ * Honey Block is special in that the reversing recipe is not a perfect mirror of the crafting recipe + * and so, it is considered a special case and not given a storage block tag. */ - public static final TagKey TOOLS_HOES = ConventionalItemTags.HOES; + public static final TagKey STORAGE_BLOCKS = tag("storage_blocks"); + public static final TagKey STORAGE_BLOCKS_BONE_MEAL = tag("storage_blocks/bone_meal"); + public static final TagKey STORAGE_BLOCKS_COAL = tag("storage_blocks/coal"); + public static final TagKey STORAGE_BLOCKS_COPPER = tag("storage_blocks/copper"); + public static final TagKey STORAGE_BLOCKS_DIAMOND = tag("storage_blocks/diamond"); + public static final TagKey STORAGE_BLOCKS_DRIED_KELP = tag("storage_blocks/dried_kelp"); + public static final TagKey STORAGE_BLOCKS_EMERALD = tag("storage_blocks/emerald"); + public static final TagKey STORAGE_BLOCKS_GOLD = tag("storage_blocks/gold"); + public static final TagKey STORAGE_BLOCKS_IRON = tag("storage_blocks/iron"); + public static final TagKey STORAGE_BLOCKS_LAPIS = tag("storage_blocks/lapis"); + public static final TagKey STORAGE_BLOCKS_NETHERITE = tag("storage_blocks/netherite"); + public static final TagKey STORAGE_BLOCKS_RAW_COPPER = tag("storage_blocks/raw_copper"); + public static final TagKey STORAGE_BLOCKS_RAW_GOLD = tag("storage_blocks/raw_gold"); + public static final TagKey STORAGE_BLOCKS_RAW_IRON = tag("storage_blocks/raw_iron"); + public static final TagKey STORAGE_BLOCKS_REDSTONE = tag("storage_blocks/redstone"); + public static final TagKey STORAGE_BLOCKS_SLIME = tag("storage_blocks/slime"); + public static final TagKey STORAGE_BLOCKS_WHEAT = tag("storage_blocks/wheat"); + public static final TagKey STRINGS = tag("strings"); + public static final TagKey VILLAGER_JOB_SITES = tag("villager_job_sites"); + + // Tools and Armors /** - * A tag containing all existing shields. + * A tag containing all existing tools. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey TOOLS_SHIELDS = tag("shields"); + public static final TagKey TOOLS = tag("tools"); /** - * A tag containing all existing bows. + * A tag containing all existing shields. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey TOOLS_BOWS = ConventionalItemTags.BOWS; + public static final TagKey TOOLS_SHIELD = tag("tools/shield"); /** - * A tag containing all existing crossbows. + * A tag containing all existing bows. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey TOOLS_CROSSBOWS = tag("crossbows"); + public static final TagKey TOOLS_BOW = tag("tools/bow"); /** - * A tag containing all existing fishing rods. + * A tag containing all existing crossbows. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see io.github.fabricators_of_create.porting_lib.tool.ToolAction + * @see io.github.fabricators_of_create.porting_lib.tool.ToolActions */ - public static final TagKey TOOLS_FISHING_RODS = tag("fishing_rods"); + public static final TagKey TOOLS_CROSSBOW = tag("tools/crossbow"); /** - * A tag containing all existing tridents. + * A tag containing all existing fishing rods. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see io.github.fabricators_of_create.porting_lib.tool.ToolAction + * @see io.github.fabricators_of_create.porting_lib.tool.ToolActions */ - public static final TagKey TOOLS_TRIDENTS = tag("tridents"); + public static final TagKey TOOLS_FISHING_ROD = tag("tools/fishing_rod"); /** - * A tag containing all existing armors. + * A tag containing all existing spears. Other tools such as throwing knives or boomerangs + * should not be put into this tag and should be put into their own tool tags. + * Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey ARMORS = tag("armors"); + public static final TagKey TOOLS_SPEAR = tag("tools/spear"); /** - * A tag containing all existing helmets. + * A tag containing all existing shears. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey ARMORS_HELMETS = tag("helmets"); + public static final TagKey TOOLS_SHEAR = tag("tools/shear"); /** - * A tag containing all chestplates. + * A tag containing all existing brushes. Do not use this tag for determining a tool's behavior. + * Please use {@link io.github.fabricators_of_create.porting_lib.tool.ToolActions} instead for what action a tool can do. + * + * @see ToolAction + * @see ToolActions */ - public static final TagKey ARMORS_CHESTPLATES = tag("chestplates"); + public static final TagKey TOOLS_BRUSH = tag("tools/brush"); /** - * A tag containing all existing leggings. + * Collects the 4 vanilla armor tags into one parent collection for ease. */ - public static final TagKey ARMORS_LEGGINGS = tag("leggings"); + public static final TagKey ARMORS = tag("armors"); /** - * A tag containing all existing boots. + * Collects the many enchantable tags into one parent collection for ease. */ - public static final TagKey ARMORS_BOOTS = tag("boots"); + public static final TagKey ENCHANTABLES = tag("enchantables"); - private static TagKey tag(String name, @Nullable Set> defaults) { - return TagKey.create(Registries.ITEM, new ResourceLocation("c", name)); + private static TagKey tag(String name) { + return TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("c", name)); } - private static TagKey tag(String name) { - return tag(name, null); + private static TagKey neoforgeTag(String name) { + return TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("neoforge", name)); } } + /** + * Note, fluid tags should not be plural to match the vanilla standard. + * This is the only tag category exempted from many-different-types plural rule. + */ public static class Fluids { - private static void init() { - } - + /** + * Holds all fluids related to water. + * This tag is done to help out multi-loader mods/datapacks where the vanilla water tag has attached behaviors outside Neo. + */ + public static final TagKey WATER = tag("water"); + /** + * Holds all fluids related to lava. + * This tag is done to help out multi-loader mods/datapacks where the vanilla lava tag has attached behaviors outside Neo. + */ + public static final TagKey LAVA = tag("lava"); /** * Holds all fluids related to milk. */ @@ -494,15 +681,97 @@ private static void init() { * Holds all fluids that are gaseous at room temperature. */ public static final TagKey GASEOUS = tag("gaseous"); + /** + * Holds all fluids related to honey.

+ * (Standard unit for honey bottle is 250mb per bottle) + */ + public static final TagKey HONEY = tag("honey"); + /** + * Holds all fluids related to potions. The effects of the potion fluid should be read from NBT. + * The effects and color of the potion fluid should be read from {@link net.minecraft.core.component.DataComponents#POTION_CONTENTS} + * component that people should be attaching to the fluidstack of this fluid.

+ * (Standard unit for potions is 250mb per bottle) + */ + public static final TagKey POTION = tag("potion"); + /** + * Holds all fluids related to Suspicious Stew. + * The effects of the suspicious stew fluid should be read from {@link net.minecraft.core.component.DataComponents#SUSPICIOUS_STEW_EFFECTS} + * component that people should be attaching to the fluidstack of this fluid.

+ * (Standard unit for suspicious stew is 250mb per bowl) + */ + public static final TagKey SUSPICIOUS_STEW = tag("suspicious_stew"); + /** + * Holds all fluids related to Mushroom Stew.

+ * (Standard unit for mushroom stew is 250mb per bowl) + */ + public static final TagKey MUSHROOM_STEW = tag("mushroom_stew"); + /** + * Holds all fluids related to Rabbit Stew.

+ * (Standard unit for rabbit stew is 250mb per bowl) + */ + public static final TagKey RABBIT_STEW = tag("rabbit_stew"); + /** + * Holds all fluids related to Beetroot Soup.

+ * (Standard unit for beetroot soup is 250mb per bowl) + */ + public static final TagKey BEETROOT_SOUP = tag("beetroot_soup"); + /** + * Tag that holds all fluids that recipe viewers should not show to users. + */ + public static final TagKey HIDDEN_FROM_RECIPE_VIEWERS = tag("hidden_from_recipe_viewers"); private static TagKey tag(String name) { - return TagKey.create(Registries.FLUID, new ResourceLocation("c", name)); + return TagKey.create(Registries.FLUID, ResourceLocation.fromNamespaceAndPath("c", name)); } } - public static class Biomes { - private static void init() { + public static class Enchantments { + /** + * A tag containing enchantments that increase the amount or + * quality of drops from blocks, such as {@link net.minecraft.world.item.enchantment.Enchantments#FORTUNE}. + */ + public static final TagKey INCREASE_BLOCK_DROPS = tag("increase_block_drops"); + /** + * A tag containing enchantments that increase the amount or + * quality of drops from entities, such as {@link net.minecraft.world.item.enchantment.Enchantments#LOOTING}. + */ + public static final TagKey INCREASE_ENTITY_DROPS = tag("increase_entity_drops"); + /** + * For enchantments that increase the damage dealt by an item. + */ + public static final TagKey WEAPON_DAMAGE_ENHANCEMENTS = tag("weapon_damage_enhancements"); + /** + * For enchantments that increase movement speed for entity wearing armor enchanted with it. + */ + public static final TagKey ENTITY_SPEED_ENHANCEMENTS = tag("entity_speed_enhancements"); + /** + * For enchantments that applies movement-based benefits unrelated to speed for the entity wearing armor enchanted with it. + * Example: Reducing falling speeds ({@link net.minecraft.world.item.enchantment.Enchantments#FEATHER_FALLING}) or allowing walking on water ({@link net.minecraft.world.item.enchantment.Enchantments#FROST_WALKER}) + */ + public static final TagKey ENTITY_AUXILIARY_MOVEMENT_ENHANCEMENTS = tag("entity_auxiliary_movement_enhancements"); + /** + * For enchantments that decrease damage taken or otherwise benefit, in regard to damage, the entity wearing armor enchanted with it. + */ + public static final TagKey ENTITY_DEFENSE_ENHANCEMENTS = tag("entity_defense_enhancements"); + + private static TagKey tag(String name) { + return TagKey.create(Registries.ENCHANTMENT, ResourceLocation.fromNamespaceAndPath("c", name)); } + } + + public static class Biomes { + /** + * For biomes that should not spawn monsters over time the normal way. + * In other words, their Spawners and Spawn Cost entries have the monster category empty. + * Example: Mushroom Biomes not having Zombies, Creepers, Skeleton, nor any other normal monsters. + */ + public static final TagKey NO_DEFAULT_MONSTERS = tag("no_default_monsters"); + /** + * Biomes that should not be locatable/selectable by modded biome-locating items or abilities. + */ + public static final TagKey HIDDEN_FROM_LOCATOR_SELECTION = tag("hidden_from_locator_selection"); + + public static final TagKey IS_VOID = tag("is_void"); public static final TagKey IS_HOT = tag("is_hot"); public static final TagKey IS_HOT_OVERWORLD = tag("is_hot/overworld"); @@ -514,14 +783,14 @@ private static void init() { public static final TagKey IS_COLD_NETHER = tag("is_cold/nether"); public static final TagKey IS_COLD_END = tag("is_cold/end"); - public static final TagKey IS_SPARSE = tag("is_sparse"); - public static final TagKey IS_SPARSE_OVERWORLD = tag("is_sparse/overworld"); - public static final TagKey IS_SPARSE_NETHER = tag("is_sparse/nether"); - public static final TagKey IS_SPARSE_END = tag("is_sparse/end"); - public static final TagKey IS_DENSE = tag("is_dense"); - public static final TagKey IS_DENSE_OVERWORLD = tag("is_dense/overworld"); - public static final TagKey IS_DENSE_NETHER = tag("is_dense/nether"); - public static final TagKey IS_DENSE_END = tag("is_dense/end"); + public static final TagKey IS_SPARSE_VEGETATION = tag("is_sparse_vegetation"); + public static final TagKey IS_SPARSE_VEGETATION_OVERWORLD = tag("is_sparse_vegetation/overworld"); + public static final TagKey IS_SPARSE_VEGETATION_NETHER = tag("is_sparse_vegetation/nether"); + public static final TagKey IS_SPARSE_VEGETATION_END = tag("is_sparse_vegetation/end"); + public static final TagKey IS_DENSE_VEGETATION = tag("is_dense_vegetation"); + public static final TagKey IS_DENSE_VEGETATION_OVERWORLD = tag("is_dense_vegetation/overworld"); + public static final TagKey IS_DENSE_VEGETATION_NETHER = tag("is_dense_vegetation/nether"); + public static final TagKey IS_DENSE_VEGETATION_END = tag("is_dense_vegetation/end"); public static final TagKey IS_WET = tag("is_wet"); public static final TagKey IS_WET_OVERWORLD = tag("is_wet/overworld"); @@ -532,34 +801,270 @@ private static void init() { public static final TagKey IS_DRY_NETHER = tag("is_dry/nether"); public static final TagKey IS_DRY_END = tag("is_dry/end"); - public static final TagKey IS_CONIFEROUS = tag("is_coniferous"); + /** + * Biomes that spawn in the Overworld. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_OVERWORLD} + *

+ * NOTE: If you do not add to the vanilla Overworld tag, be sure to add to + * {@link net.minecraft.tags.BiomeTags#HAS_STRONGHOLD} so some Strongholds do not go missing.) + */ + public static final TagKey IS_OVERWORLD = tag("is_overworld"); - public static final TagKey IS_SPOOKY = tag("is_spooky"); - public static final TagKey IS_DEAD = tag("is_dead"); - public static final TagKey IS_LUSH = tag("is_lush"); + public static final TagKey IS_CONIFEROUS_TREE = tag("is_tree/coniferous"); + public static final TagKey IS_SAVANNA_TREE = tag("is_tree/savanna"); + public static final TagKey IS_JUNGLE_TREE = tag("is_tree/jungle"); + public static final TagKey IS_DECIDUOUS_TREE = tag("is_tree/deciduous"); + + /** + * Biomes that spawn as part of giant mountains. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_MOUNTAIN}) + */ + public static final TagKey IS_MOUNTAIN = tag("is_mountain"); + public static final TagKey IS_MOUNTAIN_PEAK = tag("is_mountain/peak"); + public static final TagKey IS_MOUNTAIN_SLOPE = tag("is_mountain/slope"); + + /** + * For temperate or warmer plains-like biomes. + * For snowy plains-like biomes, see {@link #IS_SNOWY_PLAINS}. + */ + public static final TagKey IS_PLAINS = tag("is_plains"); + /** + * For snowy plains-like biomes. + * For warmer plains-like biomes, see {@link #IS_PLAINS}. + */ + public static final TagKey IS_SNOWY_PLAINS = tag("is_snowy_plains"); + /** + * Biomes densely populated with deciduous trees. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_FOREST}) + */ + public static final TagKey IS_FOREST = tag("is_forest"); + public static final TagKey IS_BIRCH_FOREST = tag("is_birch_forest"); + public static final TagKey IS_FLOWER_FOREST = tag("is_flower_forest"); + /** + * Biomes that spawn as a taiga. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_TAIGA}) + */ + public static final TagKey IS_TAIGA = tag("is_taiga"); + public static final TagKey IS_OLD_GROWTH = tag("is_old_growth"); + /** + * Biomes that spawn as a hills biome. (Previously was called Extreme Hills biome in past) + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_HILL}) + */ + public static final TagKey IS_HILL = tag("is_hill"); + public static final TagKey IS_WINDSWEPT = tag("is_windswept"); + /** + * Biomes that spawn as a jungle. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_JUNGLE}) + */ + public static final TagKey IS_JUNGLE = tag("is_jungle"); + /** + * Biomes that spawn as a savanna. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_SAVANNA}) + */ + public static final TagKey IS_SAVANNA = tag("is_savanna"); + public static final TagKey IS_SWAMP = tag("is_swamp"); + public static final TagKey IS_DESERT = tag("is_desert"); + /** + * Biomes that spawn as a badlands. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_BADLANDS}) + */ + public static final TagKey IS_BADLANDS = tag("is_badlands"); + /** + * Biomes that are dedicated to spawning on the shoreline of a body of water. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_BEACH}) + */ + public static final TagKey IS_BEACH = tag("is_beach"); + public static final TagKey IS_STONY_SHORES = tag("is_stony_shores"); public static final TagKey IS_MUSHROOM = tag("is_mushroom"); + + /** + * Biomes that spawn as a river. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_RIVER}) + */ + public static final TagKey IS_RIVER = tag("is_river"); + /** + * Biomes that spawn as part of the world's oceans. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_OCEAN}) + */ + public static final TagKey IS_OCEAN = tag("is_ocean"); + /** + * Biomes that spawn as part of the world's oceans that have low depth. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_DEEP_OCEAN}) + */ + public static final TagKey IS_DEEP_OCEAN = tag("is_deep_ocean"); + public static final TagKey IS_SHALLOW_OCEAN = tag("is_shallow_ocean"); + + public static final TagKey IS_UNDERGROUND = tag("is_underground"); + public static final TagKey IS_CAVE = tag("is_cave"); + + public static final TagKey IS_LUSH = tag("is_lush"); public static final TagKey IS_MAGICAL = tag("is_magical"); public static final TagKey IS_RARE = tag("is_rare"); public static final TagKey IS_PLATEAU = tag("is_plateau"); public static final TagKey IS_MODIFIED = tag("is_modified"); - - public static final TagKey IS_WATER = tag("is_water"); - public static final TagKey IS_DESERT = tag("is_desert"); - public static final TagKey IS_PLAINS = tag("is_plains"); - public static final TagKey IS_SWAMP = tag("is_swamp"); + public static final TagKey IS_SPOOKY = tag("is_spooky"); + /** + * Biomes that lack any natural life or vegetation. + * (Example, land destroyed and sterilized by nuclear weapons) + */ + public static final TagKey IS_WASTELAND = tag("is_wasteland"); + /** + * Biomes whose flora primarily consists of dead or decaying vegetation. + */ + public static final TagKey IS_DEAD = tag("is_dead"); + /** + * Biomes with a large amount of flowers. + */ + public static final TagKey IS_FLORAL = tag("is_floral"); + /** + * Biomes that are able to spawn sand-based blocks on the surface. + */ public static final TagKey IS_SANDY = tag("is_sandy"); + /** + * For biomes that contains lots of naturally spawned snow. + * For biomes where lot of ice is present, see {@link #IS_ICY}. + * Biome with lots of both snow and ice may be in both tags. + */ public static final TagKey IS_SNOWY = tag("is_snowy"); - public static final TagKey IS_WASTELAND = tag("is_wasteland"); - public static final TagKey IS_VOID = tag("is_void"); - public static final TagKey IS_UNDERGROUND = tag("is_underground"); + /** + * For land biomes where ice naturally spawns. + * For biomes where snow alone spawns, see {@link #IS_SNOWY}. + */ + public static final TagKey IS_ICY = tag("is_icy"); + /** + * Biomes consisting primarily of water. + */ + public static final TagKey IS_AQUATIC = tag("is_aquatic"); + /** + * For water biomes where ice naturally spawns. + * For biomes where snow alone spawns, see {@link #IS_SNOWY}. + */ + public static final TagKey IS_AQUATIC_ICY = tag("is_aquatic_icy"); - public static final TagKey IS_CAVE = tag("is_cave"); - public static final TagKey IS_PEAK = tag("is_peak"); - public static final TagKey IS_SLOPE = tag("is_slope"); - public static final TagKey IS_MOUNTAIN = tag("is_mountain"); + /** + * Biomes that spawn in the Nether. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_NETHER}) + */ + public static final TagKey IS_NETHER = tag("is_nether"); + public static final TagKey IS_NETHER_FOREST = tag("is_nether_forest"); + + /** + * Biomes that spawn in the End. + * (This is for people who want to tag their biomes without getting + * side effects from {@link net.minecraft.tags.BiomeTags#IS_END}) + */ + public static final TagKey IS_END = tag("is_end"); + /** + * Biomes that spawn as part of the large islands outside the center island in The End dimension. + */ + public static final TagKey IS_OUTER_END_ISLAND = tag("is_outer_end_island"); private static TagKey tag(String name) { - return TagKey.create(Registries.BIOME, new ResourceLocation("c", name)); + return TagKey.create(Registries.BIOME, ResourceLocation.fromNamespaceAndPath("c", name)); + } + } + + public static class Structures { + /** + * Structures that should not show up on minimaps or world map views from mods/sites. + * No effect on vanilla map items. + */ + public static final TagKey HIDDEN_FROM_DISPLAYERS = tag("hidden_from_displayers"); + + /** + * Structures that should not be locatable/selectable by modded structure-locating items or abilities. + * No effect on vanilla map items. + */ + public static final TagKey HIDDEN_FROM_LOCATOR_SELECTION = tag("hidden_from_locator_selection"); + + private static TagKey tag(String name) { + return TagKey.create(Registries.STRUCTURE, ResourceLocation.fromNamespaceAndPath("c", name)); + } + } + + public static class DamageTypes { + /** + * Damage types representing magic damage. + */ + public static final TagKey IS_MAGIC = neoforgeTag("is_magic"); + + /** + * Damage types representing poison damage. + */ + public static final TagKey IS_POISON = neoforgeTag("is_poison"); + + /** + * Damage types representing damage that can be attributed to withering or the wither. + */ + public static final TagKey IS_WITHER = neoforgeTag("is_wither"); + + /** + * Damage types representing environmental damage, such as fire, lava, magma, cactus, lightning, etc. + */ + public static final TagKey IS_ENVIRONMENT = neoforgeTag("is_environment"); + + /** + * Damage types representing physical damage.
+ * These are types that do not fit other #is_x tags (except #is_fall) + * and would meet the general definition of physical damage. + */ + public static final TagKey IS_PHYSICAL = neoforgeTag("is_physical"); + + /** + * Damage types representing damage from commands or other non-gameplay sources.
+ * Damage from these types should not be reduced, and bypasses invulnerability. + */ + public static final TagKey IS_TECHNICAL = neoforgeTag("is_technical"); + + /** + * Damage types that will not cause the red flashing effect.
+ * This tag is empty by default. + * + * @see GameRenderer#bobHurt + */ + public static final TagKey NO_FLINCH = neoforgeTag("no_flinch"); + + private static TagKey neoforgeTag(String name) { + return TagKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath("neoforge", name)); + } + } + + /** + * Use this to get a TagKey's translation key safely on any side. + * + * @return the translation key for a TagKey. + */ + public static String getTagTranslationKey(TagKey tagKey) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("tag."); + + ResourceLocation registryIdentifier = tagKey.registry().location(); + ResourceLocation tagIdentifier = tagKey.location(); + + if (!registryIdentifier.getNamespace().equals("minecraft")) { + stringBuilder.append(registryIdentifier.getNamespace()) + .append("."); } + + stringBuilder.append(registryIdentifier.getPath().replace("/", ".")) + .append(".") + .append(tagIdentifier.getNamespace()) + .append(".") + .append(tagIdentifier.getPath().replace("/", ".").replace(":", ".")); + + return stringBuilder.toString(); } } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BiomeTagsProvider.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BiomeTagsProvider.java index 3262e0b6e..a3da4a4c7 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BiomeTagsProvider.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BiomeTagsProvider.java @@ -1,91 +1,247 @@ package io.github.fabricators_of_create.porting_lib.tags.data; +import java.util.concurrent.CompletableFuture; + import io.github.fabricators_of_create.porting_lib.tags.Tags; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.BiomeTags; import net.minecraft.tags.TagKey; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; -import java.util.concurrent.CompletableFuture; - public final class BiomeTagsProvider extends FabricTagProvider { - - public BiomeTagsProvider(FabricDataOutput output, CompletableFuture registriesFuture) { - super(output, Registries.BIOME, registriesFuture); + public BiomeTagsProvider(FabricDataOutput output, CompletableFuture lookupProvider) { + super(output, Registries.BIOME, lookupProvider); } @Override - protected void addTags(HolderLookup.Provider arg) { - tag(Biomes.PLAINS, Tags.Biomes.IS_PLAINS); - tag(Biomes.DESERT, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_DRY_OVERWORLD, Tags.Biomes.IS_SANDY, Tags.Biomes.IS_DESERT); - tag(Biomes.TAIGA, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_CONIFEROUS); - tag(Biomes.SWAMP, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_SWAMP); - tag(Biomes.NETHER_WASTES, Tags.Biomes.IS_HOT_NETHER, Tags.Biomes.IS_DRY_NETHER); - tag(Biomes.THE_END, Tags.Biomes.IS_COLD_END, Tags.Biomes.IS_DRY_END); - tag(Biomes.FROZEN_OCEAN, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SNOWY); - tag(Biomes.FROZEN_RIVER, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SNOWY); - tag(Biomes.SNOWY_PLAINS, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_WASTELAND, Tags.Biomes.IS_PLAINS); - tag(Biomes.MUSHROOM_FIELDS, Tags.Biomes.IS_MUSHROOM, Tags.Biomes.IS_RARE); - tag(Biomes.JUNGLE, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_DENSE_OVERWORLD); - tag(Biomes.SPARSE_JUNGLE, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.BEACH, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_SANDY); - tag(Biomes.SNOWY_BEACH, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SNOWY); - tag(Biomes.DARK_FOREST, Tags.Biomes.IS_SPOOKY, Tags.Biomes.IS_DENSE_OVERWORLD); - tag(Biomes.SNOWY_TAIGA, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_CONIFEROUS, Tags.Biomes.IS_SNOWY); - tag(Biomes.OLD_GROWTH_PINE_TAIGA, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_CONIFEROUS); - tag(Biomes.WINDSWEPT_FOREST, Tags.Biomes.IS_SPARSE_OVERWORLD); - tag(Biomes.SAVANNA, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD); - tag(Biomes.SAVANNA_PLATEAU, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_RARE, Tags.Biomes.IS_SLOPE, Tags.Biomes.IS_PLATEAU); - tag(Biomes.BADLANDS, Tags.Biomes.IS_SANDY, Tags.Biomes.IS_DRY_OVERWORLD); - tag(Biomes.WOODED_BADLANDS, Tags.Biomes.IS_SANDY, Tags.Biomes.IS_DRY_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_SLOPE, Tags.Biomes.IS_PLATEAU); - tag(Biomes.MEADOW, Tags.Biomes.IS_PLAINS, Tags.Biomes.IS_PLATEAU, Tags.Biomes.IS_SLOPE); - tag(Biomes.GROVE, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_CONIFEROUS, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_SLOPE); - tag(Biomes.SNOWY_SLOPES, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_SLOPE); - tag(Biomes.JAGGED_PEAKS, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_PEAK); - tag(Biomes.FROZEN_PEAKS, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_PEAK); - tag(Biomes.STONY_PEAKS, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_PEAK); - tag(Biomes.SMALL_END_ISLANDS, Tags.Biomes.IS_COLD_END, Tags.Biomes.IS_DRY_END); - tag(Biomes.END_MIDLANDS, Tags.Biomes.IS_COLD_END, Tags.Biomes.IS_DRY_END); - tag(Biomes.END_HIGHLANDS, Tags.Biomes.IS_COLD_END, Tags.Biomes.IS_DRY_END); - tag(Biomes.END_BARRENS, Tags.Biomes.IS_COLD_END, Tags.Biomes.IS_DRY_END); - tag(Biomes.WARM_OCEAN, Tags.Biomes.IS_HOT_OVERWORLD); - tag(Biomes.COLD_OCEAN, Tags.Biomes.IS_COLD_OVERWORLD); - tag(Biomes.DEEP_COLD_OCEAN, Tags.Biomes.IS_COLD_OVERWORLD); - tag(Biomes.DEEP_FROZEN_OCEAN, Tags.Biomes.IS_COLD_OVERWORLD); - tag(Biomes.THE_VOID, Tags.Biomes.IS_VOID); - tag(Biomes.SUNFLOWER_PLAINS, Tags.Biomes.IS_PLAINS, Tags.Biomes.IS_RARE); - tag(Biomes.WINDSWEPT_GRAVELLY_HILLS, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.FLOWER_FOREST, Tags.Biomes.IS_RARE); - tag(Biomes.ICE_SPIKES, Tags.Biomes.IS_COLD_OVERWORLD, Tags.Biomes.IS_SNOWY, Tags.Biomes.IS_RARE); - tag(Biomes.OLD_GROWTH_BIRCH_FOREST, Tags.Biomes.IS_DENSE_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.OLD_GROWTH_SPRUCE_TAIGA, Tags.Biomes.IS_DENSE_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.WINDSWEPT_SAVANNA, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_DRY_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.ERODED_BADLANDS, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_DRY_OVERWORLD, Tags.Biomes.IS_SPARSE_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.BAMBOO_JUNGLE, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_RARE); - tag(Biomes.LUSH_CAVES, Tags.Biomes.IS_CAVE, Tags.Biomes.IS_LUSH, Tags.Biomes.IS_WET_OVERWORLD); - tag(Biomes.DRIPSTONE_CAVES, Tags.Biomes.IS_CAVE, Tags.Biomes.IS_SPARSE_OVERWORLD); - tag(Biomes.SOUL_SAND_VALLEY, Tags.Biomes.IS_HOT_NETHER, Tags.Biomes.IS_DRY_NETHER); - tag(Biomes.CRIMSON_FOREST, Tags.Biomes.IS_HOT_NETHER, Tags.Biomes.IS_DRY_NETHER); - tag(Biomes.WARPED_FOREST, Tags.Biomes.IS_HOT_NETHER, Tags.Biomes.IS_DRY_NETHER); - tag(Biomes.BASALT_DELTAS, Tags.Biomes.IS_HOT_NETHER, Tags.Biomes.IS_DRY_NETHER); - tag(Biomes.MANGROVE_SWAMP, Tags.Biomes.IS_WET_OVERWORLD, Tags.Biomes.IS_HOT_OVERWORLD, Tags.Biomes.IS_SWAMP); - tag(Biomes.DEEP_DARK, Tags.Biomes.IS_CAVE, Tags.Biomes.IS_RARE, Tags.Biomes.IS_SPOOKY); + protected void addTags(HolderLookup.Provider lookupProvider) { + tag(Tags.Biomes.NO_DEFAULT_MONSTERS).add(Biomes.MUSHROOM_FIELDS).add(Biomes.DEEP_DARK); + tag(Tags.Biomes.HIDDEN_FROM_LOCATOR_SELECTION); // Create tag file for visibility + + tag(Tags.Biomes.IS_VOID).add(Biomes.THE_VOID); + tag(Tags.Biomes.IS_END).addTag(BiomeTags.IS_END); + tag(Tags.Biomes.IS_NETHER).addTag(BiomeTags.IS_NETHER); + tag(Tags.Biomes.IS_OVERWORLD).addTag(BiomeTags.IS_OVERWORLD); + + tag(Tags.Biomes.IS_HOT_OVERWORLD) + .add(Biomes.SWAMP) + .add(Biomes.MANGROVE_SWAMP) + .add(Biomes.JUNGLE) + .add(Biomes.BAMBOO_JUNGLE) + .add(Biomes.SPARSE_JUNGLE) + .add(Biomes.DESERT) + .add(Biomes.ERODED_BADLANDS) + .add(Biomes.SAVANNA) + .add(Biomes.SAVANNA_PLATEAU) + .add(Biomes.WINDSWEPT_SAVANNA) + .add(Biomes.STONY_PEAKS) + .add(Biomes.WARM_OCEAN); + tag(Tags.Biomes.IS_HOT_NETHER) + .add(Biomes.NETHER_WASTES) + .add(Biomes.CRIMSON_FOREST) + .add(Biomes.WARPED_FOREST) + .add(Biomes.SOUL_SAND_VALLEY) + .add(Biomes.BASALT_DELTAS); + tag(Tags.Biomes.IS_HOT_END); tag(Tags.Biomes.IS_HOT).addTag(Tags.Biomes.IS_HOT_OVERWORLD).addTag(Tags.Biomes.IS_HOT_NETHER).addOptionalTag(Tags.Biomes.IS_HOT_END.location()); + + tag(Tags.Biomes.IS_COLD_OVERWORLD) + .add(Biomes.TAIGA) + .add(Biomes.OLD_GROWTH_PINE_TAIGA) + .add(Biomes.SNOWY_PLAINS) + .add(Biomes.ICE_SPIKES) + .add(Biomes.GROVE) + .add(Biomes.SNOWY_SLOPES) + .add(Biomes.JAGGED_PEAKS) + .add(Biomes.FROZEN_PEAKS) + .add(Biomes.SNOWY_BEACH) + .add(Biomes.SNOWY_TAIGA) + .add(Biomes.FROZEN_RIVER) + .add(Biomes.COLD_OCEAN) + .add(Biomes.FROZEN_OCEAN) + .add(Biomes.DEEP_COLD_OCEAN) + .add(Biomes.DEEP_FROZEN_OCEAN); + tag(Tags.Biomes.IS_COLD_NETHER); + tag(Tags.Biomes.IS_COLD_END) + .add(Biomes.THE_END) + .add(Biomes.SMALL_END_ISLANDS) + .add(Biomes.END_MIDLANDS) + .add(Biomes.END_HIGHLANDS) + .add(Biomes.END_BARRENS); tag(Tags.Biomes.IS_COLD).addTag(Tags.Biomes.IS_COLD_OVERWORLD).addOptionalTag(Tags.Biomes.IS_COLD_NETHER.location()).addTag(Tags.Biomes.IS_COLD_END); - tag(Tags.Biomes.IS_SPARSE).addTag(Tags.Biomes.IS_SPARSE_OVERWORLD).addOptionalTag(Tags.Biomes.IS_SPARSE_NETHER.location()).addOptionalTag(Tags.Biomes.IS_SPARSE_END.location()); - tag(Tags.Biomes.IS_DENSE).addTag(Tags.Biomes.IS_DENSE_OVERWORLD).addOptionalTag(Tags.Biomes.IS_DENSE_NETHER.location()).addOptionalTag(Tags.Biomes.IS_DENSE_END.location()); + + tag(Tags.Biomes.IS_SPARSE_VEGETATION_OVERWORLD) + .add(Biomes.WOODED_BADLANDS) + .add(Biomes.SAVANNA) + .add(Biomes.SAVANNA_PLATEAU) + .add(Biomes.WINDSWEPT_SAVANNA) + .add(Biomes.WINDSWEPT_FOREST) + .add(Biomes.WINDSWEPT_HILLS) + .add(Biomes.WINDSWEPT_GRAVELLY_HILLS) + .add(Biomes.SNOWY_SLOPES) + .add(Biomes.JAGGED_PEAKS) + .add(Biomes.FROZEN_PEAKS); + tag(Tags.Biomes.IS_SPARSE_VEGETATION_NETHER); + tag(Tags.Biomes.IS_SPARSE_VEGETATION_END); + tag(Tags.Biomes.IS_SPARSE_VEGETATION).addTag(Tags.Biomes.IS_SPARSE_VEGETATION_OVERWORLD).addOptionalTag(Tags.Biomes.IS_SPARSE_VEGETATION_NETHER.location()).addOptionalTag(Tags.Biomes.IS_SPARSE_VEGETATION_END.location()); + + tag(Tags.Biomes.IS_DENSE_VEGETATION_OVERWORLD) + .add(Biomes.DARK_FOREST) + .add(Biomes.OLD_GROWTH_BIRCH_FOREST) + .add(Biomes.OLD_GROWTH_SPRUCE_TAIGA) + .add(Biomes.JUNGLE) + .add(Biomes.BAMBOO_JUNGLE) + .add(Biomes.MANGROVE_SWAMP); + tag(Tags.Biomes.IS_DENSE_VEGETATION_NETHER); + tag(Tags.Biomes.IS_DENSE_VEGETATION_END); + tag(Tags.Biomes.IS_DENSE_VEGETATION).addTag(Tags.Biomes.IS_DENSE_VEGETATION_OVERWORLD).addOptionalTag(Tags.Biomes.IS_DENSE_VEGETATION_NETHER.location()).addOptionalTag(Tags.Biomes.IS_DENSE_VEGETATION_END.location()); + + tag(Tags.Biomes.IS_WET_OVERWORLD) + .add(Biomes.SWAMP) + .add(Biomes.MANGROVE_SWAMP) + .add(Biomes.JUNGLE) + .add(Biomes.BAMBOO_JUNGLE) + .add(Biomes.SPARSE_JUNGLE) + .add(Biomes.BEACH) + .add(Biomes.LUSH_CAVES) + .add(Biomes.DRIPSTONE_CAVES); + tag(Tags.Biomes.IS_WET_NETHER); + tag(Tags.Biomes.IS_WET_END); tag(Tags.Biomes.IS_WET).addTag(Tags.Biomes.IS_WET_OVERWORLD).addOptionalTag(Tags.Biomes.IS_WET_NETHER.location()).addOptionalTag(Tags.Biomes.IS_WET_END.location()); + + tag(Tags.Biomes.IS_DRY_OVERWORLD) + .add(Biomes.DESERT) + .add(Biomes.BADLANDS) + .add(Biomes.WOODED_BADLANDS) + .add(Biomes.ERODED_BADLANDS) + .add(Biomes.SAVANNA) + .add(Biomes.SAVANNA_PLATEAU) + .add(Biomes.WINDSWEPT_SAVANNA); + tag(Tags.Biomes.IS_DRY_NETHER) + .add(Biomes.NETHER_WASTES) + .add(Biomes.CRIMSON_FOREST) + .add(Biomes.WARPED_FOREST) + .add(Biomes.SOUL_SAND_VALLEY) + .add(Biomes.BASALT_DELTAS); + tag(Tags.Biomes.IS_DRY_END) + .add(Biomes.THE_END) + .add(Biomes.SMALL_END_ISLANDS) + .add(Biomes.END_MIDLANDS) + .add(Biomes.END_HIGHLANDS) + .add(Biomes.END_BARRENS); tag(Tags.Biomes.IS_DRY).addTag(Tags.Biomes.IS_DRY_OVERWORLD).addTag(Tags.Biomes.IS_DRY_NETHER).addTag(Tags.Biomes.IS_DRY_END); - tag(Tags.Biomes.IS_WATER).forceAddTag(BiomeTags.IS_OCEAN).forceAddTag(BiomeTags.IS_RIVER); // force because it thinks they don't exist - tag(Tags.Biomes.IS_MOUNTAIN).addTag(Tags.Biomes.IS_PEAK).addTag(Tags.Biomes.IS_SLOPE); + tag(Tags.Biomes.IS_CONIFEROUS_TREE).addTag(Tags.Biomes.IS_TAIGA).add(Biomes.GROVE); + tag(Tags.Biomes.IS_SAVANNA_TREE).addTag(Tags.Biomes.IS_SAVANNA); + tag(Tags.Biomes.IS_JUNGLE_TREE).addTag(Tags.Biomes.IS_JUNGLE); + tag(Tags.Biomes.IS_DECIDUOUS_TREE).add(Biomes.FOREST).add(Biomes.FLOWER_FOREST).add(Biomes.BIRCH_FOREST).add(Biomes.DARK_FOREST).add(Biomes.OLD_GROWTH_BIRCH_FOREST).add(Biomes.WINDSWEPT_FOREST); + + tag(Tags.Biomes.IS_MOUNTAIN_SLOPE).add(Biomes.SNOWY_SLOPES).add(Biomes.MEADOW).add(Biomes.GROVE).add(Biomes.CHERRY_GROVE); + tag(Tags.Biomes.IS_MOUNTAIN_PEAK).add(Biomes.JAGGED_PEAKS).add(Biomes.FROZEN_PEAKS).add(Biomes.STONY_PEAKS); + tag(Tags.Biomes.IS_MOUNTAIN).addTag(BiomeTags.IS_MOUNTAIN).addTag(Tags.Biomes.IS_MOUNTAIN_PEAK).addTag(Tags.Biomes.IS_MOUNTAIN_SLOPE); + + tag(Tags.Biomes.IS_FOREST).addTag(BiomeTags.IS_FOREST); + tag(Tags.Biomes.IS_BIRCH_FOREST).add(Biomes.BIRCH_FOREST).add(Biomes.OLD_GROWTH_BIRCH_FOREST); + tag(Tags.Biomes.IS_FLOWER_FOREST).add(Biomes.FLOWER_FOREST); + tag(Tags.Biomes.IS_FLORAL).addTag(Tags.Biomes.IS_FLOWER_FOREST).add(Biomes.SUNFLOWER_PLAINS).add(Biomes.CHERRY_GROVE).add(Biomes.MEADOW); + tag(Tags.Biomes.IS_BEACH).addTag(BiomeTags.IS_BEACH); + tag(Tags.Biomes.IS_STONY_SHORES).add(Biomes.STONY_SHORE); + tag(Tags.Biomes.IS_DESERT).add(Biomes.DESERT); + tag(Tags.Biomes.IS_BADLANDS).addTag(BiomeTags.IS_BADLANDS); + tag(Tags.Biomes.IS_PLAINS).add(Biomes.PLAINS).add(Biomes.SUNFLOWER_PLAINS); + tag(Tags.Biomes.IS_SNOWY_PLAINS).add(Biomes.SNOWY_PLAINS); + tag(Tags.Biomes.IS_TAIGA).addTag(BiomeTags.IS_TAIGA); + tag(Tags.Biomes.IS_HILL).addTag(BiomeTags.IS_HILL); + tag(Tags.Biomes.IS_WINDSWEPT).add(Biomes.WINDSWEPT_HILLS).add(Biomes.WINDSWEPT_GRAVELLY_HILLS).add(Biomes.WINDSWEPT_FOREST).add(Biomes.WINDSWEPT_SAVANNA); + tag(Tags.Biomes.IS_SAVANNA).addTag(BiomeTags.IS_SAVANNA); + tag(Tags.Biomes.IS_JUNGLE).addTag(BiomeTags.IS_JUNGLE); + tag(Tags.Biomes.IS_SNOWY).add(Biomes.SNOWY_BEACH).add(Biomes.SNOWY_PLAINS).add(Biomes.ICE_SPIKES).add(Biomes.SNOWY_TAIGA).add(Biomes.GROVE).add(Biomes.SNOWY_SLOPES).add(Biomes.JAGGED_PEAKS).add(Biomes.FROZEN_PEAKS); + tag(Tags.Biomes.IS_ICY).add(Biomes.ICE_SPIKES).add(Biomes.FROZEN_PEAKS); + tag(Tags.Biomes.IS_SWAMP).add(Biomes.SWAMP).add(Biomes.MANGROVE_SWAMP); + tag(Tags.Biomes.IS_OLD_GROWTH).add(Biomes.OLD_GROWTH_BIRCH_FOREST).add(Biomes.OLD_GROWTH_PINE_TAIGA).add(Biomes.OLD_GROWTH_SPRUCE_TAIGA); + tag(Tags.Biomes.IS_LUSH).add(Biomes.LUSH_CAVES); + tag(Tags.Biomes.IS_SANDY).add(Biomes.DESERT).add(Biomes.BADLANDS).add(Biomes.WOODED_BADLANDS).add(Biomes.ERODED_BADLANDS).add(Biomes.BEACH); + tag(Tags.Biomes.IS_MUSHROOM).add(Biomes.MUSHROOM_FIELDS); + tag(Tags.Biomes.IS_PLATEAU).add(Biomes.WOODED_BADLANDS).add(Biomes.SAVANNA_PLATEAU).add(Biomes.CHERRY_GROVE).add(Biomes.MEADOW); + tag(Tags.Biomes.IS_SPOOKY).add(Biomes.DARK_FOREST).add(Biomes.DEEP_DARK); + tag(Tags.Biomes.IS_WASTELAND); + tag(Tags.Biomes.IS_RARE).add(Biomes.SUNFLOWER_PLAINS).add(Biomes.FLOWER_FOREST).add(Biomes.OLD_GROWTH_BIRCH_FOREST).add(Biomes.OLD_GROWTH_SPRUCE_TAIGA).add(Biomes.BAMBOO_JUNGLE).add(Biomes.SPARSE_JUNGLE).add(Biomes.ERODED_BADLANDS).add(Biomes.SAVANNA_PLATEAU).add(Biomes.WINDSWEPT_SAVANNA).add(Biomes.ICE_SPIKES).add(Biomes.WINDSWEPT_GRAVELLY_HILLS).add(Biomes.MUSHROOM_FIELDS).add(Biomes.DEEP_DARK); + + tag(Tags.Biomes.IS_RIVER).addTag(BiomeTags.IS_RIVER); + tag(Tags.Biomes.IS_SHALLOW_OCEAN).add(Biomes.OCEAN).add(Biomes.LUKEWARM_OCEAN).add(Biomes.WARM_OCEAN).add(Biomes.COLD_OCEAN).add(Biomes.FROZEN_OCEAN); + tag(Tags.Biomes.IS_DEEP_OCEAN).addTag(BiomeTags.IS_DEEP_OCEAN); + tag(Tags.Biomes.IS_OCEAN).addTag(BiomeTags.IS_OCEAN).addTag(Tags.Biomes.IS_SHALLOW_OCEAN).addTag(Tags.Biomes.IS_DEEP_OCEAN); + tag(Tags.Biomes.IS_AQUATIC_ICY).add(Biomes.FROZEN_RIVER).add(Biomes.DEEP_FROZEN_OCEAN).add(Biomes.FROZEN_OCEAN); + tag(Tags.Biomes.IS_AQUATIC).addTag(Tags.Biomes.IS_OCEAN).addTag(Tags.Biomes.IS_RIVER); + + tag(Tags.Biomes.IS_CAVE).add(Biomes.LUSH_CAVES).add(Biomes.DRIPSTONE_CAVES).add(Biomes.DEEP_DARK); tag(Tags.Biomes.IS_UNDERGROUND).addTag(Tags.Biomes.IS_CAVE); + + tag(Tags.Biomes.IS_NETHER_FOREST).add(Biomes.CRIMSON_FOREST).add(Biomes.WARPED_FOREST); + tag(Tags.Biomes.IS_OUTER_END_ISLAND).add(Biomes.END_HIGHLANDS).add(Biomes.END_MIDLANDS).add(Biomes.END_BARRENS); + + // Backwards compat with pre-1.21 tags. Done after so optional tag is last for better readability. + // TODO: Remove backwards compat tag entries in 1.22 + tag(Tags.Biomes.IS_MOUNTAIN_SLOPE).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_slope")); + tag(Tags.Biomes.IS_MOUNTAIN_PEAK).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_peak")); + tagWithOptionalLegacy(Tags.Biomes.IS_MOUNTAIN); + tagWithOptionalLegacy(Tags.Biomes.IS_HOT_OVERWORLD); + tagWithOptionalLegacy(Tags.Biomes.IS_HOT_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_HOT_END); + tagWithOptionalLegacy(Tags.Biomes.IS_HOT); + tagWithOptionalLegacy(Tags.Biomes.IS_COLD_OVERWORLD); + tagWithOptionalLegacy(Tags.Biomes.IS_COLD_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_COLD_END); + tagWithOptionalLegacy(Tags.Biomes.IS_COLD); + tagWithOptionalLegacy(Tags.Biomes.IS_SPARSE_VEGETATION_OVERWORLD); + tagWithOptionalLegacy(Tags.Biomes.IS_SPARSE_VEGETATION_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_SPARSE_VEGETATION_END); + tagWithOptionalLegacy(Tags.Biomes.IS_SPARSE_VEGETATION); + tag(Tags.Biomes.IS_SPARSE_VEGETATION_OVERWORLD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_sparse/overworld")); + tag(Tags.Biomes.IS_SPARSE_VEGETATION_NETHER).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_sparse/nether")); + tag(Tags.Biomes.IS_SPARSE_VEGETATION_END).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_sparse/end")); + tag(Tags.Biomes.IS_SPARSE_VEGETATION).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_sparse")); + tag(Tags.Biomes.IS_DENSE_VEGETATION_OVERWORLD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_dense/overworld")); + tag(Tags.Biomes.IS_DENSE_VEGETATION_NETHER).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_dense/nether")); + tag(Tags.Biomes.IS_DENSE_VEGETATION_END).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_dense/end")); + tag(Tags.Biomes.IS_DENSE_VEGETATION).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_dense")); + tagWithOptionalLegacy(Tags.Biomes.IS_WET_OVERWORLD); + tagWithOptionalLegacy(Tags.Biomes.IS_WET_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_WET_END); + tagWithOptionalLegacy(Tags.Biomes.IS_WET); + tagWithOptionalLegacy(Tags.Biomes.IS_DRY_OVERWORLD); + tagWithOptionalLegacy(Tags.Biomes.IS_DRY_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_DRY_END); + tagWithOptionalLegacy(Tags.Biomes.IS_DRY); + tagWithOptionalLegacy(Tags.Biomes.IS_CONIFEROUS_TREE); + tagWithOptionalLegacy(Tags.Biomes.IS_SPOOKY); + tagWithOptionalLegacy(Tags.Biomes.IS_DEAD); + tagWithOptionalLegacy(Tags.Biomes.IS_LUSH); + tagWithOptionalLegacy(Tags.Biomes.IS_MUSHROOM); + tagWithOptionalLegacy(Tags.Biomes.IS_MAGICAL); + tagWithOptionalLegacy(Tags.Biomes.IS_RARE); + tagWithOptionalLegacy(Tags.Biomes.IS_PLATEAU); + tagWithOptionalLegacy(Tags.Biomes.IS_MODIFIED); + tagWithOptionalLegacy(Tags.Biomes.IS_FLORAL); + tag(Tags.Biomes.IS_AQUATIC).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "is_water")); + tagWithOptionalLegacy(Tags.Biomes.IS_DESERT); + tagWithOptionalLegacy(Tags.Biomes.IS_PLAINS); + tagWithOptionalLegacy(Tags.Biomes.IS_SWAMP); + tagWithOptionalLegacy(Tags.Biomes.IS_SANDY); + tagWithOptionalLegacy(Tags.Biomes.IS_SNOWY); + tagWithOptionalLegacy(Tags.Biomes.IS_WASTELAND); + tagWithOptionalLegacy(Tags.Biomes.IS_VOID); + tagWithOptionalLegacy(Tags.Biomes.IS_CAVE); + tagWithOptionalLegacy(Tags.Biomes.IS_END); + tagWithOptionalLegacy(Tags.Biomes.IS_NETHER); + tagWithOptionalLegacy(Tags.Biomes.IS_OVERWORLD); } @SafeVarargs @@ -95,7 +251,12 @@ private void tag(ResourceKey biome, TagKey... tags) { } } - public FabricTagBuilder tag(TagKey tag) { - return getOrCreateTagBuilder(tag); + private TagAppender tagWithOptionalLegacy(TagKey tag) { + return tag(tag).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", tag.location().getPath())); + } + + @Override + public String getName() { + return "PortingLib Biome Tags"; } } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BlockTagProvider.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BlockTagProvider.java index fc4528f8e..d88ce6959 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BlockTagProvider.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/BlockTagProvider.java @@ -1,75 +1,5 @@ package io.github.fabricators_of_create.porting_lib.tags.data; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.BARRELS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.BARRELS_WOODEN; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.CHESTS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.CHESTS_ENDER; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.CHESTS_TRAPPED; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.CHESTS_WOODEN; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.COBBLESTONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.COBBLESTONE_DEEPSLATE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.COBBLESTONE_INFESTED; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.COBBLESTONE_MOSSY; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.COBBLESTONE_NORMAL; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ENDERMAN_PLACE_ON_BLACKLIST; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.END_STONES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.FENCES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.FENCES_NETHER_BRICK; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.FENCES_WOODEN; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.FENCE_GATES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.FENCE_GATES_WOODEN; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS_COLORLESS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS_PANES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS_PANES_COLORLESS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS_SILICA; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GLASS_TINTED; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.GRAVEL; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.NETHERRACK; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.OBSIDIAN; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_COAL; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_COPPER; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_DIAMOND; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_EMERALD; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_GOLD; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_IN_GROUND_DEEPSLATE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_IN_GROUND_NETHERRACK; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_IN_GROUND_STONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_IRON; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_LAPIS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_NETHERITE_SCRAP; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_QUARTZ; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORES_REDSTONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_BEARING_GROUND_STONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_RATES_DENSE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_RATES_SINGULAR; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.ORE_RATES_SPARSE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.SAND; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.SANDSTONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.SAND_COLORLESS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.SAND_RED; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STAINED_GLASS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STAINED_GLASS_PANES; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STONE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_AMETHYST; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_COAL; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_COPPER; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_DIAMOND; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_EMERALD; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_GOLD; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_IRON; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_LAPIS; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_NETHERITE; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_QUARTZ; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_RAW_COPPER; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_RAW_GOLD; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_RAW_IRON; -import static io.github.fabricators_of_create.porting_lib.tags.Tags.Blocks.STORAGE_BLOCKS_REDSTONE; - import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -79,6 +9,7 @@ import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.tags.IntrinsicHolderTagsProvider; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.BlockTags; import net.minecraft.tags.TagKey; @@ -86,108 +17,290 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -public class BlockTagProvider extends FabricTagProvider.BlockTagProvider { - public BlockTagProvider(FabricDataOutput output, CompletableFuture registriesFuture) { - super(output, registriesFuture); +public final class BlockTagProvider extends FabricTagProvider.BlockTagProvider { + public BlockTagProvider(FabricDataOutput output, CompletableFuture lookupProvider) { + super(output, lookupProvider); } + @SuppressWarnings("unchecked") @Override - protected void addTags(HolderLookup.Provider arg) { - tag(BARRELS).addTag(BARRELS_WOODEN); - tag(BARRELS_WOODEN).add(Blocks.BARREL); - tag(CHESTS).addTag(CHESTS_ENDER).addTag(CHESTS_TRAPPED).addTag(CHESTS_WOODEN); - tag(CHESTS_ENDER).add(Blocks.ENDER_CHEST); - tag(CHESTS_TRAPPED).add(Blocks.TRAPPED_CHEST); - tag(CHESTS_WOODEN).add(Blocks.CHEST, Blocks.TRAPPED_CHEST); - tag(COBBLESTONE).addTag(COBBLESTONE_NORMAL).addTag(COBBLESTONE_INFESTED).addTag(COBBLESTONE_MOSSY).addTag(COBBLESTONE_DEEPSLATE); - tag(COBBLESTONE_NORMAL).add(Blocks.COBBLESTONE); - tag(COBBLESTONE_INFESTED).add(Blocks.INFESTED_COBBLESTONE); - tag(COBBLESTONE_MOSSY).add(Blocks.MOSSY_COBBLESTONE); - tag(COBBLESTONE_DEEPSLATE).add(Blocks.COBBLED_DEEPSLATE); - tag(END_STONES).add(Blocks.END_STONE); - tag(ENDERMAN_PLACE_ON_BLACKLIST); - tag(FENCE_GATES).addTag(FENCE_GATES_WOODEN); - tag(FENCE_GATES_WOODEN).add(Blocks.OAK_FENCE_GATE, Blocks.SPRUCE_FENCE_GATE, Blocks.BIRCH_FENCE_GATE, Blocks.JUNGLE_FENCE_GATE, Blocks.ACACIA_FENCE_GATE, Blocks.DARK_OAK_FENCE_GATE, Blocks.CRIMSON_FENCE_GATE, Blocks.WARPED_FENCE_GATE); - tag(FENCES).addTag(FENCES_NETHER_BRICK).addTag(FENCES_WOODEN); - tag(FENCES_NETHER_BRICK).add(Blocks.NETHER_BRICK_FENCE); - getOrCreateTagBuilder(FENCES_WOODEN).forceAddTag(BlockTags.WOODEN_FENCES); - tag(GLASS).addTag(GLASS_COLORLESS).addTag(STAINED_GLASS).addTag(GLASS_TINTED); - tag(GLASS_COLORLESS).add(Blocks.GLASS); - tag(GLASS_SILICA).add(Blocks.GLASS, Blocks.BLACK_STAINED_GLASS, Blocks.BLUE_STAINED_GLASS, Blocks.BROWN_STAINED_GLASS, Blocks.CYAN_STAINED_GLASS, Blocks.GRAY_STAINED_GLASS, Blocks.GREEN_STAINED_GLASS, Blocks.LIGHT_BLUE_STAINED_GLASS, Blocks.LIGHT_GRAY_STAINED_GLASS, Blocks.LIME_STAINED_GLASS, Blocks.MAGENTA_STAINED_GLASS, Blocks.ORANGE_STAINED_GLASS, Blocks.PINK_STAINED_GLASS, Blocks.PURPLE_STAINED_GLASS, Blocks.RED_STAINED_GLASS, Blocks.WHITE_STAINED_GLASS, Blocks.YELLOW_STAINED_GLASS); - tag(GLASS_TINTED).add(Blocks.TINTED_GLASS); - addColored(tag(STAINED_GLASS)::add, GLASS, "{color}_stained_glass"); - tag(GLASS_PANES).addTag(GLASS_PANES_COLORLESS).addTag(STAINED_GLASS_PANES); - tag(GLASS_PANES_COLORLESS).add(Blocks.GLASS_PANE); - addColored(tag(STAINED_GLASS_PANES)::add, GLASS_PANES, "{color}_stained_glass_pane"); - tag(GRAVEL).add(Blocks.GRAVEL); - tag(NETHERRACK).add(Blocks.NETHERRACK); - tag(OBSIDIAN).add(Blocks.OBSIDIAN); - tag(ORE_BEARING_GROUND_DEEPSLATE).add(Blocks.DEEPSLATE); - tag(ORE_BEARING_GROUND_NETHERRACK).add(Blocks.NETHERRACK); - tag(ORE_BEARING_GROUND_STONE).add(Blocks.STONE); - tag(ORE_RATES_DENSE).add(Blocks.COPPER_ORE, Blocks.DEEPSLATE_COPPER_ORE, Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DEEPSLATE_REDSTONE_ORE, Blocks.LAPIS_ORE, Blocks.REDSTONE_ORE); - tag(ORE_RATES_SINGULAR).add(Blocks.ANCIENT_DEBRIS, Blocks.COAL_ORE, Blocks.DEEPSLATE_COAL_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, Blocks.DEEPSLATE_EMERALD_ORE, Blocks.DEEPSLATE_GOLD_ORE, Blocks.DEEPSLATE_IRON_ORE, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.GOLD_ORE, Blocks.IRON_ORE, Blocks.NETHER_QUARTZ_ORE); - tag(ORE_RATES_SPARSE).add(Blocks.NETHER_GOLD_ORE); - tag(ORES).addTag(ORES_COAL).addTag(ORES_COPPER).addTag(ORES_DIAMOND).addTag(ORES_EMERALD).addTag(ORES_GOLD).addTag(ORES_IRON).addTag(ORES_LAPIS).addTag(ORES_REDSTONE).addTag(ORES_QUARTZ).addTag(ORES_NETHERITE_SCRAP); - getOrCreateTagBuilder(ORES_COAL).forceAddTag(BlockTags.COAL_ORES); - getOrCreateTagBuilder(ORES_COPPER).forceAddTag(BlockTags.COPPER_ORES); - getOrCreateTagBuilder(ORES_DIAMOND).forceAddTag(BlockTags.DIAMOND_ORES); - getOrCreateTagBuilder(ORES_EMERALD).forceAddTag(BlockTags.EMERALD_ORES); - getOrCreateTagBuilder(ORES_GOLD).forceAddTag(BlockTags.GOLD_ORES); - getOrCreateTagBuilder(ORES_IRON).forceAddTag(BlockTags.IRON_ORES); - getOrCreateTagBuilder(ORES_LAPIS).forceAddTag(BlockTags.LAPIS_ORES); - tag(ORES_QUARTZ).add(Blocks.NETHER_QUARTZ_ORE); - getOrCreateTagBuilder(ORES_REDSTONE).forceAddTag(BlockTags.REDSTONE_ORES); - tag(ORES_NETHERITE_SCRAP).add(Blocks.ANCIENT_DEBRIS); - tag(ORES_IN_GROUND_DEEPSLATE).add(Blocks.DEEPSLATE_COAL_ORE, Blocks.DEEPSLATE_COPPER_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, Blocks.DEEPSLATE_EMERALD_ORE, Blocks.DEEPSLATE_GOLD_ORE, Blocks.DEEPSLATE_IRON_ORE, Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DEEPSLATE_REDSTONE_ORE); - tag(ORES_IN_GROUND_NETHERRACK).add(Blocks.NETHER_GOLD_ORE, Blocks.NETHER_QUARTZ_ORE); - tag(ORES_IN_GROUND_STONE).add(Blocks.COAL_ORE, Blocks.COPPER_ORE, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.GOLD_ORE, Blocks.IRON_ORE, Blocks.LAPIS_ORE, Blocks.REDSTONE_ORE); - tag(SAND).addTag(SAND_COLORLESS).addTag(SAND_RED); - tag(SAND_COLORLESS).add(Blocks.SAND); - tag(SAND_RED).add(Blocks.RED_SAND); - tag(SANDSTONE).add(Blocks.SANDSTONE, Blocks.CUT_SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.SMOOTH_SANDSTONE, Blocks.RED_SANDSTONE, Blocks.CUT_RED_SANDSTONE, Blocks.CHISELED_RED_SANDSTONE, Blocks.SMOOTH_RED_SANDSTONE); - tag(STONE).add(Blocks.ANDESITE, Blocks.DIORITE, Blocks.GRANITE, Blocks.INFESTED_STONE, Blocks.STONE, Blocks.POLISHED_ANDESITE, Blocks.POLISHED_DIORITE, Blocks.POLISHED_GRANITE, Blocks.DEEPSLATE, Blocks.POLISHED_DEEPSLATE, Blocks.INFESTED_DEEPSLATE, Blocks.TUFF); - tag(STORAGE_BLOCKS).addTag(STORAGE_BLOCKS_AMETHYST).addTag(STORAGE_BLOCKS_COAL).addTag(STORAGE_BLOCKS_COPPER).addTag(STORAGE_BLOCKS_DIAMOND).addTag(STORAGE_BLOCKS_EMERALD).addTag(STORAGE_BLOCKS_GOLD).addTag(STORAGE_BLOCKS_IRON).addTag(STORAGE_BLOCKS_LAPIS).addTag(STORAGE_BLOCKS_QUARTZ).addTag(STORAGE_BLOCKS_RAW_COPPER).addTag(STORAGE_BLOCKS_RAW_GOLD).addTag(STORAGE_BLOCKS_RAW_IRON).addTag(STORAGE_BLOCKS_REDSTONE).addTag(STORAGE_BLOCKS_NETHERITE); - tag(STORAGE_BLOCKS_AMETHYST).add(Blocks.AMETHYST_BLOCK); - tag(STORAGE_BLOCKS_COAL).add(Blocks.COAL_BLOCK); - tag(STORAGE_BLOCKS_COPPER).add(Blocks.COPPER_BLOCK); // cut copper intentionally not included: #62 - tag(STORAGE_BLOCKS_DIAMOND).add(Blocks.DIAMOND_BLOCK); - tag(STORAGE_BLOCKS_EMERALD).add(Blocks.EMERALD_BLOCK); - tag(STORAGE_BLOCKS_GOLD).add(Blocks.GOLD_BLOCK); - tag(STORAGE_BLOCKS_IRON).add(Blocks.IRON_BLOCK); - tag(STORAGE_BLOCKS_LAPIS).add(Blocks.LAPIS_BLOCK); - tag(STORAGE_BLOCKS_QUARTZ).add(Blocks.QUARTZ_BLOCK); - tag(STORAGE_BLOCKS_RAW_COPPER).add(Blocks.RAW_COPPER_BLOCK); - tag(STORAGE_BLOCKS_RAW_GOLD).add(Blocks.RAW_GOLD_BLOCK); - tag(STORAGE_BLOCKS_RAW_IRON).add(Blocks.RAW_IRON_BLOCK); - tag(STORAGE_BLOCKS_REDSTONE).add(Blocks.REDSTONE_BLOCK); - tag(STORAGE_BLOCKS_NETHERITE).add(Blocks.NETHERITE_BLOCK); + public void addTags(HolderLookup.Provider p_256380_) { + tag(Tags.Blocks.BARRELS).addTag(Tags.Blocks.BARRELS_WOODEN); + tag(Tags.Blocks.BARRELS_WOODEN).add(Blocks.BARREL); + tag(Tags.Blocks.BOOKSHELVES).add(Blocks.BOOKSHELF); + tag(Tags.Blocks.BUDDING_BLOCKS).add(Blocks.BUDDING_AMETHYST); + tag(Tags.Blocks.BUDS).add(Blocks.SMALL_AMETHYST_BUD).add(Blocks.MEDIUM_AMETHYST_BUD).add(Blocks.LARGE_AMETHYST_BUD); + tag(Tags.Blocks.CHAINS).add(Blocks.CHAIN); + tag(Tags.Blocks.CHESTS).addTag(Tags.Blocks.CHESTS_ENDER).addTag(Tags.Blocks.CHESTS_TRAPPED).addTag(Tags.Blocks.CHESTS_WOODEN); + tag(Tags.Blocks.CHESTS_ENDER).add(Blocks.ENDER_CHEST); + tag(Tags.Blocks.CHESTS_TRAPPED).add(Blocks.TRAPPED_CHEST); + tag(Tags.Blocks.CHESTS_WOODEN).add(Blocks.CHEST, Blocks.TRAPPED_CHEST); + tag(Tags.Blocks.CLUSTERS).add(Blocks.AMETHYST_CLUSTER); + tag(Tags.Blocks.COBBLESTONES).addTag(Tags.Blocks.COBBLESTONES_NORMAL).addTag(Tags.Blocks.COBBLESTONES_INFESTED).addTag(Tags.Blocks.COBBLESTONES_MOSSY).addTag(Tags.Blocks.COBBLESTONES_DEEPSLATE); + tag(Tags.Blocks.COBBLESTONES_NORMAL).add(Blocks.COBBLESTONE); + tag(Tags.Blocks.COBBLESTONES_INFESTED).add(Blocks.INFESTED_COBBLESTONE); + tag(Tags.Blocks.COBBLESTONES_MOSSY).add(Blocks.MOSSY_COBBLESTONE); + tag(Tags.Blocks.COBBLESTONES_DEEPSLATE).add(Blocks.COBBLED_DEEPSLATE); + tag(Tags.Blocks.CONCRETES).add(Blocks.WHITE_CONCRETE, Blocks.ORANGE_CONCRETE, Blocks.MAGENTA_CONCRETE, Blocks.LIGHT_BLUE_CONCRETE, Blocks.YELLOW_CONCRETE, Blocks.LIME_CONCRETE, Blocks.PINK_CONCRETE, Blocks.GRAY_CONCRETE, Blocks.LIGHT_GRAY_CONCRETE, Blocks.CYAN_CONCRETE, Blocks.PURPLE_CONCRETE, Blocks.BLUE_CONCRETE, Blocks.BROWN_CONCRETE, Blocks.GREEN_CONCRETE, Blocks.RED_CONCRETE, Blocks.BLACK_CONCRETE); + addColored(Tags.Blocks.DYED, "{color}_banner"); + addColored(Tags.Blocks.DYED, "{color}_bed"); + addColored(Tags.Blocks.DYED, "{color}_candle"); + addColored(Tags.Blocks.DYED, "{color}_carpet"); + addColored(Tags.Blocks.DYED, "{color}_concrete"); + addColored(Tags.Blocks.DYED, "{color}_concrete_powder"); + addColored(Tags.Blocks.DYED, "{color}_glazed_terracotta"); + addColored(Tags.Blocks.DYED, "{color}_shulker_box"); + addColored(Tags.Blocks.DYED, "{color}_stained_glass"); + addColored(Tags.Blocks.DYED, "{color}_stained_glass_pane"); + addColored(Tags.Blocks.DYED, "{color}_terracotta"); + addColored(Tags.Blocks.DYED, "{color}_wall_banner"); + addColored(Tags.Blocks.DYED, "{color}_wool"); + addColoredTags(tag(Tags.Blocks.DYED)::addTag, Tags.Blocks.DYED); + tag(Tags.Blocks.END_STONES).add(Blocks.END_STONE); + tag(Tags.Blocks.ENDERMAN_PLACE_ON_BLACKLIST); + tag(Tags.Blocks.FENCE_GATES).addTag(Tags.Blocks.FENCE_GATES_WOODEN); + tag(Tags.Blocks.FENCE_GATES_WOODEN).add(Blocks.OAK_FENCE_GATE, Blocks.SPRUCE_FENCE_GATE, Blocks.BIRCH_FENCE_GATE, Blocks.JUNGLE_FENCE_GATE, Blocks.ACACIA_FENCE_GATE, Blocks.DARK_OAK_FENCE_GATE, Blocks.CRIMSON_FENCE_GATE, Blocks.WARPED_FENCE_GATE, Blocks.MANGROVE_FENCE_GATE, Blocks.BAMBOO_FENCE_GATE, Blocks.CHERRY_FENCE_GATE); + tag(Tags.Blocks.FENCES).addTag(Tags.Blocks.FENCES_NETHER_BRICK).addTag(Tags.Blocks.FENCES_WOODEN); + tag(Tags.Blocks.FENCES_NETHER_BRICK).add(Blocks.NETHER_BRICK_FENCE); + tag(Tags.Blocks.FENCES_WOODEN).addTag(BlockTags.WOODEN_FENCES); + tag(Tags.Blocks.GLASS_BLOCKS).addTag(Tags.Blocks.GLASS_BLOCKS_COLORLESS).addTag(Tags.Blocks.GLASS_BLOCKS_CHEAP).addTag(Tags.Blocks.GLASS_BLOCKS_TINTED).add(Blocks.WHITE_STAINED_GLASS, Blocks.ORANGE_STAINED_GLASS, Blocks.MAGENTA_STAINED_GLASS, Blocks.LIGHT_BLUE_STAINED_GLASS, Blocks.YELLOW_STAINED_GLASS, Blocks.LIME_STAINED_GLASS, Blocks.PINK_STAINED_GLASS, Blocks.GRAY_STAINED_GLASS, Blocks.LIGHT_GRAY_STAINED_GLASS, Blocks.CYAN_STAINED_GLASS, Blocks.PURPLE_STAINED_GLASS, Blocks.BLUE_STAINED_GLASS, Blocks.BROWN_STAINED_GLASS, Blocks.GREEN_STAINED_GLASS, Blocks.RED_STAINED_GLASS, Blocks.BLACK_STAINED_GLASS); + tag(Tags.Blocks.GLASS_BLOCKS_COLORLESS).add(Blocks.GLASS); + tag(Tags.Blocks.GLASS_BLOCKS_CHEAP).add(Blocks.GLASS, Blocks.WHITE_STAINED_GLASS, Blocks.ORANGE_STAINED_GLASS, Blocks.MAGENTA_STAINED_GLASS, Blocks.LIGHT_BLUE_STAINED_GLASS, Blocks.YELLOW_STAINED_GLASS, Blocks.LIME_STAINED_GLASS, Blocks.PINK_STAINED_GLASS, Blocks.GRAY_STAINED_GLASS, Blocks.LIGHT_GRAY_STAINED_GLASS, Blocks.CYAN_STAINED_GLASS, Blocks.PURPLE_STAINED_GLASS, Blocks.BLUE_STAINED_GLASS, Blocks.BROWN_STAINED_GLASS, Blocks.GREEN_STAINED_GLASS, Blocks.RED_STAINED_GLASS, Blocks.BLACK_STAINED_GLASS); + tag(Tags.Blocks.GLASS_BLOCKS_TINTED).add(Blocks.TINTED_GLASS); + tag(Tags.Blocks.GLASS_PANES).addTag(Tags.Blocks.GLASS_PANES_COLORLESS).add(Blocks.WHITE_STAINED_GLASS_PANE, Blocks.ORANGE_STAINED_GLASS_PANE, Blocks.MAGENTA_STAINED_GLASS_PANE, Blocks.LIGHT_BLUE_STAINED_GLASS_PANE, Blocks.YELLOW_STAINED_GLASS_PANE, Blocks.LIME_STAINED_GLASS_PANE, Blocks.PINK_STAINED_GLASS_PANE, Blocks.GRAY_STAINED_GLASS_PANE, Blocks.LIGHT_GRAY_STAINED_GLASS_PANE, Blocks.CYAN_STAINED_GLASS_PANE, Blocks.PURPLE_STAINED_GLASS_PANE, Blocks.BLUE_STAINED_GLASS_PANE, Blocks.BROWN_STAINED_GLASS_PANE, Blocks.GREEN_STAINED_GLASS_PANE, Blocks.RED_STAINED_GLASS_PANE, Blocks.BLACK_STAINED_GLASS_PANE); + tag(Tags.Blocks.GLASS_PANES_COLORLESS).add(Blocks.GLASS_PANE); + tag(Tags.Blocks.GLAZED_TERRACOTTAS).add(Blocks.WHITE_GLAZED_TERRACOTTA, Blocks.ORANGE_GLAZED_TERRACOTTA, Blocks.MAGENTA_GLAZED_TERRACOTTA, Blocks.LIGHT_BLUE_GLAZED_TERRACOTTA, Blocks.YELLOW_GLAZED_TERRACOTTA, Blocks.LIME_GLAZED_TERRACOTTA, Blocks.PINK_GLAZED_TERRACOTTA, Blocks.GRAY_GLAZED_TERRACOTTA, Blocks.LIGHT_GRAY_GLAZED_TERRACOTTA, Blocks.CYAN_GLAZED_TERRACOTTA, Blocks.PURPLE_GLAZED_TERRACOTTA, Blocks.BLUE_GLAZED_TERRACOTTA, Blocks.BROWN_GLAZED_TERRACOTTA, Blocks.GREEN_GLAZED_TERRACOTTA, Blocks.RED_GLAZED_TERRACOTTA, Blocks.BLACK_GLAZED_TERRACOTTA); + tag(Tags.Blocks.GRAVELS).add(Blocks.GRAVEL); + tag(Tags.Blocks.SKULLS).add(Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL, Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL, Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD, Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD, Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD, Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD, Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD); + tag(Tags.Blocks.HIDDEN_FROM_RECIPE_VIEWERS); + tag(Tags.Blocks.NETHERRACKS).add(Blocks.NETHERRACK); + tag(Tags.Blocks.OBSIDIANS).add(Blocks.OBSIDIAN); + tag(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE).add(Blocks.DEEPSLATE); + tag(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK).add(Blocks.NETHERRACK); + tag(Tags.Blocks.ORE_BEARING_GROUND_STONE).add(Blocks.STONE); + tag(Tags.Blocks.ORE_RATES_DENSE).add(Blocks.COPPER_ORE, Blocks.DEEPSLATE_COPPER_ORE, Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DEEPSLATE_REDSTONE_ORE, Blocks.LAPIS_ORE, Blocks.REDSTONE_ORE); + tag(Tags.Blocks.ORE_RATES_SINGULAR).add(Blocks.ANCIENT_DEBRIS, Blocks.COAL_ORE, Blocks.DEEPSLATE_COAL_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, Blocks.DEEPSLATE_EMERALD_ORE, Blocks.DEEPSLATE_GOLD_ORE, Blocks.DEEPSLATE_IRON_ORE, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.GOLD_ORE, Blocks.IRON_ORE, Blocks.NETHER_QUARTZ_ORE); + tag(Tags.Blocks.ORE_RATES_SPARSE).add(Blocks.NETHER_GOLD_ORE); + tag(Tags.Blocks.ORES).addTag(Tags.Blocks.ORES_COAL).addTag(Tags.Blocks.ORES_COPPER).addTag(Tags.Blocks.ORES_DIAMOND).addTag(Tags.Blocks.ORES_EMERALD).addTag(Tags.Blocks.ORES_GOLD).addTag(Tags.Blocks.ORES_IRON).addTag(Tags.Blocks.ORES_LAPIS).addTag(Tags.Blocks.ORES_NETHERITE_SCRAP).addTag(Tags.Blocks.ORES_REDSTONE).addTag(Tags.Blocks.ORES_QUARTZ); + tag(Tags.Blocks.ORES_COAL).addTag(BlockTags.COAL_ORES); + tag(Tags.Blocks.ORES_COPPER).addTag(BlockTags.COPPER_ORES); + tag(Tags.Blocks.ORES_DIAMOND).addTag(BlockTags.DIAMOND_ORES); + tag(Tags.Blocks.ORES_EMERALD).addTag(BlockTags.EMERALD_ORES); + tag(Tags.Blocks.ORES_GOLD).addTag(BlockTags.GOLD_ORES); + tag(Tags.Blocks.ORES_IRON).addTag(BlockTags.IRON_ORES); + tag(Tags.Blocks.ORES_LAPIS).addTag(BlockTags.LAPIS_ORES); + tag(Tags.Blocks.ORES_QUARTZ).add(Blocks.NETHER_QUARTZ_ORE); + tag(Tags.Blocks.ORES_REDSTONE).addTag(BlockTags.REDSTONE_ORES); + tag(Tags.Blocks.ORES_NETHERITE_SCRAP).add(Blocks.ANCIENT_DEBRIS); + tag(Tags.Blocks.ORES_IN_GROUND_DEEPSLATE).add(Blocks.DEEPSLATE_COAL_ORE, Blocks.DEEPSLATE_COPPER_ORE, Blocks.DEEPSLATE_DIAMOND_ORE, Blocks.DEEPSLATE_EMERALD_ORE, Blocks.DEEPSLATE_GOLD_ORE, Blocks.DEEPSLATE_IRON_ORE, Blocks.DEEPSLATE_LAPIS_ORE, Blocks.DEEPSLATE_REDSTONE_ORE); + tag(Tags.Blocks.ORES_IN_GROUND_NETHERRACK).add(Blocks.NETHER_GOLD_ORE, Blocks.NETHER_QUARTZ_ORE); + tag(Tags.Blocks.ORES_IN_GROUND_STONE).add(Blocks.COAL_ORE, Blocks.COPPER_ORE, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.GOLD_ORE, Blocks.IRON_ORE, Blocks.LAPIS_ORE, Blocks.REDSTONE_ORE); + tag(Tags.Blocks.PLAYER_WORKSTATIONS_CRAFTING_TABLES).add(Blocks.CRAFTING_TABLE); + tag(Tags.Blocks.PLAYER_WORKSTATIONS_FURNACES).add(Blocks.FURNACE); + tag(Tags.Blocks.SANDS).addTag(Tags.Blocks.SANDS_COLORLESS).addTag(Tags.Blocks.SANDS_RED); + tag(Tags.Blocks.RELOCATION_NOT_SUPPORTED); + tag(Tags.Blocks.ROPES); + tag(Tags.Blocks.SANDS_COLORLESS).add(Blocks.SAND); + tag(Tags.Blocks.SANDS_RED).add(Blocks.RED_SAND); + + tag(Tags.Blocks.SANDSTONE_RED_BLOCKS).add(Blocks.RED_SANDSTONE, Blocks.CUT_RED_SANDSTONE, Blocks.CHISELED_RED_SANDSTONE, Blocks.SMOOTH_RED_SANDSTONE); + tag(Tags.Blocks.SANDSTONE_UNCOLORED_BLOCKS).add(Blocks.SANDSTONE, Blocks.CUT_SANDSTONE, Blocks.CHISELED_SANDSTONE, Blocks.SMOOTH_SANDSTONE); + tag(Tags.Blocks.SANDSTONE_BLOCKS).addTag(Tags.Blocks.SANDSTONE_RED_BLOCKS).addTag(Tags.Blocks.SANDSTONE_UNCOLORED_BLOCKS); + tag(Tags.Blocks.SANDSTONE_RED_SLABS).add(Blocks.RED_SANDSTONE_SLAB, Blocks.CUT_RED_SANDSTONE_SLAB, Blocks.SMOOTH_RED_SANDSTONE_SLAB); + tag(Tags.Blocks.SANDSTONE_UNCOLORED_SLABS).add(Blocks.SANDSTONE_SLAB, Blocks.CUT_SANDSTONE_SLAB, Blocks.SMOOTH_SANDSTONE_SLAB); + tag(Tags.Blocks.SANDSTONE_SLABS).addTag(Tags.Blocks.SANDSTONE_RED_SLABS).addTag(Tags.Blocks.SANDSTONE_UNCOLORED_SLABS); + tag(Tags.Blocks.SANDSTONE_RED_STAIRS).add(Blocks.RED_SANDSTONE_STAIRS, Blocks.SMOOTH_RED_SANDSTONE_STAIRS); + tag(Tags.Blocks.SANDSTONE_UNCOLORED_STAIRS).add(Blocks.SANDSTONE_STAIRS, Blocks.SMOOTH_SANDSTONE_STAIRS); + tag(Tags.Blocks.SANDSTONE_STAIRS).addTag(Tags.Blocks.SANDSTONE_RED_STAIRS).addTag(Tags.Blocks.SANDSTONE_UNCOLORED_STAIRS); + + tag(Tags.Blocks.STONES).add(Blocks.ANDESITE, Blocks.DIORITE, Blocks.GRANITE, Blocks.STONE, Blocks.DEEPSLATE, Blocks.TUFF); + tag(Tags.Blocks.STORAGE_BLOCKS).addTag(Tags.Blocks.STORAGE_BLOCKS_BONE_MEAL).addTag(Tags.Blocks.STORAGE_BLOCKS_COAL) + .addTag(Tags.Blocks.STORAGE_BLOCKS_COPPER).addTag(Tags.Blocks.STORAGE_BLOCKS_DIAMOND).addTag(Tags.Blocks.STORAGE_BLOCKS_DRIED_KELP) + .addTag(Tags.Blocks.STORAGE_BLOCKS_EMERALD).addTag(Tags.Blocks.STORAGE_BLOCKS_GOLD).addTag(Tags.Blocks.STORAGE_BLOCKS_IRON) + .addTag(Tags.Blocks.STORAGE_BLOCKS_LAPIS).addTag(Tags.Blocks.STORAGE_BLOCKS_NETHERITE).addTag(Tags.Blocks.STORAGE_BLOCKS_RAW_COPPER) + .addTag(Tags.Blocks.STORAGE_BLOCKS_RAW_GOLD).addTag(Tags.Blocks.STORAGE_BLOCKS_RAW_IRON).addTag(Tags.Blocks.STORAGE_BLOCKS_REDSTONE) + .addTag(Tags.Blocks.STORAGE_BLOCKS_SLIME).addTag(Tags.Blocks.STORAGE_BLOCKS_WHEAT); + tag(Tags.Blocks.STORAGE_BLOCKS_BONE_MEAL).add(Blocks.BONE_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_COAL).add(Blocks.COAL_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_COPPER).add(Blocks.COPPER_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_DIAMOND).add(Blocks.DIAMOND_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_DRIED_KELP).add(Blocks.DRIED_KELP_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_EMERALD).add(Blocks.EMERALD_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_GOLD).add(Blocks.GOLD_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_IRON).add(Blocks.IRON_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_LAPIS).add(Blocks.LAPIS_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_NETHERITE).add(Blocks.NETHERITE_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_RAW_COPPER).add(Blocks.RAW_COPPER_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_RAW_GOLD).add(Blocks.RAW_GOLD_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_RAW_IRON).add(Blocks.RAW_IRON_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_REDSTONE).add(Blocks.REDSTONE_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_SLIME).add(Blocks.SLIME_BLOCK); + tag(Tags.Blocks.STORAGE_BLOCKS_WHEAT).add(Blocks.HAY_BLOCK); + tag(Tags.Blocks.VILLAGER_JOB_SITES).add( + Blocks.BARREL, Blocks.BLAST_FURNACE, Blocks.BREWING_STAND, Blocks.CARTOGRAPHY_TABLE, + Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, + Blocks.COMPOSTER, Blocks.FLETCHING_TABLE, Blocks.GRINDSTONE, Blocks.LECTERN, + Blocks.LOOM, Blocks.SMITHING_TABLE, Blocks.SMOKER, Blocks.STONECUTTER); + + // Backwards compat with pre-1.21 tags. Done after so optional tag is last for better readability. + // TODO: Remove backwards compat tag entries in 1.22 +// tagWithOptionalLegacy(Tags.Blocks.BARRELS); +// tagWithOptionalLegacy(Tags.Blocks.BARRELS_WOODEN); +// tagWithOptionalLegacy(Tags.Blocks.BOOKSHELVES); +// tagWithOptionalLegacy(Tags.Blocks.CHESTS); +// tagWithOptionalLegacy(Tags.Blocks.CHESTS_ENDER); +// tagWithOptionalLegacy(Tags.Blocks.CHESTS_TRAPPED); +// tagWithOptionalLegacy(Tags.Blocks.CHESTS_WOODEN); + tag(Tags.Blocks.COBBLESTONES).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "cobblestone")); + tag(Tags.Blocks.COBBLESTONES_NORMAL).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "cobblestone/normal")); + tag(Tags.Blocks.COBBLESTONES_INFESTED).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "cobblestone/infested")); + tag(Tags.Blocks.COBBLESTONES_MOSSY).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "cobblestone/mossy")); + tag(Tags.Blocks.COBBLESTONES_DEEPSLATE).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "cobblestone/deepslate")); + tag(Tags.Blocks.DYED_BLACK) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/black")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/black")); + tag(Tags.Blocks.DYED_BLUE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/blue")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/blue")); + tag(Tags.Blocks.DYED_BROWN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/brown")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/brown")); + tag(Tags.Blocks.DYED_CYAN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/cyan")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/cyan")); + tag(Tags.Blocks.DYED_GRAY) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/gray")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/gray")); + tag(Tags.Blocks.DYED_GREEN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/green")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/green")); + tag(Tags.Blocks.DYED_LIGHT_BLUE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/light_blue")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/light_blue")); + tag(Tags.Blocks.DYED_LIGHT_GRAY) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/light_gray")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/light_gray")); + tag(Tags.Blocks.DYED_LIME) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/lime")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/lime")); + tag(Tags.Blocks.DYED_MAGENTA) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/magenta")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/magenta")); + tag(Tags.Blocks.DYED_MAGENTA) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/magenta")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/magenta")); + tag(Tags.Blocks.DYED_ORANGE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/orange")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/orange")); + tag(Tags.Blocks.DYED_PINK) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/pink")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/pink")); + tag(Tags.Blocks.DYED_PURPLE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/purple")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/purple")); + tag(Tags.Blocks.DYED_RED) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/red")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/red")); + tag(Tags.Blocks.DYED_WHITE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/white")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/white")); + tag(Tags.Blocks.DYED_YELLOW) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/yellow")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/yellow")); +// tagWithOptionalLegacy(Tags.Blocks.END_STONES); +// tagWithOptionalLegacy(Tags.Blocks.ENDERMAN_PLACE_ON_BLACKLIST); +// tagWithOptionalLegacy(Tags.Blocks.FENCE_GATES); +// tagWithOptionalLegacy(Tags.Blocks.FENCE_GATES_WOODEN); +// tagWithOptionalLegacy(Tags.Blocks.FENCES); +// tagWithOptionalLegacy(Tags.Blocks.FENCES_NETHER_BRICK); +// tagWithOptionalLegacy(Tags.Blocks.FENCES_WOODEN); + tag(Tags.Blocks.GRAVELS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "gravel")); + tag(Tags.Blocks.GLASS_BLOCKS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass")); + tag(Tags.Blocks.GLASS_BLOCKS_COLORLESS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass_colorless")); + tag(Tags.Blocks.GLASS_BLOCKS_CHEAP).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass_silica")); + tag(Tags.Blocks.GLASS_BLOCKS_TINTED).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass_tinted")); + tag(Tags.Blocks.GLASS_PANES_COLORLESS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass_panes_colorless")); + tag(Tags.Blocks.NETHERRACKS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "netherrack")); + tag(Tags.Blocks.OBSIDIANS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "obsidian")); +// tagWithOptionalLegacy(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE); +// tagWithOptionalLegacy(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK); +// tagWithOptionalLegacy(Tags.Blocks.ORE_BEARING_GROUND_STONE); +// tagWithOptionalLegacy(Tags.Blocks.ORE_RATES_DENSE); +// tagWithOptionalLegacy(Tags.Blocks.ORE_RATES_SINGULAR); +// tagWithOptionalLegacy(Tags.Blocks.ORE_RATES_SPARSE); +// tagWithOptionalLegacy(Tags.Blocks.ORES); +// tagWithOptionalLegacy(Tags.Blocks.ORES_COAL); +// tagWithOptionalLegacy(Tags.Blocks.ORES_COPPER); +// tagWithOptionalLegacy(Tags.Blocks.ORES_DIAMOND); +// tagWithOptionalLegacy(Tags.Blocks.ORES_EMERALD); +// tagWithOptionalLegacy(Tags.Blocks.ORES_GOLD); +// tagWithOptionalLegacy(Tags.Blocks.ORES_IRON); +// tagWithOptionalLegacy(Tags.Blocks.ORES_LAPIS); +// tagWithOptionalLegacy(Tags.Blocks.ORES_QUARTZ); +// tagWithOptionalLegacy(Tags.Blocks.ORES_REDSTONE); +// tagWithOptionalLegacy(Tags.Blocks.ORES_NETHERITE_SCRAP); +// tagWithOptionalLegacy(Tags.Blocks.ORES_IN_GROUND_DEEPSLATE); +// tagWithOptionalLegacy(Tags.Blocks.ORES_IN_GROUND_NETHERRACK); +// tagWithOptionalLegacy(Tags.Blocks.ORES_IN_GROUND_STONE); + tag(Tags.Blocks.STONES).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stone")); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_COAL); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_COPPER); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_DIAMOND); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_EMERALD); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_GOLD); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_IRON); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_LAPIS); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_RAW_COPPER); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_RAW_GOLD); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_RAW_IRON); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_REDSTONE); +// tagWithOptionalLegacy(Tags.Blocks.STORAGE_BLOCKS_NETHERITE); + tag(Tags.Blocks.RELOCATION_NOT_SUPPORTED) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "relocation_not_supported")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "immovable")); + tag(Tags.Blocks.SANDSTONE_BLOCKS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "sandstone")); + tag(Tags.Blocks.SANDS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "sand")); + tag(Tags.Blocks.SANDS_COLORLESS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "sand/colorless")); + tag(Tags.Blocks.SANDS_RED).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "sand/red")); } - private void addColored(Consumer consumer, TagKey group, String pattern) { +// private FabricTagBuilder tagWithOptionalLegacy(TagKey tag) { +// FabricTagBuilder tagAppender = tag(tag); +// tagAppender.addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", tag.location().getPath())); +// return tagAppender; +// } + + private void addColored(TagKey group, String pattern) { String prefix = group.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; for (DyeColor color : DyeColor.values()) { - ResourceLocation key = new ResourceLocation("minecraft", pattern.replace("{color}", color.getName())); + ResourceLocation key = ResourceLocation.fromNamespaceAndPath("minecraft", pattern.replace("{color}", color.getName())); TagKey tag = getForgeTag(prefix + color.getName()); Block block = BuiltInRegistries.BLOCK.get(key); if (block == null || block == Blocks.AIR) - throw new IllegalStateException("Unknown vanilla block: " + key.toString()); + throw new IllegalStateException("Unknown vanilla block: " + key); tag(tag).add(block); - consumer.accept(block); + } + } + + private void addColoredTags(Consumer> consumer, TagKey group) { + String prefix = group.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; + for (DyeColor color : DyeColor.values()) { + TagKey tag = getForgeTag(prefix + color.getName()); + consumer.accept(tag); } } @SuppressWarnings("unchecked") private TagKey getForgeTag(String name) { try { - name = name.toUpperCase(Locale.ENGLISH).replace("_BLOCKS", ""); + name = name.toUpperCase(Locale.ENGLISH); return (TagKey) Tags.Blocks.class.getDeclaredField(name).get(null); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { throw new IllegalStateException(Tags.Blocks.class.getName() + " is missing tag name: " + name); } } - public FabricTagBuilder tag(TagKey tag) { return getOrCreateTagBuilder(tag); } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/DataGenerators.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/DataGenerators.java index 2b7912ede..9c02ce8e0 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/DataGenerators.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/DataGenerators.java @@ -4,6 +4,9 @@ import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.minecraft.core.HolderLookup; + +import java.util.concurrent.CompletableFuture; public class DataGenerators implements DataGeneratorEntrypoint { @Override @@ -17,7 +20,7 @@ public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { pack.addProvider(DataGenerators::itemTagLang); } - private static ItemTagLangProvider itemTagLang(FabricDataOutput output) { - return new ItemTagLangProvider(output, Tags.Items.class); + private static ItemTagLangProvider itemTagLang(FabricDataOutput output, CompletableFuture registryLookup) { + return new ItemTagLangProvider(output, registryLookup, Tags.Items.class); } } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagLangProvider.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagLangProvider.java index c8a2b7029..e2ce171d9 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagLangProvider.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagLangProvider.java @@ -2,6 +2,7 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider; +import net.minecraft.core.HolderLookup; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; @@ -12,6 +13,7 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** @@ -23,18 +25,18 @@ public class ItemTagLangProvider extends FabricLanguageProvider { private final Class tagClass; private final Map, String> specialCases; - public ItemTagLangProvider(FabricDataOutput output, Class tagClass) { - this(output, tagClass, Map.of()); + public ItemTagLangProvider(FabricDataOutput output, CompletableFuture registryLookup, Class tagClass) { + this(output, registryLookup, tagClass, Map.of()); } - public ItemTagLangProvider(FabricDataOutput output, Class tagClass, Map, String> specialCases) { - super(output); + public ItemTagLangProvider(FabricDataOutput output, CompletableFuture registryLookup, Class tagClass, Map, String> specialCases) { + super(output, registryLookup); this.tagClass = tagClass; this.specialCases = specialCases; } @Override - public void generateTranslations(TranslationBuilder translationBuilder) { + public void generateTranslations(HolderLookup.Provider registryLookup, TranslationBuilder translationBuilder) { for (Field field : tagClass.getDeclaredFields()) { field.setAccessible(true); try { diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagProvider.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagProvider.java index a670e78fe..45df1edd8 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagProvider.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/data/ItemTagProvider.java @@ -10,43 +10,80 @@ import net.minecraft.core.HolderLookup; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; -public class ItemTagProvider extends FabricTagProvider.ItemTagProvider { - public ItemTagProvider(FabricDataOutput output, CompletableFuture registriesFuture, BlockTagProvider blockTags) { - super(output, registriesFuture, blockTags); +public final class ItemTagProvider extends FabricTagProvider.ItemTagProvider { + public ItemTagProvider(FabricDataOutput output, CompletableFuture lookupProvider, FabricTagProvider.BlockTagProvider blockTagProvider) { + super(output, lookupProvider, blockTagProvider); } + @SuppressWarnings("unchecked") @Override - protected void addTags(HolderLookup.Provider arg) { + public void addTags(HolderLookup.Provider lookupProvider) { copy(Tags.Blocks.BARRELS, Tags.Items.BARRELS); copy(Tags.Blocks.BARRELS_WOODEN, Tags.Items.BARRELS_WOODEN); tag(Tags.Items.BONES).add(Items.BONE); copy(Tags.Blocks.BOOKSHELVES, Tags.Items.BOOKSHELVES); + tag(Tags.Items.BRICKS).addTag(Tags.Items.BRICKS_NORMAL).addTag(Tags.Items.BRICKS_NETHER); + tag(Tags.Items.BRICKS_NORMAL).add(Items.BRICK); + tag(Tags.Items.BRICKS_NETHER).add(Items.NETHER_BRICK); + tag(Tags.Items.BUCKETS_EMPTY).add(Items.BUCKET); + tag(Tags.Items.BUCKETS_WATER).add(Items.WATER_BUCKET); + tag(Tags.Items.BUCKETS_LAVA).add(Items.LAVA_BUCKET); + tag(Tags.Items.BUCKETS_MILK).add(Items.MILK_BUCKET); + tag(Tags.Items.BUCKETS_POWDER_SNOW).add(Items.POWDER_SNOW_BUCKET); + tag(Tags.Items.BUCKETS_ENTITY_WATER).add(Items.AXOLOTL_BUCKET, Items.COD_BUCKET, Items.PUFFERFISH_BUCKET, Items.TADPOLE_BUCKET, Items.TROPICAL_FISH_BUCKET, Items.SALMON_BUCKET); + tag(Tags.Items.BUCKETS).addTag(Tags.Items.BUCKETS_EMPTY).addTag(Tags.Items.BUCKETS_WATER).addTag(Tags.Items.BUCKETS_LAVA).addTag(Tags.Items.BUCKETS_MILK).addTag(Tags.Items.BUCKETS_POWDER_SNOW).addTag(Tags.Items.BUCKETS_ENTITY_WATER); + copy(Tags.Blocks.BUDDING_BLOCKS, Tags.Items.BUDDING_BLOCKS); + copy(Tags.Blocks.BUDS, Tags.Items.BUDS); + copy(Tags.Blocks.CHAINS, Tags.Items.CHAINS); copy(Tags.Blocks.CHESTS, Tags.Items.CHESTS); copy(Tags.Blocks.CHESTS_ENDER, Tags.Items.CHESTS_ENDER); copy(Tags.Blocks.CHESTS_TRAPPED, Tags.Items.CHESTS_TRAPPED); copy(Tags.Blocks.CHESTS_WOODEN, Tags.Items.CHESTS_WOODEN); - copy(Tags.Blocks.COBBLESTONE, Tags.Items.COBBLESTONE); - copy(Tags.Blocks.COBBLESTONE_NORMAL, Tags.Items.COBBLESTONE_NORMAL); - copy(Tags.Blocks.COBBLESTONE_INFESTED, Tags.Items.COBBLESTONE_INFESTED); - copy(Tags.Blocks.COBBLESTONE_MOSSY, Tags.Items.COBBLESTONE_MOSSY); - copy(Tags.Blocks.COBBLESTONE_DEEPSLATE, Tags.Items.COBBLESTONE_DEEPSLATE); + copy(Tags.Blocks.CLUSTERS, Tags.Items.CLUSTERS); + copy(Tags.Blocks.COBBLESTONES, Tags.Items.COBBLESTONES); + copy(Tags.Blocks.COBBLESTONES_NORMAL, Tags.Items.COBBLESTONES_NORMAL); + copy(Tags.Blocks.COBBLESTONES_INFESTED, Tags.Items.COBBLESTONES_INFESTED); + copy(Tags.Blocks.COBBLESTONES_MOSSY, Tags.Items.COBBLESTONES_MOSSY); + copy(Tags.Blocks.COBBLESTONES_DEEPSLATE, Tags.Items.COBBLESTONES_DEEPSLATE); + copy(Tags.Blocks.CONCRETES, Tags.Items.CONCRETES); + tag(Tags.Items.CONCRETE_POWDERS) + .add(Items.WHITE_CONCRETE_POWDER).add(Items.ORANGE_CONCRETE_POWDER).add(Items.MAGENTA_CONCRETE_POWDER) + .add(Items.LIGHT_BLUE_CONCRETE_POWDER).add(Items.YELLOW_CONCRETE_POWDER).add(Items.LIME_CONCRETE_POWDER) + .add(Items.PINK_CONCRETE_POWDER).add(Items.GRAY_CONCRETE_POWDER).add(Items.LIGHT_GRAY_CONCRETE_POWDER) + .add(Items.CYAN_CONCRETE_POWDER).add(Items.PURPLE_CONCRETE_POWDER).add(Items.BLUE_CONCRETE_POWDER) + .add(Items.BROWN_CONCRETE_POWDER).add(Items.GREEN_CONCRETE_POWDER).add(Items.RED_CONCRETE_POWDER) + .add(Items.BLACK_CONCRETE_POWDER); tag(Tags.Items.CROPS).addTag(Tags.Items.CROPS_BEETROOT).addTag(Tags.Items.CROPS_CARROT).addTag(Tags.Items.CROPS_NETHER_WART).addTag(Tags.Items.CROPS_POTATO).addTag(Tags.Items.CROPS_WHEAT); tag(Tags.Items.CROPS_BEETROOT).add(Items.BEETROOT); tag(Tags.Items.CROPS_CARROT).add(Items.CARROT); tag(Tags.Items.CROPS_NETHER_WART).add(Items.NETHER_WART); tag(Tags.Items.CROPS_POTATO).add(Items.POTATO); tag(Tags.Items.CROPS_WHEAT).add(Items.WHEAT); - tag(Tags.Items.DUSTS).addTag(Tags.Items.DUSTS_GLOWSTONE).addTag(Tags.Items.DUSTS_PRISMARINE).addTag(Tags.Items.DUSTS_REDSTONE); + addColored(Tags.Items.DYED, "{color}_banner"); + addColored(Tags.Items.DYED, "{color}_bed"); + addColored(Tags.Items.DYED, "{color}_candle"); + addColored(Tags.Items.DYED, "{color}_carpet"); + addColored(Tags.Items.DYED, "{color}_concrete"); + addColored(Tags.Items.DYED, "{color}_concrete_powder"); + addColored(Tags.Items.DYED, "{color}_glazed_terracotta"); + addColored(Tags.Items.DYED, "{color}_shulker_box"); + addColored(Tags.Items.DYED, "{color}_stained_glass"); + addColored(Tags.Items.DYED, "{color}_stained_glass_pane"); + addColored(Tags.Items.DYED, "{color}_terracotta"); + addColored(Tags.Items.DYED, "{color}_wool"); + addColoredTags(tag(Tags.Items.DYED)::addTag, Tags.Items.DYED); + tag(Tags.Items.DUSTS).addTag(Tags.Items.DUSTS_GLOWSTONE).addTag(Tags.Items.DUSTS_REDSTONE); tag(Tags.Items.DUSTS_GLOWSTONE).add(Items.GLOWSTONE_DUST); - tag(Tags.Items.DUSTS_PRISMARINE).add(Items.PRISMARINE_SHARD); tag(Tags.Items.DUSTS_REDSTONE).add(Items.REDSTONE); - addColored(tag(Tags.Items.DYES)::addTag, Tags.Items.DYES, "{color}_dye"); + addColored(Tags.Items.DYES, "{color}_dye"); + addColoredTags(tag(Tags.Items.DYES)::addTag, Tags.Items.DYES); tag(Tags.Items.EGGS).add(Items.EGG); tag(Tags.Items.ENCHANTING_FUELS).addTag(Tags.Items.GEMS_LAPIS); copy(Tags.Blocks.END_STONES, Tags.Items.END_STONES); @@ -57,6 +94,25 @@ protected void addTags(HolderLookup.Provider arg) { copy(Tags.Blocks.FENCES, Tags.Items.FENCES); copy(Tags.Blocks.FENCES_NETHER_BRICK, Tags.Items.FENCES_NETHER_BRICK); copy(Tags.Blocks.FENCES_WOODEN, Tags.Items.FENCES_WOODEN); + tag(Tags.Items.FOODS_FRUITS).add(Items.APPLE, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE); + tag(Tags.Items.FOODS_VEGETABLES).add(Items.CARROT, Items.GOLDEN_CARROT, Items.POTATO, Items.MELON_SLICE, Items.BEETROOT); + tag(Tags.Items.FOODS_BERRIES).add(Items.SWEET_BERRIES, Items.GLOW_BERRIES); + tag(Tags.Items.FOODS_BREADS).add(Items.BREAD); + tag(Tags.Items.FOODS_COOKIES).add(Items.COOKIE); + tag(Tags.Items.FOODS_RAW_MEATS).add(Items.BEEF, Items.PORKCHOP, Items.CHICKEN, Items.RABBIT, Items.MUTTON); + tag(Tags.Items.FOODS_RAW_FISHES).add(Items.COD, Items.SALMON, Items.TROPICAL_FISH, Items.PUFFERFISH); + tag(Tags.Items.FOODS_COOKED_MEATS).add(Items.COOKED_BEEF, Items.COOKED_PORKCHOP, Items.COOKED_CHICKEN, Items.COOKED_RABBIT, Items.COOKED_MUTTON); + tag(Tags.Items.FOODS_COOKED_FISHES).add(Items.COOKED_COD, Items.COOKED_SALMON); + tag(Tags.Items.FOODS_SOUPS).add(Items.BEETROOT_SOUP, Items.MUSHROOM_STEW, Items.RABBIT_STEW, Items.SUSPICIOUS_STEW); + tag(Tags.Items.FOODS_CANDIES); + tag(Tags.Items.FOODS_EDIBLE_WHEN_PLACED).add(Items.CAKE); + tag(Tags.Items.FOODS_FOOD_POISONING).add(Items.POISONOUS_POTATO, Items.PUFFERFISH, Items.SPIDER_EYE, Items.CHICKEN, Items.ROTTEN_FLESH); + tag(Tags.Items.FOODS) + .add(Items.BAKED_POTATO, Items.PUMPKIN_PIE, Items.HONEY_BOTTLE, Items.OMINOUS_BOTTLE, Items.DRIED_KELP) + .addTag(Tags.Items.FOODS_FRUITS).addTag(Tags.Items.FOODS_VEGETABLES).addTag(Tags.Items.FOODS_BERRIES).addTag(Tags.Items.FOODS_BREADS).addTag(Tags.Items.FOODS_COOKIES) + .addTag(Tags.Items.FOODS_RAW_MEATS).addTag(Tags.Items.FOODS_RAW_FISHES).addTag(Tags.Items.FOODS_COOKED_MEATS).addTag(Tags.Items.FOODS_COOKED_FISHES) + .addTag(Tags.Items.FOODS_SOUPS).addTag(Tags.Items.FOODS_CANDIES) + .addTag(Tags.Items.FOODS_EDIBLE_WHEN_PLACED).addTag(Tags.Items.FOODS_FOOD_POISONING); tag(Tags.Items.GEMS).addTag(Tags.Items.GEMS_AMETHYST).addTag(Tags.Items.GEMS_DIAMOND).addTag(Tags.Items.GEMS_EMERALD).addTag(Tags.Items.GEMS_LAPIS).addTag(Tags.Items.GEMS_PRISMARINE).addTag(Tags.Items.GEMS_QUARTZ); tag(Tags.Items.GEMS_AMETHYST).add(Items.AMETHYST_SHARD); tag(Tags.Items.GEMS_DIAMOND).add(Items.DIAMOND); @@ -64,30 +120,34 @@ protected void addTags(HolderLookup.Provider arg) { tag(Tags.Items.GEMS_LAPIS).add(Items.LAPIS_LAZULI); tag(Tags.Items.GEMS_PRISMARINE).add(Items.PRISMARINE_CRYSTALS); tag(Tags.Items.GEMS_QUARTZ).add(Items.QUARTZ); - copy(Tags.Blocks.GLASS, Tags.Items.GLASS); - copy(Tags.Blocks.GLASS_TINTED, Tags.Items.GLASS_TINTED); - copy(Tags.Blocks.GLASS_SILICA, Tags.Items.GLASS_SILICA); - copyColored(Tags.Blocks.GLASS, Tags.Items.GLASS); + copy(Tags.Blocks.GLASS_BLOCKS, Tags.Items.GLASS_BLOCKS); + copy(Tags.Blocks.GLASS_BLOCKS_COLORLESS, Tags.Items.GLASS_BLOCKS_COLORLESS); + copy(Tags.Blocks.GLASS_BLOCKS_TINTED, Tags.Items.GLASS_BLOCKS_TINTED); + copy(Tags.Blocks.GLASS_BLOCKS_CHEAP, Tags.Items.GLASS_BLOCKS_CHEAP); copy(Tags.Blocks.GLASS_PANES, Tags.Items.GLASS_PANES); - copyColored(Tags.Blocks.GLASS_PANES, Tags.Items.GLASS_PANES); - copy(Tags.Blocks.GRAVEL, Tags.Items.GRAVEL); - tag(Tags.Items.GUNPOWDER).add(Items.GUNPOWDER); - tag(Tags.Items.HEADS).add(Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PLAYER_HEAD, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, Items.ZOMBIE_HEAD); - tag(Tags.Items.INGOTS).addTag(Tags.Items.INGOTS_BRICK).addTag(Tags.Items.INGOTS_COPPER).addTag(Tags.Items.INGOTS_GOLD).addTag(Tags.Items.INGOTS_IRON).addTag(Tags.Items.INGOTS_NETHERITE).addTag(Tags.Items.INGOTS_NETHER_BRICK); - tag(Tags.Items.INGOTS_BRICK).add(Items.BRICK); + copy(Tags.Blocks.GLASS_PANES_COLORLESS, Tags.Items.GLASS_PANES_COLORLESS); + copy(Tags.Blocks.GLAZED_TERRACOTTAS, Tags.Items.GLAZED_TERRACOTTAS); + copy(Tags.Blocks.GRAVELS, Tags.Items.GRAVELS); + tag(Tags.Items.GUNPOWDERS).add(Items.GUNPOWDER); + tag(Tags.Items.HIDDEN_FROM_RECIPE_VIEWERS); + tag(Tags.Items.INGOTS).addTag(Tags.Items.INGOTS_COPPER).addTag(Tags.Items.INGOTS_GOLD).addTag(Tags.Items.INGOTS_IRON).addTag(Tags.Items.INGOTS_NETHERITE); tag(Tags.Items.INGOTS_COPPER).add(Items.COPPER_INGOT); tag(Tags.Items.INGOTS_GOLD).add(Items.GOLD_INGOT); tag(Tags.Items.INGOTS_IRON).add(Items.IRON_INGOT); tag(Tags.Items.INGOTS_NETHERITE).add(Items.NETHERITE_INGOT); - tag(Tags.Items.INGOTS_NETHER_BRICK).add(Items.NETHER_BRICK); - tag(Tags.Items.LEATHER).add(Items.LEATHER); + tag(Tags.Items.LEATHERS).add(Items.LEATHER); tag(Tags.Items.MUSHROOMS).add(Items.BROWN_MUSHROOM, Items.RED_MUSHROOM); + tag(Tags.Items.MUSIC_DISCS).add(Items.MUSIC_DISC_13, Items.MUSIC_DISC_CAT, Items.MUSIC_DISC_BLOCKS, Items.MUSIC_DISC_CHIRP, + Items.MUSIC_DISC_FAR, Items.MUSIC_DISC_MALL, Items.MUSIC_DISC_MELLOHI, Items.MUSIC_DISC_STAL, Items.MUSIC_DISC_STRAD, + Items.MUSIC_DISC_WARD, Items.MUSIC_DISC_11, Items.MUSIC_DISC_WAIT, Items.MUSIC_DISC_OTHERSIDE, Items.MUSIC_DISC_5, + Items.MUSIC_DISC_PIGSTEP, Items.MUSIC_DISC_RELIC, Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, + Items.MUSIC_DISC_PRECIPICE); tag(Tags.Items.NETHER_STARS).add(Items.NETHER_STAR); - copy(Tags.Blocks.NETHERRACK, Tags.Items.NETHERRACK); - tag(Tags.Items.NUGGETS).addTag(Tags.Items.NUGGETS_IRON).addTag(Tags.Items.NUGGETS_GOLD); + copy(Tags.Blocks.NETHERRACKS, Tags.Items.NETHERRACKS); + tag(Tags.Items.NUGGETS).addTag(Tags.Items.NUGGETS_GOLD).addTag(Tags.Items.NUGGETS_IRON); tag(Tags.Items.NUGGETS_IRON).add(Items.IRON_NUGGET); tag(Tags.Items.NUGGETS_GOLD).add(Items.GOLD_NUGGET); - copy(Tags.Blocks.OBSIDIAN, Tags.Items.OBSIDIAN); + copy(Tags.Blocks.OBSIDIANS, Tags.Items.OBSIDIANS); copy(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE, Tags.Items.ORE_BEARING_GROUND_DEEPSLATE); copy(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK, Tags.Items.ORE_BEARING_GROUND_NETHERRACK); copy(Tags.Blocks.ORE_BEARING_GROUND_STONE, Tags.Items.ORE_BEARING_GROUND_STONE); @@ -108,89 +168,239 @@ protected void addTags(HolderLookup.Provider arg) { copy(Tags.Blocks.ORES_IN_GROUND_DEEPSLATE, Tags.Items.ORES_IN_GROUND_DEEPSLATE); copy(Tags.Blocks.ORES_IN_GROUND_NETHERRACK, Tags.Items.ORES_IN_GROUND_NETHERRACK); copy(Tags.Blocks.ORES_IN_GROUND_STONE, Tags.Items.ORES_IN_GROUND_STONE); + copy(Tags.Blocks.PLAYER_WORKSTATIONS_CRAFTING_TABLES, Tags.Items.PLAYER_WORKSTATIONS_CRAFTING_TABLES); + copy(Tags.Blocks.PLAYER_WORKSTATIONS_FURNACES, Tags.Items.PLAYER_WORKSTATIONS_FURNACES); tag(Tags.Items.RAW_MATERIALS).addTag(Tags.Items.RAW_MATERIALS_COPPER).addTag(Tags.Items.RAW_MATERIALS_GOLD).addTag(Tags.Items.RAW_MATERIALS_IRON); tag(Tags.Items.RAW_MATERIALS_COPPER).add(Items.RAW_COPPER); tag(Tags.Items.RAW_MATERIALS_GOLD).add(Items.RAW_GOLD); tag(Tags.Items.RAW_MATERIALS_IRON).add(Items.RAW_IRON); - tag(Tags.Items.RODS).addTag(Tags.Items.RODS_BLAZE).addTag(Tags.Items.RODS_WOODEN); + tag(Tags.Items.RODS).addTag(Tags.Items.RODS_WOODEN).addTag(Tags.Items.RODS_BLAZE).addTag(Tags.Items.RODS_BREEZE); tag(Tags.Items.RODS_BLAZE).add(Items.BLAZE_ROD); + tag(Tags.Items.RODS_BREEZE).add(Items.BREEZE_ROD); tag(Tags.Items.RODS_WOODEN).add(Items.STICK); - copy(Tags.Blocks.SAND, Tags.Items.SAND); - copy(Tags.Blocks.SAND_COLORLESS, Tags.Items.SAND_COLORLESS); - copy(Tags.Blocks.SAND_RED, Tags.Items.SAND_RED); - copy(Tags.Blocks.SANDSTONE, Tags.Items.SANDSTONE); + copy(Tags.Blocks.ROPES, Tags.Items.ROPES); + copy(Tags.Blocks.SANDS, Tags.Items.SANDS); + copy(Tags.Blocks.SANDS_COLORLESS, Tags.Items.SANDS_COLORLESS); + copy(Tags.Blocks.SANDS_RED, Tags.Items.SANDS_RED); + copy(Tags.Blocks.SANDSTONE_BLOCKS, Tags.Items.SANDSTONE_BLOCKS); + copy(Tags.Blocks.SANDSTONE_SLABS, Tags.Items.SANDSTONE_SLABS); + copy(Tags.Blocks.SANDSTONE_STAIRS, Tags.Items.SANDSTONE_STAIRS); + copy(Tags.Blocks.SANDSTONE_RED_BLOCKS, Tags.Items.SANDSTONE_RED_BLOCKS); + copy(Tags.Blocks.SANDSTONE_RED_SLABS, Tags.Items.SANDSTONE_RED_SLABS); + copy(Tags.Blocks.SANDSTONE_RED_STAIRS, Tags.Items.SANDSTONE_RED_STAIRS); + copy(Tags.Blocks.SANDSTONE_UNCOLORED_BLOCKS, Tags.Items.SANDSTONE_UNCOLORED_BLOCKS); + copy(Tags.Blocks.SANDSTONE_UNCOLORED_SLABS, Tags.Items.SANDSTONE_UNCOLORED_SLABS); + copy(Tags.Blocks.SANDSTONE_UNCOLORED_STAIRS, Tags.Items.SANDSTONE_UNCOLORED_STAIRS); tag(Tags.Items.SEEDS).addTag(Tags.Items.SEEDS_BEETROOT).addTag(Tags.Items.SEEDS_MELON).addTag(Tags.Items.SEEDS_PUMPKIN).addTag(Tags.Items.SEEDS_WHEAT); tag(Tags.Items.SEEDS_BEETROOT).add(Items.BEETROOT_SEEDS); tag(Tags.Items.SEEDS_MELON).add(Items.MELON_SEEDS); tag(Tags.Items.SEEDS_PUMPKIN).add(Items.PUMPKIN_SEEDS); tag(Tags.Items.SEEDS_WHEAT).add(Items.WHEAT_SEEDS); - tag(Tags.Items.SHEARS).add(Items.SHEARS); tag(Tags.Items.SLIMEBALLS).add(Items.SLIME_BALL); - copy(Tags.Blocks.STAINED_GLASS, Tags.Items.STAINED_GLASS); - copy(Tags.Blocks.STAINED_GLASS_PANES, Tags.Items.STAINED_GLASS_PANES); - copy(Tags.Blocks.STONE, Tags.Items.STONE); + tag(Tags.Items.SHULKER_BOXES) + .add(Items.SHULKER_BOX).add(Items.WHITE_SHULKER_BOX).add(Items.ORANGE_SHULKER_BOX) + .add(Items.MAGENTA_SHULKER_BOX).add(Items.LIGHT_BLUE_SHULKER_BOX).add(Items.YELLOW_SHULKER_BOX) + .add(Items.LIME_SHULKER_BOX).add(Items.PINK_SHULKER_BOX).add(Items.GRAY_SHULKER_BOX) + .add(Items.LIGHT_GRAY_SHULKER_BOX).add(Items.CYAN_SHULKER_BOX).add(Items.PURPLE_SHULKER_BOX) + .add(Items.BLUE_SHULKER_BOX).add(Items.BROWN_SHULKER_BOX).add(Items.GREEN_SHULKER_BOX) + .add(Items.RED_SHULKER_BOX).add(Items.BLACK_SHULKER_BOX); + copy(Tags.Blocks.STONES, Tags.Items.STONES); copy(Tags.Blocks.STORAGE_BLOCKS, Tags.Items.STORAGE_BLOCKS); - copy(Tags.Blocks.STORAGE_BLOCKS_AMETHYST, Tags.Items.STORAGE_BLOCKS_AMETHYST); + copy(Tags.Blocks.STORAGE_BLOCKS_BONE_MEAL, Tags.Items.STORAGE_BLOCKS_BONE_MEAL); copy(Tags.Blocks.STORAGE_BLOCKS_COAL, Tags.Items.STORAGE_BLOCKS_COAL); copy(Tags.Blocks.STORAGE_BLOCKS_COPPER, Tags.Items.STORAGE_BLOCKS_COPPER); copy(Tags.Blocks.STORAGE_BLOCKS_DIAMOND, Tags.Items.STORAGE_BLOCKS_DIAMOND); + copy(Tags.Blocks.STORAGE_BLOCKS_DRIED_KELP, Tags.Items.STORAGE_BLOCKS_DRIED_KELP); copy(Tags.Blocks.STORAGE_BLOCKS_EMERALD, Tags.Items.STORAGE_BLOCKS_EMERALD); copy(Tags.Blocks.STORAGE_BLOCKS_GOLD, Tags.Items.STORAGE_BLOCKS_GOLD); copy(Tags.Blocks.STORAGE_BLOCKS_IRON, Tags.Items.STORAGE_BLOCKS_IRON); copy(Tags.Blocks.STORAGE_BLOCKS_LAPIS, Tags.Items.STORAGE_BLOCKS_LAPIS); - copy(Tags.Blocks.STORAGE_BLOCKS_QUARTZ, Tags.Items.STORAGE_BLOCKS_QUARTZ); - copy(Tags.Blocks.STORAGE_BLOCKS_REDSTONE, Tags.Items.STORAGE_BLOCKS_REDSTONE); + copy(Tags.Blocks.STORAGE_BLOCKS_NETHERITE, Tags.Items.STORAGE_BLOCKS_NETHERITE); copy(Tags.Blocks.STORAGE_BLOCKS_RAW_COPPER, Tags.Items.STORAGE_BLOCKS_RAW_COPPER); copy(Tags.Blocks.STORAGE_BLOCKS_RAW_GOLD, Tags.Items.STORAGE_BLOCKS_RAW_GOLD); copy(Tags.Blocks.STORAGE_BLOCKS_RAW_IRON, Tags.Items.STORAGE_BLOCKS_RAW_IRON); - copy(Tags.Blocks.STORAGE_BLOCKS_NETHERITE, Tags.Items.STORAGE_BLOCKS_NETHERITE); - tag(Tags.Items.STRING).add(Items.STRING); - tag(Tags.Items.TOOLS_SWORDS).add(Items.WOODEN_SWORD, Items.STONE_SWORD, Items.IRON_SWORD, Items.GOLDEN_SWORD, Items.DIAMOND_SWORD, Items.NETHERITE_SWORD); - tag(Tags.Items.TOOLS_AXES).add(Items.WOODEN_AXE, Items.STONE_AXE, Items.IRON_AXE, Items.GOLDEN_AXE, Items.DIAMOND_AXE, Items.NETHERITE_AXE); - tag(Tags.Items.TOOLS_PICKAXES).add(Items.WOODEN_PICKAXE, Items.STONE_PICKAXE, Items.IRON_PICKAXE, Items.GOLDEN_PICKAXE, Items.DIAMOND_PICKAXE, Items.NETHERITE_PICKAXE); - tag(Tags.Items.TOOLS_SHOVELS).add(Items.WOODEN_SHOVEL, Items.STONE_SHOVEL, Items.IRON_SHOVEL, Items.GOLDEN_SHOVEL, Items.DIAMOND_SHOVEL, Items.NETHERITE_SHOVEL); - tag(Tags.Items.TOOLS_HOES).add(Items.WOODEN_HOE, Items.STONE_HOE, Items.IRON_HOE, Items.GOLDEN_HOE, Items.DIAMOND_HOE, Items.NETHERITE_HOE); - tag(Tags.Items.TOOLS_SHIELDS).add(Items.SHIELD); - tag(Tags.Items.TOOLS_BOWS).add(Items.BOW); - tag(Tags.Items.TOOLS_CROSSBOWS).add(Items.CROSSBOW); - tag(Tags.Items.TOOLS_FISHING_RODS).add(Items.FISHING_ROD); - tag(Tags.Items.TOOLS_TRIDENTS).add(Items.TRIDENT); - tag(Tags.Items.TOOLS).addTag(Tags.Items.TOOLS_SWORDS).addTag(Tags.Items.TOOLS_AXES).addTag(Tags.Items.TOOLS_PICKAXES).addTag(Tags.Items.TOOLS_SHOVELS).addTag(Tags.Items.TOOLS_HOES).addTag(Tags.Items.TOOLS_SHIELDS).addTag(Tags.Items.TOOLS_BOWS).addTag(Tags.Items.TOOLS_CROSSBOWS).addTag(Tags.Items.TOOLS_FISHING_RODS).addTag(Tags.Items.TOOLS_TRIDENTS); - tag(Tags.Items.ARMORS_HELMETS).add(Items.LEATHER_HELMET, Items.TURTLE_HELMET, Items.CHAINMAIL_HELMET, Items.IRON_HELMET, Items.GOLDEN_HELMET, Items.DIAMOND_HELMET, Items.NETHERITE_HELMET); - tag(Tags.Items.ARMORS_CHESTPLATES).add(Items.LEATHER_CHESTPLATE, Items.CHAINMAIL_CHESTPLATE, Items.IRON_CHESTPLATE, Items.GOLDEN_CHESTPLATE, Items.DIAMOND_CHESTPLATE, Items.NETHERITE_CHESTPLATE); - tag(Tags.Items.ARMORS_LEGGINGS).add(Items.LEATHER_LEGGINGS, Items.CHAINMAIL_LEGGINGS, Items.IRON_LEGGINGS, Items.GOLDEN_LEGGINGS, Items.DIAMOND_LEGGINGS, Items.NETHERITE_LEGGINGS); - tag(Tags.Items.ARMORS_BOOTS).add(Items.LEATHER_BOOTS, Items.CHAINMAIL_BOOTS, Items.IRON_BOOTS, Items.GOLDEN_BOOTS, Items.DIAMOND_BOOTS, Items.NETHERITE_BOOTS); - tag(Tags.Items.ARMORS).addTag(Tags.Items.ARMORS_HELMETS).addTag(Tags.Items.ARMORS_CHESTPLATES).addTag(Tags.Items.ARMORS_LEGGINGS).addTag(Tags.Items.ARMORS_BOOTS); + copy(Tags.Blocks.STORAGE_BLOCKS_REDSTONE, Tags.Items.STORAGE_BLOCKS_REDSTONE); + copy(Tags.Blocks.STORAGE_BLOCKS_SLIME, Tags.Items.STORAGE_BLOCKS_SLIME); + copy(Tags.Blocks.STORAGE_BLOCKS_WHEAT, Tags.Items.STORAGE_BLOCKS_WHEAT); + tag(Tags.Items.STRINGS).add(Items.STRING); + tag(Tags.Items.VILLAGER_JOB_SITES).add( + Items.BARREL, Items.BLAST_FURNACE, Items.BREWING_STAND, Items.CARTOGRAPHY_TABLE, + Items.CAULDRON, Items.COMPOSTER, Items.FLETCHING_TABLE, Items.GRINDSTONE, + Items.LECTERN, Items.LOOM, Items.SMITHING_TABLE, Items.SMOKER, Items.STONECUTTER); + + // Tools and Armors + tag(Tags.Items.TOOLS_SHIELD).add(Items.SHIELD); + tag(Tags.Items.TOOLS_BOW).add(Items.BOW); + tag(Tags.Items.TOOLS_BRUSH).add(Items.BRUSH); + tag(Tags.Items.TOOLS_CROSSBOW).add(Items.CROSSBOW); + tag(Tags.Items.TOOLS_FISHING_ROD).add(Items.FISHING_ROD); + tag(Tags.Items.TOOLS_SHEAR).add(Items.SHEARS); + tag(Tags.Items.TOOLS_SPEAR).add(Items.TRIDENT); + tag(Tags.Items.TOOLS) + .addTag(ItemTags.AXES).addTag(ItemTags.HOES).addTag(ItemTags.PICKAXES).addTag(ItemTags.SHOVELS).addTag(ItemTags.SWORDS) + .addTag(Tags.Items.TOOLS_BOW).addTag(Tags.Items.TOOLS_BRUSH).addTag(Tags.Items.TOOLS_CROSSBOW).addTag(Tags.Items.TOOLS_FISHING_ROD).addTag(Tags.Items.TOOLS_SHEAR).addTag(Tags.Items.TOOLS_SHIELD).addTag(Tags.Items.TOOLS_SPEAR); + tag(Tags.Items.ARMORS).addTag(ItemTags.HEAD_ARMOR).addTag(ItemTags.CHEST_ARMOR).addTag(ItemTags.LEG_ARMOR).addTag(ItemTags.FOOT_ARMOR); + tag(Tags.Items.ENCHANTABLES).addTag(ItemTags.ARMOR_ENCHANTABLE).addTag(ItemTags.EQUIPPABLE_ENCHANTABLE).addTag(ItemTags.WEAPON_ENCHANTABLE).addTag(ItemTags.SWORD_ENCHANTABLE).addTag(ItemTags.MINING_ENCHANTABLE).addTag(ItemTags.MINING_LOOT_ENCHANTABLE).addTag(ItemTags.FISHING_ENCHANTABLE).addTag(ItemTags.TRIDENT_ENCHANTABLE).addTag(ItemTags.BOW_ENCHANTABLE).addTag(ItemTags.CROSSBOW_ENCHANTABLE).addTag(ItemTags.FIRE_ASPECT_ENCHANTABLE).addTag(ItemTags.DURABILITY_ENCHANTABLE).addOptionalTag(ItemTags.MACE_ENCHANTABLE); + + // Backwards compat with pre-1.21 tags. Done after so optional tag is last for better readability. + // TODO: Remove backwards compat tag entries in 1.22 +// tagWithOptionalLegacy(Tags.Items.BONES); + tag(Tags.Items.BRICKS_NORMAL).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "ingots/brick")); + tag(Tags.Items.BRICKS_NETHER).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "ingots/nether_brick")); +// tagWithOptionalLegacy(Tags.Items.CROPS); +// tagWithOptionalLegacy(Tags.Items.CROPS_BEETROOT); +// tagWithOptionalLegacy(Tags.Items.CROPS_CARROT); +// tagWithOptionalLegacy(Tags.Items.CROPS_NETHER_WART); +// tagWithOptionalLegacy(Tags.Items.CROPS_POTATO); +// tagWithOptionalLegacy(Tags.Items.CROPS_WHEAT); +// tagWithOptionalLegacy(Tags.Items.DUSTS); +// tagWithOptionalLegacy(Tags.Items.DUSTS_GLOWSTONE); +// tagWithOptionalLegacy(Tags.Items.DUSTS_REDSTONE); +// tagColoredWithOptionalLegacy(Tags.Items.DYES); + tag(Tags.Items.DYED_BLACK) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/black")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/black")); + tag(Tags.Items.DYED_BLUE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/blue")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/blue")); + tag(Tags.Items.DYED_BROWN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/brown")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/brown")); + tag(Tags.Items.DYED_CYAN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/cyan")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/cyan")); + tag(Tags.Items.DYED_GRAY) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/gray")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/gray")); + tag(Tags.Items.DYED_GREEN) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/green")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/green")); + tag(Tags.Items.DYED_LIGHT_BLUE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/light_blue")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/light_blue")); + tag(Tags.Items.DYED_LIGHT_GRAY) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/light_gray")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/light_gray")); + tag(Tags.Items.DYED_LIME) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/lime")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/lime")); + tag(Tags.Items.DYED_MAGENTA) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/magenta")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/magenta")); + tag(Tags.Items.DYED_MAGENTA) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/magenta")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/magenta")); + tag(Tags.Items.DYED_ORANGE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/orange")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/orange")); + tag(Tags.Items.DYED_PINK) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/pink")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/pink")); + tag(Tags.Items.DYED_PURPLE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/purple")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/purple")); + tag(Tags.Items.DYED_RED) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/red")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/red")); + tag(Tags.Items.DYED_WHITE) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/white")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/white")); + tag(Tags.Items.DYED_YELLOW) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "glass/yellow")) + .addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "stained_glass/yellow")); +// tagWithOptionalLegacy(Tags.Items.ENDER_PEARLS); +// tagWithOptionalLegacy(Tags.Items.FEATHERS); +// tagWithOptionalLegacy(Tags.Items.GEMS); +// tagWithOptionalLegacy(Tags.Items.GEMS_AMETHYST); +// tagWithOptionalLegacy(Tags.Items.GEMS_DIAMOND); +// tagWithOptionalLegacy(Tags.Items.GEMS_EMERALD); +// tagWithOptionalLegacy(Tags.Items.GEMS_LAPIS); +// tagWithOptionalLegacy(Tags.Items.GEMS_PRISMARINE); +// tagWithOptionalLegacy(Tags.Items.GEMS_QUARTZ); + tag(Tags.Items.GUNPOWDERS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "gunpowder")); +// tagWithOptionalLegacy(Tags.Items.INGOTS); +// tagWithOptionalLegacy(Tags.Items.INGOTS_COPPER); +// tagWithOptionalLegacy(Tags.Items.INGOTS_GOLD); +// tagWithOptionalLegacy(Tags.Items.INGOTS_IRON); +// tagWithOptionalLegacy(Tags.Items.INGOTS_NETHERITE); + tag(Tags.Items.LEATHERS).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "leather")); +// tagWithOptionalLegacy(Tags.Items.MUSHROOMS); +// tagWithOptionalLegacy(Tags.Items.NETHER_STARS); +// tagWithOptionalLegacy(Tags.Items.NUGGETS); +// tagWithOptionalLegacy(Tags.Items.NUGGETS_IRON); +// tagWithOptionalLegacy(Tags.Items.NUGGETS_GOLD); +// tagWithOptionalLegacy(Tags.Items.RAW_MATERIALS); +// tagWithOptionalLegacy(Tags.Items.RAW_MATERIALS_COPPER); +// tagWithOptionalLegacy(Tags.Items.RAW_MATERIALS_GOLD); +// tagWithOptionalLegacy(Tags.Items.RAW_MATERIALS_IRON); +// tagWithOptionalLegacy(Tags.Items.RODS); +// tagWithOptionalLegacy(Tags.Items.RODS_BLAZE); +// tagWithOptionalLegacy(Tags.Items.RODS_WOODEN); +// tagWithOptionalLegacy(Tags.Items.SEEDS); +// tagWithOptionalLegacy(Tags.Items.SEEDS_BEETROOT); +// tagWithOptionalLegacy(Tags.Items.SEEDS_MELON); +// tagWithOptionalLegacy(Tags.Items.SEEDS_PUMPKIN); +// tagWithOptionalLegacy(Tags.Items.SEEDS_WHEAT); +// tagWithOptionalLegacy(Tags.Items.SLIMEBALLS); +// tagWithOptionalLegacy(Tags.Items.STRINGS); + tag(Tags.Items.TOOLS_SHEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "shears")); + tag(Tags.Items.TOOLS_SPEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/tridents")); +// tagWithOptionalLegacy(Tags.Items.TOOLS); +// tagWithOptionalLegacy(Tags.Items.ARMORS); + tag(Tags.Items.TOOLS_SHIELD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/shields")); + tag(Tags.Items.TOOLS_BOW).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/bows")); + tag(Tags.Items.TOOLS_BRUSH).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/brushes")); + tag(Tags.Items.TOOLS_CROSSBOW).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/crossbows")); + tag(Tags.Items.TOOLS_FISHING_ROD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/fishing_rods")); + tag(Tags.Items.TOOLS_SHEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/shears")); + tag(Tags.Items.TOOLS_SPEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", "tools/tridents")); + tag(Tags.Items.TOOLS_SHIELD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/shields")); + tag(Tags.Items.TOOLS_BOW).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/bows")); + tag(Tags.Items.TOOLS_BRUSH).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/brushes")); + tag(Tags.Items.TOOLS_CROSSBOW).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/crossbows")); + tag(Tags.Items.TOOLS_FISHING_ROD).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/fishing_rods")); + tag(Tags.Items.TOOLS_SHEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/shears")); + tag(Tags.Items.TOOLS_SPEAR).addOptionalTag(ResourceLocation.fromNamespaceAndPath("c", "tools/tridents")); } - private void addColored(Consumer> consumer, TagKey group, String pattern) { +// private FabricTagBuilder tagWithOptionalLegacy(TagKey tag) { +// FabricTagBuilder tagAppender = tag(tag); +// tagAppender.addOptionalTag(ResourceLocation.fromNamespaceAndPath("forge", tag.location().getPath())); +// return tagAppender; +// } + +// private void tagColoredWithOptionalLegacy(TagKey group) { +// String prefix = group.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; +// for (DyeColor color : DyeColor.values()) { +// TagKey tag = getForgeItemTag(prefix + color.getName()); +// tagWithOptionalLegacy(tag); +// } +// } + + private void addColored(TagKey group, String pattern) { String prefix = group.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; for (DyeColor color : DyeColor.values()) { - ResourceLocation key = new ResourceLocation("minecraft", pattern.replace("{color}", color.getName())); + ResourceLocation key = ResourceLocation.fromNamespaceAndPath("minecraft", pattern.replace("{color}", color.getName())); TagKey tag = getForgeItemTag(prefix + color.getName()); Item item = BuiltInRegistries.ITEM.get(key); if (item == null || item == Items.AIR) - throw new IllegalStateException("Unknown vanilla item: " + key.toString()); + throw new IllegalStateException("Unknown vanilla item: " + key); tag(tag).add(item); - consumer.accept(tag); } } - private void copyColored(TagKey blockGroup, TagKey itemGroup) { - String blockPre = blockGroup.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; - String itemPre = itemGroup.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; + private void addColoredTags(Consumer> consumer, TagKey group) { + String prefix = group.location().getPath().toUpperCase(Locale.ENGLISH) + '_'; for (DyeColor color : DyeColor.values()) { - TagKey from = getForgeBlockTag(blockPre + color.getName()); - TagKey to = getForgeItemTag(itemPre + color.getName()); - copy(from, to); + TagKey tag = getForgeItemTag(prefix + color.getName()); + consumer.accept(tag); } - copy(getForgeBlockTag(blockPre + "colorless"), getForgeItemTag(itemPre + "colorless")); } @SuppressWarnings("unchecked") private TagKey getForgeBlockTag(String name) { try { - name = name.toUpperCase(Locale.ENGLISH).replace("_BLOCKS", "");; + name = name.toUpperCase(Locale.ENGLISH); return (TagKey) Tags.Blocks.class.getDeclaredField(name).get(null); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { throw new IllegalStateException(Tags.Blocks.class.getName() + " is missing tag name: " + name); @@ -200,7 +410,7 @@ private TagKey getForgeBlockTag(String name) { @SuppressWarnings("unchecked") private TagKey getForgeItemTag(String name) { try { - name = name.toUpperCase(Locale.ENGLISH).replace("_BLOCKS", "");; + name = name.toUpperCase(Locale.ENGLISH); return (TagKey) Tags.Items.class.getDeclaredField(name).get(null); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { throw new IllegalStateException(Tags.Items.class.getName() + " is missing tag name: " + name); @@ -210,4 +420,9 @@ private TagKey getForgeItemTag(String name) { public FabricTagBuilder tag(TagKey tag) { return getOrCreateTagBuilder(tag); } + + @Override + public String getName() { + return "PortingLib Item Tags"; + } } diff --git a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/mixin/DyeColorMixin.java b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/mixin/DyeColorMixin.java index cc940a70e..f5c35e38a 100644 --- a/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/mixin/DyeColorMixin.java +++ b/modules/tags/src/main/java/io/github/fabricators_of_create/porting_lib/tags/mixin/DyeColorMixin.java @@ -27,7 +27,7 @@ public class DyeColorMixin implements DyeExtension { @Inject(method = "", at = @At("TAIL")) public void addTag(String enumName, int enumIndex, int id, String name, int color, MapColor mapColor, int fireworkColor, int signColor, CallbackInfo ci) { - tag = TagKey.create(Registries.ITEM, new ResourceLocation("c", name + "_dyes")); + tag = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("c", "dyes/" + enumName)); } @Override diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/MutableContainerItemContext.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/MutableContainerItemContext.java index b7004b466..0eb4dc5f6 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/MutableContainerItemContext.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/MutableContainerItemContext.java @@ -43,7 +43,7 @@ public Slot(ItemStack initial) { @Override protected long getCapacity(ItemVariant variant) { - return variant.getItem().getMaxStackSize(); + return variant.getItem().getDefaultMaxStackSize(); } } } diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/TransferUtil.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/TransferUtil.java index 201b9059d..b66e83148 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/TransferUtil.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/TransferUtil.java @@ -314,7 +314,7 @@ public static List getItems(Storage storage, int cutoff) for (StorageView view : storage.nonEmptyViews()) { long contained = view.getAmount(); ItemVariant item = view.getResource(); - int maxSize = item.getItem().getMaxStackSize(); + int maxSize = item.getItem().getDefaultMaxStackSize(); while (contained > 0 && stacks.size() < cutoff) { int stackSize = Math.min(maxSize, (int) contained); contained -= stackSize; @@ -431,7 +431,7 @@ public static long extractItem(Storage storage, ItemStack stack) { /** Quickly extract and commit the given ItemStack. */ public static long extractFluid(Storage storage, FluidStack stack) { - return extract(storage, stack.getType(), stack.getAmount()); + return extract(storage, stack.getVariant(), stack.getAmount()); } /** Quickly insert and commit the given variant with the given amount. */ @@ -451,7 +451,7 @@ public static long insertItem(Storage storage, ItemStack stack) { /** Quickly insert and commit the given FluidStack. */ public static long insertFluid(Storage storage, FluidStack stack) { - return insert(storage, stack.getType(), stack.getAmount()); + return insert(storage, stack.getVariant(), stack.getAmount()); } /** Insert the given variant and amount into the given Player's inventory, excluding the hotbar, offhand, and armor. */ @@ -488,7 +488,7 @@ public static List extractAllAsStacks(Storage storage) { continue; } ItemVariant variant = currentView.getResource(); - int max = (int) Math.min(contained, variant.getItem().getMaxStackSize()); + int max = (int) Math.min(contained, variant.getItem().getDefaultMaxStackSize()); long extracted = currentView.extract(variant, max, t); if (extracted == 0) { currentView = itr.hasNext() ? itr.next() : null; diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/FluidTank.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/FluidTank.java index a260633f9..94d47d694 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/FluidTank.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/FluidTank.java @@ -5,6 +5,7 @@ import net.fabricmc.fabric.api.transfer.v1.storage.base.ResourceAmount; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import java.util.function.Predicate; @@ -66,7 +67,7 @@ public FluidTank setCapacity(long capacity) { @Override protected FluidVariant getBlankVariant() { - return FluidStack.EMPTY.getType(); + return FluidStack.EMPTY.getVariant(); } @Override @@ -83,22 +84,22 @@ public FluidStack getFluid() { } public void setFluid(FluidStack fluid) { - this.variant = fluid.getType(); + this.variant = fluid.getVariant(); this.amount = fluid.getAmount(); this.stack = fluid; } - public CompoundTag writeToNBT(CompoundTag tag) { - updateStack(); - stack.writeToNBT(tag); - tag.putLong("Capacity", capacity); - return tag; + public FluidTank readFromNBT(HolderLookup.Provider lookupProvider, CompoundTag nbt) { + setFluid(FluidStack.parseOptional(lookupProvider, nbt.getCompound("Fluid"))); + return this; } - public FluidTank readFromNBT(CompoundTag tag) { - setFluid(FluidStack.loadFluidStackFromNBT(tag)); - if (tag.contains("Capacity")) this.capacity = tag.getLong("Capacity"); - return this; + public CompoundTag writeToNBT(HolderLookup.Provider lookupProvider, CompoundTag nbt) { + if (!getFluid().isEmpty()) { + nbt.put("Fluid", getFluid().save(lookupProvider)); + } + + return nbt; } public boolean isEmpty() { diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/SimpleFluidContent.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/SimpleFluidContent.java new file mode 100644 index 000000000..dfc4f6c57 --- /dev/null +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/SimpleFluidContent.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package io.github.fabricators_of_create.porting_lib.transfer.fluid; + +import com.mojang.serialization.Codec; +import java.util.function.Predicate; + +import io.github.fabricators_of_create.porting_lib.fluids.FluidStack; +import io.github.fabricators_of_create.porting_lib.fluids.FluidType; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.component.DataComponentHolder; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.material.Fluid; + +/** + * Stock data component class to hold a {@link FluidStack}. + * + *

A corresponding {@link DataComponentType} must be registered to use this class. + */ +public class SimpleFluidContent implements DataComponentHolder { + public static final SimpleFluidContent EMPTY = new SimpleFluidContent(FluidStack.EMPTY); + public static final Codec CODEC = FluidStack.OPTIONAL_CODEC + .xmap(SimpleFluidContent::new, content -> content.fluidStack); + public static final StreamCodec STREAM_CODEC = FluidStack.OPTIONAL_STREAM_CODEC + .map(SimpleFluidContent::new, content -> content.fluidStack); + + private final FluidStack fluidStack; + + private SimpleFluidContent(FluidStack fluidStack) { + this.fluidStack = fluidStack; + } + + public static SimpleFluidContent copyOf(FluidStack fluidStack) { + return fluidStack.isEmpty() ? EMPTY : new SimpleFluidContent(fluidStack.copy()); + } + + public FluidStack copy() { + return this.fluidStack.copy(); + } + + public boolean isEmpty() { + return this.fluidStack.isEmpty(); + } + + public Fluid getFluid() { + return fluidStack.getFluid(); + } + + public Holder getFluidHolder() { + return fluidStack.getFluidHolder(); + } + + public boolean is(TagKey tag) { + return fluidStack.is(tag); + } + + public boolean is(Fluid fluid) { + return fluidStack.is(fluid); + } + + public boolean is(Predicate> predicate) { + return fluidStack.is(predicate); + } + + public boolean is(Holder holder) { + return fluidStack.is(holder); + } + + public boolean is(HolderSet holders) { + return fluidStack.is(holders); + } + + public long getAmount() { + return fluidStack.getAmount(); + } + + public FluidType getFluidType() { + return fluidStack.getFluidType(); + } + + public boolean is(FluidType fluidType) { + return fluidStack.is(fluidType); + } + + public boolean matches(FluidStack other) { + return FluidStack.matches(fluidStack, other); + } + + public boolean isSameFluid(FluidStack other) { + return FluidStack.isSameFluid(fluidStack, other); + } + + public boolean isSameFluidSameComponents(FluidStack other) { + return FluidStack.isSameFluidSameComponents(fluidStack, other); + } + + public boolean isSameFluidSameComponents(SimpleFluidContent content) { + return isSameFluidSameComponents(content.fluidStack); + } + + @Override + public DataComponentMap getComponents() { + return fluidStack.getComponents(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (!(obj instanceof SimpleFluidContent o)) { + return false; + } else { + return FluidStack.matches(this.fluidStack, o.fluidStack); + } + } + + @Override + public int hashCode() { + return (int) (this.fluidStack.getAmount() * 31 + FluidStack.hashFluidAndComponents(this.fluidStack)); + } +} diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidBucketWrapper.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidBucketWrapper.java index 203d270c5..6b7a6307c 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidBucketWrapper.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidBucketWrapper.java @@ -1,123 +1,123 @@ -package io.github.fabricators_of_create.porting_lib.transfer.fluid.item; - -import io.github.fabricators_of_create.porting_lib.fluids.FluidStack; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import io.github.fabricators_of_create.porting_lib.transfer.TransferUtil; -import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; -import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants; -import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; -import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; -import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; -import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; -import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -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.item.MilkBucketItem; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -@ApiStatus.Experimental -public class FluidBucketWrapper implements SingleSlotStorage { - - @NotNull - protected ContainerItemContext context; - - public FluidBucketWrapper(@NotNull ContainerItemContext context) { - this.context = context; - } - - public boolean canFillFluidType(FluidVariant resource, long amount) { - if (resource.getFluid() == Fluids.WATER || resource.getFluid() == Fluids.LAVA) { - return true; - } - return !new ItemStack(resource.getFluid().getBucket()).isEmpty(); - } - - @NotNull - public FluidStack getFluid() { - Item item = context.getItemVariant().getItem(); - if (item instanceof BucketItem bucketItem) { - return new FluidStack(bucketItem.content, FluidConstants.BUCKET); - } else { - return FluidStack.EMPTY; - } - } - - protected void setFluid(@NotNull FluidStack fluidStack) { - try (Transaction tx = TransferUtil.getTransaction()) { - if (fluidStack.isEmpty()) { - if (context.exchange(ItemVariant.of(Items.BUCKET), 1, tx) == 1) - tx.commit(); - } else{ - if (context.exchange(ItemVariant.of(getFilledBucket(fluidStack)), 1, tx) == 1) - tx.commit(); - } - } - } - - @Override - public boolean isResourceBlank() { - return getResource().isBlank(); - } - - @Override - public FluidVariant getResource() { - return getFluid().getType(); - } - - @Override - public long getAmount() { - return getFluid().getAmount(); - } - - @Override - public long getCapacity() { - return FluidConstants.BUCKET; - } - - @Override - public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { - if (context.getAmount() != 1 || maxAmount < FluidConstants.BUCKET || context.getItemVariant().getItem() instanceof MilkBucketItem || !new FluidStack(resource, maxAmount).isEmpty() || !canFillFluidType(resource, maxAmount)) { - return 0; - } - - setFluid(new FluidStack(resource, maxAmount)); - - return FluidConstants.BUCKET; - } - - @Override - public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { - if (context.getAmount() != 1 || maxAmount < FluidConstants.BUCKET) { - return 0; - } - - FluidStack fluidStack = getFluid(); - if (!fluidStack.isEmpty() && fluidStack.isFluidEqual(resource)) { - setFluid(FluidStack.EMPTY); - return fluidStack.getAmount(); - } - - return 0; - } - - @NotNull - public ItemStack getFilledBucket(@NotNull FluidStack fluidStack) { - Fluid fluid = fluidStack.getFluid(); - - if (!fluidStack.hasTag() || fluidStack.getTag().isEmpty()) { - if (fluid == Fluids.WATER) { - return new ItemStack(Items.WATER_BUCKET); - } else if (fluid == Fluids.LAVA) { - return new ItemStack(Items.LAVA_BUCKET); - } - } - - return new ItemStack(fluidStack.getFluid().getBucket()); - } -} +//package io.github.fabricators_of_create.porting_lib.transfer.fluid.item; +// +//import io.github.fabricators_of_create.porting_lib.fluids.FluidStack; +// +//import org.jetbrains.annotations.ApiStatus; +//import org.jetbrains.annotations.NotNull; +// +//import io.github.fabricators_of_create.porting_lib.transfer.TransferUtil; +//import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; +//import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants; +//import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +//import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +//import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; +//import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +//import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +//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.item.MilkBucketItem; +//import net.minecraft.world.level.material.Fluid; +//import net.minecraft.world.level.material.Fluids; +// +//@ApiStatus.Experimental +//public class FluidBucketWrapper implements SingleSlotStorage { TODO: PORT +// +// @NotNull +// protected ContainerItemContext context; +// +// public FluidBucketWrapper(@NotNull ContainerItemContext context) { +// this.context = context; +// } +// +// public boolean canFillFluidType(FluidVariant resource, long amount) { +// if (resource.getFluid() == Fluids.WATER || resource.getFluid() == Fluids.LAVA) { +// return true; +// } +// return !new ItemStack(resource.getFluid().getBucket()).isEmpty(); +// } +// +// @NotNull +// public FluidStack getFluid() { +// Item item = context.getItemVariant().getItem(); +// if (item instanceof BucketItem bucketItem) { +// return new FluidStack(bucketItem.content, FluidConstants.BUCKET); +// } else { +// return FluidStack.EMPTY; +// } +// } +// +// protected void setFluid(@NotNull FluidStack fluidStack) { +// try (Transaction tx = TransferUtil.getTransaction()) { +// if (fluidStack.isEmpty()) { +// if (context.exchange(ItemVariant.of(Items.BUCKET), 1, tx) == 1) +// tx.commit(); +// } else{ +// if (context.exchange(ItemVariant.of(getFilledBucket(fluidStack)), 1, tx) == 1) +// tx.commit(); +// } +// } +// } +// +// @Override +// public boolean isResourceBlank() { +// return getResource().isBlank(); +// } +// +// @Override +// public FluidVariant getResource() { +// return getFluid().getVariant(); +// } +// +// @Override +// public long getAmount() { +// return getFluid().getAmount(); +// } +// +// @Override +// public long getCapacity() { +// return FluidConstants.BUCKET; +// } +// +// @Override +// public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { +// if (context.getAmount() != 1 || maxAmount < FluidConstants.BUCKET || context.getItemVariant().getItem() instanceof MilkBucketItem || !new FluidStack(resource, maxAmount).isEmpty() || !canFillFluidType(resource, maxAmount)) { +// return 0; +// } +// +// setFluid(new FluidStack(resource, maxAmount)); +// +// return FluidConstants.BUCKET; +// } +// +// @Override +// public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { +// if (context.getAmount() != 1 || maxAmount < FluidConstants.BUCKET) { +// return 0; +// } +// +// FluidStack fluidStack = getFluid(); +// if (!fluidStack.isEmpty() && fluidStack.isFluidEqual(resource)) { +// setFluid(FluidStack.EMPTY); +// return fluidStack.getAmount(); +// } +// +// return 0; +// } +// +// @NotNull +// public ItemStack getFilledBucket(@NotNull FluidStack fluidStack) { +// Fluid fluid = fluidStack.getFluid(); +// +// if (!fluidStack.hasTag() || fluidStack.getTag().isEmpty()) { +// if (fluid == Fluids.WATER) { +// return new ItemStack(Items.WATER_BUCKET); +// } else if (fluid == Fluids.LAVA) { +// return new ItemStack(Items.LAVA_BUCKET); +// } +// } +// +// return new ItemStack(fluidStack.getFluid().getBucket()); +// } +//} diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidHandlerItemStack.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidHandlerItemStack.java index da772aee5..027c059cc 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidHandlerItemStack.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/fluid/item/FluidHandlerItemStack.java @@ -1,230 +1,242 @@ -package io.github.fabricators_of_create.porting_lib.transfer.fluid.item; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -import io.github.fabricators_of_create.porting_lib.fluids.FluidStack; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; -import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; -import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; -import net.fabricmc.fabric.api.transfer.v1.storage.Storage; -import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; -import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; -import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.ItemStack; - -@ApiStatus.Experimental -public class FluidHandlerItemStack implements Storage { - public static final String FLUID_NBT_KEY = "Fluid"; - - @NotNull - protected ContainerItemContext container; - protected long capacity; - - /** - * @param container The container {@link ContainerItemContext}, data is stored on the {@link ItemVariant} NBT. - * @param capacity The maximum capacity of this fluid tank. - */ - public FluidHandlerItemStack(@NotNull ContainerItemContext container, long capacity) { - this.container = container; - this.capacity = capacity; - } - - @NotNull - public FluidStack getFluid() { - CompoundTag tagCompound = container.getItemVariant().getNbt(); - if (tagCompound == null || !tagCompound.contains(FLUID_NBT_KEY)) { - return FluidStack.EMPTY; - } - return FluidStack.loadFluidStackFromNBT(tagCompound.getCompound(FLUID_NBT_KEY)); - } - - protected boolean setFluid(FluidStack fluid, TransactionContext tx) { - ItemStack newStack = container.getItemVariant().toStack(); - if (!newStack.hasTag()) { - newStack.setTag(new CompoundTag()); - } - - CompoundTag fluidTag = new CompoundTag(); - fluid.writeToNBT(fluidTag); - newStack.getTag().put(FLUID_NBT_KEY, fluidTag); - - if (container.exchange(ItemVariant.of(newStack), 1, tx) == 1) - return true; - return false; - } - - - @Override - public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { - if (container.getAmount() != 1 || new FluidStack(resource, maxAmount).isEmpty() || !canFillFluidType(resource, maxAmount)) - return 0; - FluidStack contained = getFluid(); - if (contained.isEmpty()) { - long fillAmount = Math.min(capacity, maxAmount); - - FluidStack filled = new FluidStack(resource, maxAmount); - filled.setAmount(fillAmount); - if (setFluid(filled, transaction)) - return fillAmount; - } else { - if (contained.isFluidEqual(resource)) { - long fillAmount = Math.min(capacity - contained.getAmount(), maxAmount); - - if (fillAmount > 0) { - contained.grow(fillAmount); - if (setFluid(contained, transaction)) - return fillAmount; - } - } - } - - return 0; - } - - @Override - public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { - if (container.getAmount() != 1 || new FluidStack(resource, maxAmount).isEmpty() || !FluidStack.isFluidEqual(resource, getFluid().getType()) || maxAmount <= 0) - return 0; - FluidStack contained = getFluid(); - if (contained.isEmpty() || !canDrainFluidType(contained.getType(), contained.getAmount())) - { - return 0; - } - - final long drainAmount = Math.min(contained.getAmount(), maxAmount); - - contained.shrink(drainAmount); - if (contained.isEmpty()) { - if (setContainerToEmpty(transaction)) - return drainAmount; - } else { - if (setFluid(contained, transaction)) - return drainAmount; - } - - return 0; - } - - @Override - public Iterator> iterator() { - return new Iterator<>() { - boolean hasNext = true; - - @Override - public boolean hasNext() { - return hasNext; - } - - @Override - public StorageView next() { - if (!hasNext) { - throw new NoSuchElementException(); - } - - hasNext = false; - return new FluidHandlerItemStackView(); - } - }; - } - - public class FluidHandlerItemStackView implements StorageView { - - @Override - public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { - return FluidHandlerItemStack.this.extract(resource, maxAmount, transaction); - } - - @Override - public boolean isResourceBlank() { - return getResource().isBlank(); - } - - @Override - public FluidVariant getResource() { - return getFluid().getType(); - } - - @Override - public long getAmount() { - return getFluid().getAmount(); - } - - @Override - public long getCapacity() { - return capacity; - } - } - - public boolean canFillFluidType(FluidVariant variant, long amount) { - return true; - } - - public boolean canDrainFluidType(FluidVariant variant, long amount) { - return true; - } - - /** - * Override this method for special handling. - * Can be used to swap out or destroy the container. - * @param tx The current transaction to use. - * @return returns true if the container was successfully emptied. - */ - protected boolean setContainerToEmpty(TransactionContext tx) { - ItemStack newStack = container.getItemVariant().toStack(); - newStack.removeTagKey(FLUID_NBT_KEY); - if (container.exchange(ItemVariant.of(newStack), 1, tx) == 1) - return true; - return false; - } - - /** - * Destroys the container item when it's emptied. - */ - public static class Consumable extends FluidHandlerItemStack { - public Consumable(ContainerItemContext container, int capacity) { - super(container, capacity); - } - - @Override - protected boolean setContainerToEmpty(TransactionContext tx) { - boolean result = super.setContainerToEmpty(tx); - try (Transaction nested = tx.openNested()) { - if (container.extract(container.getItemVariant(), 1, nested) == 1) { - nested.commit(); - return true; - } - } - return result; - } - } - - /** - * Swaps the container item for a different one when it's emptied. - */ - public static class SwapEmpty extends FluidHandlerItemStack { - protected final ItemStack emptyContainer; - - public SwapEmpty(ContainerItemContext container, ItemStack emptyContainer, int capacity) { - super(container, capacity); - this.emptyContainer = emptyContainer; - } - - @Override - protected boolean setContainerToEmpty(TransactionContext tx) { - boolean result = super.setContainerToEmpty(tx); - try (Transaction nested = tx.openNested()) { - if (container.exchange(ItemVariant.of(emptyContainer), emptyContainer.getCount(), nested) == emptyContainer.getCount()) { - nested.commit(); - return true; - } - } - return result; - } - } -} +//package io.github.fabricators_of_create.porting_lib.transfer.fluid.item; +// +//import java.util.Iterator; +//import java.util.NoSuchElementException; +//import java.util.function.Supplier; +// +//import io.github.fabricators_of_create.porting_lib.fluids.FluidStack; +// +//import io.github.fabricators_of_create.porting_lib.transfer.fluid.SimpleFluidContent; +// +//import net.minecraft.core.component.DataComponentType; +// +//import org.jetbrains.annotations.ApiStatus; +//import org.jetbrains.annotations.NotNull; +// +//import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; +//import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +//import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +//import net.fabricmc.fabric.api.transfer.v1.storage.Storage; +//import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; +//import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction; +//import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +//import net.minecraft.nbt.CompoundTag; +//import net.minecraft.world.item.ItemStack; +// +///** +// * FluidHandlerItemStack is a template capability provider for ItemStacks. +// * Data is stored in a {@link SimpleFluidContent} component. +// * +// *

This class allows an ItemStack to contain any partial level of fluid up to its capacity, unlike {@link FluidHandlerItemStackSimple} +// * +// *

Additional examples are provided to enable consumable fluid containers (see {@link Consumable}), +// * fluid containers with different empty and full items (see {@link SwapEmpty}, +// */ +//@ApiStatus.Experimental +//public class FluidHandlerItemStack implements Storage { TODO: PORT +// public static final String FLUID_NBT_KEY = "Fluid"; +// +// protected final Supplier> componentType; +// @NotNull +// protected ContainerItemContext container; +// protected long capacity; +// +// /** +// * @param componentType The data component type to use for data storage. +// * @param container The container {@link ContainerItemContext}, data is stored on the {@link ItemVariant} NBT. +// * @param capacity The maximum capacity of this fluid tank. +// */ +// public FluidHandlerItemStack(Supplier> componentType, @NotNull ContainerItemContext container, long capacity) { +// this.container = container; +// this.capacity = capacity; +// } +// +// @NotNull +// public FluidStack getFluid() { +// return container.getItemVariant().getComponents().get(componentType, SimpleFluidContent.EMPTY).copy() +// } +// +// protected boolean setFluid(FluidStack fluid, TransactionContext tx) { +// ItemStack newStack = container.getItemVariant().toStack(); +// if (!newStack.hasTag()) { +// newStack.setTag(new CompoundTag()); +// } +// +// CompoundTag fluidTag = new CompoundTag(); +// fluid.writeToNBT(fluidTag); +// newStack.getTag().put(FLUID_NBT_KEY, fluidTag); +// +// if (container.exchange(ItemVariant.of(newStack), 1, tx) == 1) +// return true; +// return false; +// } +// +// +// @Override +// public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { +// if (container.getAmount() != 1 || new FluidStack(resource, maxAmount).isEmpty() || !canFillFluidType(resource, maxAmount)) +// return 0; +// FluidStack contained = getFluid(); +// if (contained.isEmpty()) { +// long fillAmount = Math.min(capacity, maxAmount); +// +// FluidStack filled = new FluidStack(resource, maxAmount); +// filled.setAmount(fillAmount); +// if (setFluid(filled, transaction)) +// return fillAmount; +// } else { +// if (contained.isFluidEqual(resource)) { +// long fillAmount = Math.min(capacity - contained.getAmount(), maxAmount); +// +// if (fillAmount > 0) { +// contained.grow(fillAmount); +// if (setFluid(contained, transaction)) +// return fillAmount; +// } +// } +// } +// +// return 0; +// } +// +// @Override +// public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { +// if (container.getAmount() != 1 || new FluidStack(resource, maxAmount).isEmpty() || !FluidStack.isFluidEqual(resource, getFluid().getType()) || maxAmount <= 0) +// return 0; +// FluidStack contained = getFluid(); +// if (contained.isEmpty() || !canDrainFluidType(contained.getType(), contained.getAmount())) +// { +// return 0; +// } +// +// final long drainAmount = Math.min(contained.getAmount(), maxAmount); +// +// contained.shrink(drainAmount); +// if (contained.isEmpty()) { +// if (setContainerToEmpty(transaction)) +// return drainAmount; +// } else { +// if (setFluid(contained, transaction)) +// return drainAmount; +// } +// +// return 0; +// } +// +// @Override +// public Iterator> iterator() { +// return new Iterator<>() { +// boolean hasNext = true; +// +// @Override +// public boolean hasNext() { +// return hasNext; +// } +// +// @Override +// public StorageView next() { +// if (!hasNext) { +// throw new NoSuchElementException(); +// } +// +// hasNext = false; +// return new FluidHandlerItemStackView(); +// } +// }; +// } +// +// public class FluidHandlerItemStackView implements StorageView { +// +// @Override +// public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { +// return FluidHandlerItemStack.this.extract(resource, maxAmount, transaction); +// } +// +// @Override +// public boolean isResourceBlank() { +// return getResource().isBlank(); +// } +// +// @Override +// public FluidVariant getResource() { +// return getFluid().getType(); +// } +// +// @Override +// public long getAmount() { +// return getFluid().getAmount(); +// } +// +// @Override +// public long getCapacity() { +// return capacity; +// } +// } +// +// public boolean canFillFluidType(FluidVariant variant, long amount) { +// return true; +// } +// +// public boolean canDrainFluidType(FluidVariant variant, long amount) { +// return true; +// } +// +// /** +// * Override this method for special handling. +// * Can be used to swap out or destroy the container. +// * @param tx The current transaction to use. +// * @return returns true if the container was successfully emptied. +// */ +// protected boolean setContainerToEmpty(TransactionContext tx) { +// ItemStack newStack = container.getItemVariant().toStack(); +// newStack.removeTagKey(FLUID_NBT_KEY); +// if (container.exchange(ItemVariant.of(newStack), 1, tx) == 1) +// return true; +// return false; +// } +// +// /** +// * Destroys the container item when it's emptied. +// */ +// public static class Consumable extends FluidHandlerItemStack { +// public Consumable(ContainerItemContext container, int capacity) { +// super(container, capacity); +// } +// +// @Override +// protected boolean setContainerToEmpty(TransactionContext tx) { +// boolean result = super.setContainerToEmpty(tx); +// try (Transaction nested = tx.openNested()) { +// if (container.extract(container.getItemVariant(), 1, nested) == 1) { +// nested.commit(); +// return true; +// } +// } +// return result; +// } +// } +// +// /** +// * Swaps the container item for a different one when it's emptied. +// */ +// public static class SwapEmpty extends FluidHandlerItemStack { +// protected final ItemStack emptyContainer; +// +// public SwapEmpty(Supplier> componentType, ContainerItemContext container, ItemStack emptyContainer, int capacity) { +// super(componentType, container, capacity); +// this.emptyContainer = emptyContainer; +// } +// +// @Override +// protected boolean setContainerToEmpty(TransactionContext tx) { +// boolean result = super.setContainerToEmpty(tx); +// try (Transaction nested = tx.openNested()) { +// if (container.exchange(ItemVariant.of(emptyContainer), emptyContainer.getCount(), nested) == emptyContainer.getCount()) { +// nested.commit(); +// return true; +// } +// } +// return result; +// } +// } +//} diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemHandlerHelper.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemHandlerHelper.java index d2ba8d569..5b19f8b97 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemHandlerHelper.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemHandlerHelper.java @@ -15,22 +15,6 @@ import javax.annotation.Nonnull; public class ItemHandlerHelper { - // left for drop-in compat - public static boolean canItemStacksStack(ItemStack first, ItemStack second) { - return ItemStack.isSameItemSameTags(first, second); - } - - public static ItemStack copyStackWithSize(ItemStack stack, int size) { - if (size == 0) return ItemStack.EMPTY; - ItemStack copy = stack.copy(); - copy.setCount(size); - return copy; - } - - public static ItemStack growCopy(ItemStack stack, int amount) { - return copyStackWithSize(stack, stack.getCount() + amount); - } - /** * giveItemToPlayer without preferred slot */ diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandler.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandler.java index 51334258e..fcd855637 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandler.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandler.java @@ -11,6 +11,7 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -192,16 +193,16 @@ protected ItemStackHandlerSlot makeSlot(int index, ItemStack stack) { // serialization @Override - public CompoundTag serializeNBT() { + public CompoundTag serializeNBT(HolderLookup.Provider provider) { CompoundTag nbt = new CompoundTag(); nbt.putInt("Size", this.slots.size()); ListTag slots = new ListTag(); for (ItemStackHandlerSlot slot : this.slots) { - CompoundTag slotTag = slot.save(); - if (slotTag != null) { - slotTag.putInt("Slot", slot.getIndex()); - slots.add(slotTag); + if (!slot.getStack().isEmpty()) { + CompoundTag itemTag = new CompoundTag(); + itemTag.putInt("Slot", slot.getIndex()); + slots.add(slot.save(provider, itemTag)); } } @@ -210,7 +211,7 @@ public CompoundTag serializeNBT() { } @Override - public void deserializeNBT(CompoundTag nbt) { + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { setSize(nbt.contains("Size", Tag.TAG_INT) ? nbt.getInt("Size") : slots.size()); // also clears ListTag slots = nbt.getList("Items", Tag.TAG_COMPOUND); for (int i = 0; i < slots.size(); i++) { @@ -218,7 +219,7 @@ public void deserializeNBT(CompoundTag nbt) { int index = slotTag.getInt("Slot"); if (index >= 0 && index < this.slots.size()) { - this.slots.get(index).load(slotTag); + this.slots.get(index).load(provider, slotTag); } } onLoad(); diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerContainer.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerContainer.java index f195d74e2..0c2723f59 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerContainer.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerContainer.java @@ -59,8 +59,8 @@ public ItemStack removeItem(int index, int amount) { int count = stack.getCount(); int toRemove = Math.min(amount, count); int remaining = count - toRemove; - ItemStack removed = ItemHandlerHelper.copyStackWithSize(stack, toRemove); - ItemStack remainder = remaining <= 0 ? ItemStack.EMPTY : ItemHandlerHelper.copyStackWithSize(stack, remaining); + ItemStack removed = stack.copyWithCount(toRemove); + ItemStack remainder = remaining <= 0 ? ItemStack.EMPTY : stack.copyWithCount(remaining); slot.setNewStack(remainder); return removed; } diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerSlot.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerSlot.java index a06ec71ba..2379efe53 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerSlot.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/ItemStackHandlerSlot.java @@ -4,6 +4,10 @@ import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; import net.fabricmc.fabric.api.transfer.v1.item.base.SingleStackStorage; +import net.minecraft.core.HolderLookup; + +import net.minecraft.nbt.Tag; + import org.jetbrains.annotations.Nullable; import net.minecraft.nbt.CompoundTag; @@ -83,12 +87,12 @@ protected void notifyHandlerOfChange() { * @return null to skip saving this slot */ @Nullable - public CompoundTag save() { - return stack.isEmpty() ? null : stack.save(new CompoundTag()); + public Tag save(HolderLookup.Provider provider, Tag tag) { + return stack.save(provider, tag); } - public void load(CompoundTag tag) { - setStack(ItemStack.of(tag)); + public void load(HolderLookup.Provider provider, CompoundTag tag) { + ItemStack.parse(provider, tag).ifPresent(this::setStack); onStackChange(); // intentionally do not notify handler, matches forge } diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/RecipeWrapper.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/RecipeWrapper.java index 822bec6f3..74d54b7a8 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/RecipeWrapper.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/transfer/item/RecipeWrapper.java @@ -4,6 +4,7 @@ import net.fabricmc.fabric.api.transfer.v1.storage.StorageView; import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; @@ -148,13 +149,13 @@ public void setSize(int size) { } @Override - public CompoundTag serializeNBT() { - return handler.serializeNBT(); + public CompoundTag serializeNBT(HolderLookup.Provider provider) { + return handler.serializeNBT(provider); } @Override - public void deserializeNBT(CompoundTag nbt) { - handler.deserializeNBT(nbt); + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { + handler.deserializeNBT(provider, nbt); } @Override diff --git a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemStackUtil.java b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemStackUtil.java index 914b5ccfd..b81437731 100644 --- a/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemStackUtil.java +++ b/modules/transfer/src/main/java/io/github/fabricators_of_create/porting_lib/util/ItemStackUtil.java @@ -2,46 +2,12 @@ import java.util.Arrays; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; public class ItemStackUtil { - /** - * @deprecated {@link ItemStack#matches(ItemStack, ItemStack)} - */ - @Deprecated(forRemoval = true) - public static boolean equals(ItemStack stack1, ItemStack stack2, boolean limitTags) { - if (stack1.isEmpty()) { - return stack2.isEmpty(); - } else { - return !stack2.isEmpty() && stack1.getCount() == stack2.getCount() && stack1.getItem() == stack2.getItem() && - (limitTags ? areTagsEqual(stack1, stack2) : ItemStack.isSameItemSameTags(stack1, stack2)); - } - } - - public static boolean areTagsEqual(ItemStack stack1, ItemStack stack2) { - CompoundTag tag1 = stack1.getTag(); - CompoundTag tag2 = stack2.getTag(); - if (tag1 == null) { - return tag2 == null; - } else { - return tag1.equals(tag2); - } - } - public static ItemStack[] createEmptyStackArray(int size) { ItemStack[] stacks = new ItemStack[size]; Arrays.fill(stacks, ItemStack.EMPTY); return stacks; } - - /** - * @deprecated {@link ItemStack#isSameItemSameTags(ItemStack, ItemStack)} - */ - @Deprecated(forRemoval = true) - public static boolean canItemStacksStack(ItemStack first, ItemStack second) { - if (first.isEmpty() || !ItemStack.isSameItem(first, second) || first.hasTag() != second.hasTag()) return false; - - return !first.hasTag() || first.getTag().equals(second.getTag()); - } } diff --git a/modules/utility/build.gradle b/modules/utility/build.gradle deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibUtility.java b/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibUtility.java deleted file mode 100644 index 9b6fc446b..000000000 --- a/modules/utility/src/main/java/io/github/fabricators_of_create/porting_lib/PortingLibUtility.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.fabricators_of_create.porting_lib; - -import io.github.fabricators_of_create.porting_lib.util.ServerLifecycleHooks; -import io.github.fabricators_of_create.porting_lib.util.TrueCondition; -import net.fabricmc.api.ModInitializer; - -public class PortingLibUtility implements ModInitializer { - @Override - public void onInitialize() { - ServerLifecycleHooks.init(); - TrueCondition.init(); - } -} diff --git a/modules/utility/src/main/resources/fabric.mod.json b/modules/utility/src/main/resources/fabric.mod.json deleted file mode 100644 index 45c6861b4..000000000 --- a/modules/utility/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "schemaVersion": 1, - "id": "porting_lib_utility", - "version": "${version}", - "name": "Porting Lib Utility", - "description": "Misc Utilities", - "entrypoints": { - "main": [ - "io.github.fabricators_of_create.porting_lib.PortingLibUtility" - ] - } -}