From 3fcf98aebf4ed7c1e7be761578525d4d50ce19a0 Mon Sep 17 00:00:00 2001 From: ErrorCraft Date: Fri, 8 May 2026 20:42:11 +0200 Subject: [PATCH 1/4] Unify the block and fluid placement for buckets --- .../data/minecraft/item/axolotl_bucket.json | 14 +- .../generated/data/minecraft/item/bucket.json | 4 +- .../data/minecraft/item/cod_bucket.json | 14 +- .../data/minecraft/item/lava_bucket.json | 9 +- .../minecraft/item/powder_snow_bucket.json | 9 +- .../minecraft/item/pufferfish_bucket.json | 14 +- .../data/minecraft/item/salmon_bucket.json | 14 +- .../data/minecraft/item/tadpole_bucket.json | 14 +- .../minecraft/item/tropical_fish_bucket.json | 14 +- .../data/minecraft/item/water_bucket.json | 9 +- .../net/errorcraft/itematic/Itematic.java | 2 + .../errorcraft/itematic/fluid/FluidKeys.java | 1 - .../errorcraft/itematic/fluid/FluidUtil.java | 49 +++++ .../errorcraft/itematic/item/ItemUtil.java | 20 +- .../modification/WorldModification.java | 21 ++ .../modification/WorldModificationType.java | 6 + .../modification/WorldModificationTypes.java | 21 ++ .../bucket/modification/type/DrainFluid.java | 40 ++++ .../bucket/modification/type/PlaceBlock.java | 58 ++++++ .../bucket/modification/type/PlaceFluid.java | 54 +++++ .../components/BucketItemComponent.java | 171 +++++++--------- .../itematic/item/placement/BlockPlacer.java | 38 +++- .../itematic/item/placement/FluidPlacer.java | 187 ------------------ .../item/placement/fluid/FluidDrainer.java | 74 +++++++ .../item/placement/fluid/FluidPlacer.java | 175 ++++++++++++++++ .../itematic/registry/ItematicRegistries.java | 3 + .../registry/ItematicRegistryKeys.java | 2 + .../world/action/actions/UseBucketAction.java | 33 +--- .../world/action/context/ActionContext.java | 1 - 29 files changed, 679 insertions(+), 392 deletions(-) create mode 100644 src/main/java/net/errorcraft/itematic/fluid/FluidUtil.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java create mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java delete mode 100644 src/main/java/net/errorcraft/itematic/item/placement/FluidPlacer.java create mode 100644 src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java create mode 100644 src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java diff --git a/src/main/generated/data/minecraft/item/axolotl_bucket.json b/src/main/generated/data/minecraft/item/axolotl_bucket.json index 40b0d31a..3904ae0d 100644 --- a/src/main/generated/data/minecraft/item/axolotl_bucket.json +++ b/src/main/generated/data/minecraft/item/axolotl_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_axolotl", - "entity": { - "entity": "minecraft:axolotl", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:axolotl", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_axolotl", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/bucket.json b/src/main/generated/data/minecraft/item/bucket.json index 6cf016d8..ca972026 100644 --- a/src/main/generated/data/minecraft/item/bucket.json +++ b/src/main/generated/data/minecraft/item/bucket.json @@ -1,7 +1,9 @@ { "behavior": { "minecraft:bucket": { - "fluid": "minecraft:empty" + "modification": { + "type": "minecraft:drain_fluid" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/cod_bucket.json b/src/main/generated/data/minecraft/item/cod_bucket.json index 70aade48..fefd159b 100644 --- a/src/main/generated/data/minecraft/item/cod_bucket.json +++ b/src/main/generated/data/minecraft/item/cod_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_fish", - "entity": { - "entity": "minecraft:cod", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:cod", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_fish", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/lava_bucket.json b/src/main/generated/data/minecraft/item/lava_bucket.json index 4c4dbb1c..26e7560e 100644 --- a/src/main/generated/data/minecraft/item/lava_bucket.json +++ b/src/main/generated/data/minecraft/item/lava_bucket.json @@ -1,9 +1,12 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_lava", - "fluid": "minecraft:lava", - "transforms_into": "minecraft:bucket" + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:lava", + "place_sound": "minecraft:item.bucket.empty_lava", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/powder_snow_bucket.json b/src/main/generated/data/minecraft/item/powder_snow_bucket.json index 46c9f11b..9147f534 100644 --- a/src/main/generated/data/minecraft/item/powder_snow_bucket.json +++ b/src/main/generated/data/minecraft/item/powder_snow_bucket.json @@ -1,9 +1,12 @@ { "behavior": { "minecraft:bucket": { - "block": "minecraft:powder_snow", - "emptying_sound_event": "minecraft:item.bucket.empty_powder_snow", - "transforms_into": "minecraft:bucket" + "modification": { + "type": "minecraft:place_block", + "block": "minecraft:powder_snow", + "place_sound": "minecraft:item.bucket.empty_powder_snow", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/pufferfish_bucket.json b/src/main/generated/data/minecraft/item/pufferfish_bucket.json index cf9a8e55..39c84fdd 100644 --- a/src/main/generated/data/minecraft/item/pufferfish_bucket.json +++ b/src/main/generated/data/minecraft/item/pufferfish_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_fish", - "entity": { - "entity": "minecraft:pufferfish", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:pufferfish", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_fish", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/salmon_bucket.json b/src/main/generated/data/minecraft/item/salmon_bucket.json index c3721d34..fc269fcc 100644 --- a/src/main/generated/data/minecraft/item/salmon_bucket.json +++ b/src/main/generated/data/minecraft/item/salmon_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_fish", - "entity": { - "entity": "minecraft:salmon", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:salmon", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_fish", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/tadpole_bucket.json b/src/main/generated/data/minecraft/item/tadpole_bucket.json index 120344c6..35c81622 100644 --- a/src/main/generated/data/minecraft/item/tadpole_bucket.json +++ b/src/main/generated/data/minecraft/item/tadpole_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_tadpole", - "entity": { - "entity": "minecraft:tadpole", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:tadpole", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_tadpole", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/tropical_fish_bucket.json b/src/main/generated/data/minecraft/item/tropical_fish_bucket.json index d2774573..c04c3174 100644 --- a/src/main/generated/data/minecraft/item/tropical_fish_bucket.json +++ b/src/main/generated/data/minecraft/item/tropical_fish_bucket.json @@ -1,13 +1,13 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty_fish", - "entity": { - "entity": "minecraft:tropical_fish", - "require_other_successful_placement": true - }, - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "entity": "minecraft:tropical_fish", + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty_fish", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/generated/data/minecraft/item/water_bucket.json b/src/main/generated/data/minecraft/item/water_bucket.json index 1cb1ac31..c5c457bc 100644 --- a/src/main/generated/data/minecraft/item/water_bucket.json +++ b/src/main/generated/data/minecraft/item/water_bucket.json @@ -1,9 +1,12 @@ { "behavior": { "minecraft:bucket": { - "emptying_sound_event": "minecraft:item.bucket.empty", - "fluid": "minecraft:water", - "transforms_into": "minecraft:bucket" + "modification": { + "type": "minecraft:place_fluid", + "fluid": "minecraft:water", + "place_sound": "minecraft:item.bucket.empty", + "transforms_into": "minecraft:bucket" + } }, "minecraft:dispensable": { "behavior": "minecraft:use_bucket" diff --git a/src/main/java/net/errorcraft/itematic/Itematic.java b/src/main/java/net/errorcraft/itematic/Itematic.java index 52a2e04a..407de364 100644 --- a/src/main/java/net/errorcraft/itematic/Itematic.java +++ b/src/main/java/net/errorcraft/itematic/Itematic.java @@ -1,6 +1,7 @@ package net.errorcraft.itematic; import net.errorcraft.itematic.component.ItematicDataComponentTypes; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.event.ItemEvents; import net.errorcraft.itematic.item.holder.rule.ItemHolderRuleTypes; @@ -47,5 +48,6 @@ public void onInitialize() { ItematicRecipeDisplaySerializers.init(); ItematicSlotDisplaySerializers.init(); ItematicEntitySubPredicateTypes.init(); + WorldModificationTypes.init(); } } diff --git a/src/main/java/net/errorcraft/itematic/fluid/FluidKeys.java b/src/main/java/net/errorcraft/itematic/fluid/FluidKeys.java index 6d7fb5de..1116585d 100644 --- a/src/main/java/net/errorcraft/itematic/fluid/FluidKeys.java +++ b/src/main/java/net/errorcraft/itematic/fluid/FluidKeys.java @@ -6,7 +6,6 @@ import net.minecraft.util.Identifier; public class FluidKeys { - public static final RegistryKey EMPTY = of("empty"); public static final RegistryKey WATER = of("water"); public static final RegistryKey LAVA = of("lava"); diff --git a/src/main/java/net/errorcraft/itematic/fluid/FluidUtil.java b/src/main/java/net/errorcraft/itematic/fluid/FluidUtil.java new file mode 100644 index 00000000..05f3ce25 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/fluid/FluidUtil.java @@ -0,0 +1,49 @@ +package net.errorcraft.itematic.fluid; + +import net.errorcraft.itematic.util.context.ItematicContextParameters; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.Nullable; + +public class FluidUtil { + private FluidUtil() {} + + @Nullable + public static BlockPos getPlacementPosition(ActionContext context, PositionTarget position) { + BlockPos pos = context.get(position.parameter(), BlockPos::ofFloored); + if (pos == null) { + return null; + } + + if (!canPlaceAt(context, pos)) { + return null; + } + + return pos; + } + + private static boolean canPlaceAt(ActionContext context, BlockPos pos) { + Entity placer = context.get(LootContextParameters.THIS_ENTITY); + if (placer == null) { + return true; + } + + if (!context.world().canEntityModifyAt(placer, pos)) { + return false; + } + + Direction direction = context.getOrDefault(ItematicContextParameters.SIDE, Direction.UP); + return !(placer instanceof PlayerEntity player) || + player.canPlaceOn( + pos.offset(direction), + direction, + context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY) + ); + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/ItemUtil.java b/src/main/java/net/errorcraft/itematic/item/ItemUtil.java index 3ca5c5d1..5b461c02 100644 --- a/src/main/java/net/errorcraft/itematic/item/ItemUtil.java +++ b/src/main/java/net/errorcraft/itematic/item/ItemUtil.java @@ -10085,63 +10085,63 @@ private void bootstrapBuckets() { this.registerable.register(ItemKeys.BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.fluid(this.fluids.getOrThrow(FluidKeys.EMPTY), this.dispenseBehaviors)) + .with(BucketItemComponent.drainFluid(this.dispenseBehaviors)) .with(DispensableItemComponent.of(this.dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET))) .build() )); this.registerable.register(ItemKeys.WATER_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.WATER_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.fluid(this.fluids.getOrThrow(FluidKeys.WATER), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluid(this.fluids.getOrThrow(FluidKeys.WATER), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.LAVA_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.LAVA_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.fluid(this.fluids.getOrThrow(FluidKeys.LAVA), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_LAVA), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluid(this.fluids.getOrThrow(FluidKeys.LAVA), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_LAVA), this.items, this.dispenseBehaviors)) .with(FuelItemComponent.of(FuelTimes.LAVA, this.items.getOrThrow(ItemKeys.BUCKET))) .build() )); this.registerable.register(ItemKeys.POWDER_SNOW_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.POWDER_SNOW_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.block(this.blocks.getOrThrow(BlockKeys.POWDER_SNOW), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_POWDER_SNOW), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeBlock(this.blocks.getOrThrow(BlockKeys.POWDER_SNOW), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_POWDER_SNOW), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.PUFFERFISH_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.PUFFERFISH_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.PUFFERFISH), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.PUFFERFISH), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.SALMON_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.SALMON_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.SALMON), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.SALMON), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.COD_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.COD_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.COD), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.COD), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.TROPICAL_FISH_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.TROPICAL_FISH_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.TROPICAL_FISH), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.TROPICAL_FISH), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_FISH), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.AXOLOTL_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.AXOLOTL_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.AXOLOTL), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_AXOLOTL), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.AXOLOTL), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_AXOLOTL), this.items, this.dispenseBehaviors)) .build() )); this.registerable.register(ItemKeys.TADPOLE_BUCKET, create( ItemDisplay.Builder.forItem(ItemKeys.TADPOLE_BUCKET).build(), ItemComponentSet.builder() - .with(BucketItemComponent.entity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.TADPOLE), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_TADPOLE), this.items, this.dispenseBehaviors)) + .with(BucketItemComponent.placeFluidWithEntity(this.fluids.getOrThrow(FluidKeys.WATER), this.entityTypes.getOrThrow(EntityTypeKeys.TADPOLE), this.soundEvents.getOrThrow(SoundEventKeys.BUCKET_EMPTY_TADPOLE), this.items, this.dispenseBehaviors)) .build() )); } diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java new file mode 100644 index 00000000..08233618 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java @@ -0,0 +1,21 @@ +package net.errorcraft.itematic.item.bucket.modification; + +import com.mojang.serialization.Codec; +import net.errorcraft.itematic.registry.ItematicRegistries; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.item.ItemStack; +import net.minecraft.world.RaycastContext; + +import java.util.Optional; + +public interface WorldModification { + Codec CODEC = ItematicRegistries.WORLD_MODIFICATION_TYPE.getCodec().dispatch( + WorldModification::type, + WorldModificationType::codec + ); + + WorldModificationType type(); + Optional modify(ActionContext context, PositionTarget position, boolean mayOffset); + RaycastContext.FluidHandling fluidHandling(); +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java new file mode 100644 index 00000000..5cf48b6c --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java @@ -0,0 +1,6 @@ +package net.errorcraft.itematic.item.bucket.modification; + +import com.mojang.serialization.MapCodec; + +public record WorldModificationType(MapCodec codec) { +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java new file mode 100644 index 00000000..f45e6005 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java @@ -0,0 +1,21 @@ +package net.errorcraft.itematic.item.bucket.modification; + +import net.errorcraft.itematic.item.bucket.modification.type.DrainFluid; +import net.errorcraft.itematic.item.bucket.modification.type.PlaceBlock; +import net.errorcraft.itematic.item.bucket.modification.type.PlaceFluid; +import net.errorcraft.itematic.registry.ItematicRegistries; +import net.minecraft.registry.Registry; + +public class WorldModificationTypes { + public static final WorldModificationType DRAIN_FLUID = register("drain_fluid", new WorldModificationType<>(DrainFluid.CODEC)); + public static final WorldModificationType PLACE_FLUID = register("place_fluid", new WorldModificationType<>(PlaceFluid.CODEC)); + public static final WorldModificationType PLACE_BLOCK = register("place_block", new WorldModificationType<>(PlaceBlock.CODEC)); + + private WorldModificationTypes() {} + + public static void init() {} + + private static WorldModificationType register(String id, WorldModificationType type) { + return Registry.register(ItematicRegistries.WORLD_MODIFICATION_TYPE, id, type); + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java new file mode 100644 index 00000000..72233901 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java @@ -0,0 +1,40 @@ +package net.errorcraft.itematic.item.bucket.modification.type; + +import com.mojang.serialization.MapCodec; +import net.errorcraft.itematic.item.bucket.modification.WorldModification; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; +import net.errorcraft.itematic.item.placement.fluid.FluidDrainer; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.item.ItemStack; +import net.minecraft.world.RaycastContext; + +import java.util.Optional; + +public class DrainFluid implements WorldModification { + public static final DrainFluid INSTANCE = new DrainFluid(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); + + private DrainFluid() {} + + @Override + public WorldModificationType type() { + return WorldModificationTypes.DRAIN_FLUID; + } + + @Override + public Optional modify(ActionContext context, PositionTarget position, boolean mayOffset) { + ItemStack drainedStack = new FluidDrainer(context, position).drain(); + if (drainedStack == null) { + return Optional.empty(); + } + + return Optional.of(drainedStack); + } + + @Override + public RaycastContext.FluidHandling fluidHandling() { + return RaycastContext.FluidHandling.SOURCE_ONLY; + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java new file mode 100644 index 00000000..3943d687 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java @@ -0,0 +1,58 @@ +package net.errorcraft.itematic.item.bucket.modification.type; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.errorcraft.itematic.item.bucket.modification.WorldModification; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; +import net.errorcraft.itematic.item.placement.BlockPlacer; +import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryFixedCodec; +import net.minecraft.sound.SoundEvent; +import net.minecraft.world.RaycastContext; + +import java.util.Optional; + +public record PlaceBlock(BlockPicker block, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + BlockPicker.CODEC.fieldOf("block").forGetter(PlaceBlock::block), + SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceBlock::placeSound), + RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceBlock::transformsInto) + ).apply(instance, PlaceBlock::new)); + + @Override + public WorldModificationType type() { + return WorldModificationTypes.PLACE_BLOCK; + } + + @Override + public Optional modify(ActionContext context, PositionTarget position, boolean mayOffset) { + BlockPlacer placer = BlockPlacer.action( + context, + PositionTarget.INTERACTED_POSITION, + this.block, + false, + this.placeSound + ); + if (placer == null) { + return Optional.empty(); + } + + if (!placer.place().succeeds()) { + return Optional.empty(); + } + + return Optional.of(new ItemStack(this.transformsInto)); + } + + @Override + public RaycastContext.FluidHandling fluidHandling() { + return RaycastContext.FluidHandling.NONE; + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java new file mode 100644 index 00000000..8a8e1a38 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java @@ -0,0 +1,54 @@ +package net.errorcraft.itematic.item.bucket.modification.type; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.errorcraft.itematic.item.bucket.modification.WorldModification; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; +import net.errorcraft.itematic.item.placement.fluid.FluidPlacer; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.fluid.Fluid; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryFixedCodec; +import net.minecraft.sound.SoundEvent; +import net.minecraft.world.RaycastContext; + +import java.util.Optional; + +public record PlaceFluid(RegistryEntry fluid, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + RegistryFixedCodec.of(RegistryKeys.FLUID).fieldOf("fluid").forGetter(PlaceFluid::fluid), + SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceFluid::placeSound), + RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceFluid::transformsInto) + ).apply(instance, PlaceFluid::new)); + + @Override + public WorldModificationType type() { + return WorldModificationTypes.PLACE_FLUID; + } + + @Override + public Optional modify(ActionContext context, PositionTarget position, boolean mayOffset) { + FluidPlacer placer = new FluidPlacer( + context, + position, + this.fluid, + this.placeSound, + mayOffset + ); + if (placer.place()) { + return Optional.of(new ItemStack(this.transformsInto)); + } + + return Optional.empty(); + } + + @Override + public RaycastContext.FluidHandling fluidHandling() { + return RaycastContext.FluidHandling.NONE; + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java index 27cef2ea..f5edf3e8 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java @@ -2,19 +2,19 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.errorcraft.itematic.fluid.FluidKeys; import net.errorcraft.itematic.item.ItemKeys; import net.errorcraft.itematic.item.ItemResult; +import net.errorcraft.itematic.item.ItemStackUtil; +import net.errorcraft.itematic.item.bucket.modification.WorldModification; +import net.errorcraft.itematic.item.bucket.modification.type.DrainFluid; +import net.errorcraft.itematic.item.bucket.modification.type.PlaceBlock; +import net.errorcraft.itematic.item.bucket.modification.type.PlaceFluid; import net.errorcraft.itematic.item.component.ItemComponent; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.dispense.behavior.DispenseBehavior; import net.errorcraft.itematic.item.dispense.behavior.DispenseBehaviors; -import net.errorcraft.itematic.item.placement.BlockPlacer; import net.errorcraft.itematic.item.placement.EntityPlacer; -import net.errorcraft.itematic.item.placement.FluidPlacer; -import net.errorcraft.itematic.item.placement.Placer; -import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; import net.errorcraft.itematic.item.placement.block.picker.pickers.SimpleBlockPicker; import net.errorcraft.itematic.mixin.item.ItemAccessor; import net.errorcraft.itematic.util.context.ItematicContextParameters; @@ -25,69 +25,71 @@ import net.minecraft.component.ComponentMap; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.NbtComponent; -import net.minecraft.entity.Bucketable; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.*; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.Fluid; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUsageContext; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryEntryLookup; -import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.registry.entry.RegistryFixedCodec; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvent; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; -import net.minecraft.world.RaycastContext; import net.minecraft.world.World; -import org.jetbrains.annotations.Nullable; import java.util.Optional; -public record BucketItemComponent(Optional> fluid, Optional entity, Optional> block, Optional> emptyingSound, Optional> transformsInto) implements ItemComponent { +public record BucketItemComponent(WorldModification modification, Optional>> entity) implements ItemComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - RegistryFixedCodec.of(RegistryKeys.FLUID).optionalFieldOf("fluid").forGetter(BucketItemComponent::fluid), - EntityTarget.CODEC.optionalFieldOf("entity").forGetter(BucketItemComponent::entity), - BlockPicker.CODEC.optionalFieldOf("block").forGetter(BucketItemComponent::block), - SoundEvent.ENTRY_CODEC.optionalFieldOf("emptying_sound_event").forGetter(BucketItemComponent::emptyingSound), - RegistryFixedCodec.of(RegistryKeys.ITEM).optionalFieldOf("transforms_into").forGetter(BucketItemComponent::transformsInto) + WorldModification.CODEC.fieldOf("modification").forGetter(BucketItemComponent::modification), + Registries.ENTITY_TYPE.getEntryCodec().optionalFieldOf("entity").forGetter(BucketItemComponent::entity) ).apply(instance, BucketItemComponent::new)); - public static ItemComponent[] fluid(RegistryEntry fluid, RegistryEntryLookup dispenseBehaviors) { + + public static ItemComponent[] drainFluid(RegistryEntryLookup dispenseBehaviors) { return new ItemComponent[] { StackableItemComponent.of(16), - new BucketItemComponent(Optional.of(fluid), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()), + new BucketItemComponent( + DrainFluid.INSTANCE, + Optional.empty() + ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) }; } - public static ItemComponent[] fluid(RegistryEntry fluid, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { + public static ItemComponent[] placeFluid(RegistryEntry fluid, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { return new ItemComponent[] { StackableItemComponent.of(1), - new BucketItemComponent(Optional.of(fluid), Optional.empty(), Optional.empty(), Optional.of(emptyingSound), Optional.of(items.getOrThrow(ItemKeys.BUCKET))), + new BucketItemComponent( + new PlaceFluid(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + Optional.empty() + ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) }; } - public static ItemComponent[] entity(RegistryEntry fluid, RegistryEntry> entity, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { + public static ItemComponent[] placeFluidWithEntity(RegistryEntry fluid, RegistryEntry> entity, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { return new ItemComponent[] { StackableItemComponent.of(1), - new BucketItemComponent(Optional.of(fluid), Optional.of(EntityTarget.ofRequired(entity)), Optional.empty(), Optional.of(emptyingSound), Optional.of(items.getOrThrow(ItemKeys.BUCKET))), + new BucketItemComponent( + new PlaceFluid(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + Optional.of(entity) + ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) }; } - public static ItemComponent[] block(RegistryEntry block, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { + public static ItemComponent[] placeBlock(RegistryEntry block, RegistryEntry emptyingSound, RegistryEntryLookup items, RegistryEntryLookup dispenseBehaviors) { return new ItemComponent[] { StackableItemComponent.of(1), - new BucketItemComponent(Optional.empty(), Optional.empty(), Optional.of(new SimpleBlockPicker(block)), Optional.of(emptyingSound), Optional.of(items.getOrThrow(ItemKeys.BUCKET))), + new BucketItemComponent( + new PlaceBlock(new SimpleBlockPicker(block), emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + Optional.empty() + ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) }; } @@ -104,12 +106,29 @@ public Codec codec() { @Override public ItemResult use(World world, PlayerEntity user, Hand hand, ItemStack stack, ItemStackExchanger stackExchanger) { - BlockHitResult blockHitResult = ItemAccessor.raycast(world, user, this.getFluidHandling()); + if (world.isClient()) { + return ItemResult.PASS; + } + + BlockHitResult blockHitResult = ItemAccessor.raycast(world, user, this.modification().fluidHandling()); if (blockHitResult.getType() != HitResult.Type.BLOCK) { return ItemResult.PASS; } - return this.place(world, user, hand, stack, stackExchanger, blockHitResult); + ActionContext context = ActionContext.builder((ServerWorld) world) + .stackExchanger(stackExchanger) + .addOptional(LootContextParameters.THIS_ENTITY, user) + .addOptional(LootContextParameters.ORIGIN, user, Entity::getPos) + .add(ItematicContextParameters.INTERACTED_POSITION, blockHitResult.getBlockPos().toCenterPos()) + .add(LootContextParameters.TOOL, stack) + .add(ItematicContextParameters.HAND, hand) + .add(ItematicContextParameters.SIDE, blockHitResult.getSide()) + .build(); + if (this.use(context, PositionTarget.INTERACTED_POSITION, !blockHitResult.isInsideBlock())) { + return ItemResult.CONSUME; + } + + return ItemResult.PASS; } @Override @@ -119,95 +138,37 @@ public void addComponents(ComponentMap.Builder builder) { } } - public ItemResult place(World world, @Nullable PlayerEntity user, Hand hand, ItemStack stack, ItemStackExchanger stackExchanger, BlockHitResult blockHitResult) { - ItemResult result = ItemResult.PASS; - if (this.fluid.isPresent()) { - FluidPlacer fluidPlacer = FluidPlacer.of(stack, stackExchanger, world, blockHitResult, user, this.fluid.get(), this.emptyingSound.orElse(null)); - result = place(fluidPlacer, result); - } - - if (this.block.isPresent()) { - ItemUsageContext context = new ItemUsageContext(world, user, hand, stack, blockHitResult); - BlockPlacer blockPlacer = BlockPlacer.of(context, stackExchanger, this.block.get(), false, false); - result = place(blockPlacer, result); - } - - result = this.tryPlaceEntity(world, user, hand, stack, blockHitResult, stackExchanger, result); - if (result.succeeds()) { - stack.decrementUnlessCreative(1, user); - this.transformsInto.map(ItemStack::new).ifPresent(stackExchanger::exchange); - } - - return result; - } - - private RaycastContext.FluidHandling getFluidHandling() { - if (this.fluid.isEmpty()) { - return RaycastContext.FluidHandling.NONE; - } - - if (this.fluid.get().matchesKey(FluidKeys.EMPTY)) { - return RaycastContext.FluidHandling.SOURCE_ONLY; - } - - return RaycastContext.FluidHandling.NONE; - } - - private ItemResult tryPlaceEntity(World world, @Nullable PlayerEntity user, Hand hand, ItemStack stack, BlockHitResult blockHitResult, ItemStackExchanger stackExchanger, ItemResult currentResult) { - if (this.entity.isEmpty()) { - return currentResult; - } - - EntityTarget target = this.entity.get(); - if (target.requireOtherSuccessfulPlacement && !currentResult.succeeds()) { - return currentResult; + public boolean use(ActionContext context, PositionTarget position, boolean mayOffset) { + Optional result = this.modification.modify(context, position, mayOffset); + if (result.isEmpty()) { + return false; } - if (world.isClient()) { - return currentResult; - } - - ActionContext context = ActionContext.builder((ServerWorld) world) - .stackExchanger(stackExchanger) - .addOptional(LootContextParameters.THIS_ENTITY, user) - .addOptional(LootContextParameters.ORIGIN, user, Entity::getPos) - .add(ItematicContextParameters.INTERACTED_POSITION, blockHitResult.getBlockPos().toCenterPos()) - .add(LootContextParameters.TOOL, stack) - .add(ItematicContextParameters.HAND, hand) - .add(ItematicContextParameters.SIDE, blockHitResult.getSide()) - .build(); - EntityPlacer.of( - target.entity.value(), + this.entity.ifPresent(entity -> EntityPlacer.of( + entity.value(), context, false, SpawnReason.BUCKET, BucketItemComponent::initializeBucketEntity, true, PositionTarget.INTERACTED_POSITION - ).place(); - return ItemResult.CONSUME; - } + ).place()); + ItemStack stack = context.get(LootContextParameters.TOOL); + if (!ItemStackUtil.isNullOrEmpty(stack)) { + stack.decrementUnlessCreative( + 1, + context.get(LootContextParameters.THIS_ENTITY, LivingEntity.class) + ); + } - private static ItemResult place(Placer placer, ItemResult currentResult) { - ItemResult result = placer.place(); - return currentResult.max(result); + context.exchangeStack(result.get()); + return true; } - public static void initializeBucketEntity(Entity entity, ItemStack stack) { + private static void initializeBucketEntity(Entity entity, ItemStack stack) { if (entity instanceof Bucketable bucketable) { bucketable.copyDataFromNbt(stack.getOrDefault(DataComponentTypes.BUCKET_ENTITY_DATA, NbtComponent.DEFAULT).copyNbt()); bucketable.setFromBucket(true); } } - - public record EntityTarget(RegistryEntry> entity, boolean requireOtherSuccessfulPlacement) { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Registries.ENTITY_TYPE.getEntryCodec().fieldOf("entity").forGetter(EntityTarget::entity), - Codec.BOOL.optionalFieldOf("require_other_successful_placement", false).forGetter(EntityTarget::requireOtherSuccessfulPlacement) - ).apply(instance, EntityTarget::new)); - - public static EntityTarget ofRequired(RegistryEntry> entity) { - return new EntityTarget(entity, true); - } - } } diff --git a/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java index a38618ae..83b9f083 100644 --- a/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java +++ b/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java @@ -22,9 +22,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -36,16 +38,23 @@ public class BlockPlacer extends Placer { private final ItemPlacementContext context; private final boolean operatorOnly; private final boolean decrementStack; + @Nullable + private final RegistryEntry placeSound; - private BlockPlacer(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockPos blockPos, BlockState blockState, PlayerEntity player, BlockPicker block, ItemPlacementContext context, boolean operatorOnly, boolean decrementStack) { + private BlockPlacer(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockPos blockPos, BlockState blockState, PlayerEntity player, BlockPicker block, ItemPlacementContext context, boolean operatorOnly, boolean decrementStack, @Nullable RegistryEntry placeSound) { super(stack, stackExchanger, world, blockPos, blockState, player); this.block = block; this.context = context; this.operatorOnly = operatorOnly; this.decrementStack = decrementStack; + this.placeSound = placeSound; } public static BlockPlacer action(ActionContext context, PositionTarget position, BlockPicker block, boolean decrementCount) { + return action(context, position, block, decrementCount, null); + } + + public static BlockPlacer action(ActionContext context, PositionTarget position, BlockPicker block, boolean decrementCount, RegistryEntry placeSound) { ItemPlacementContext placeContext = context.blockPlaceContext(position, block); if (placeContext == null) { return null; @@ -66,7 +75,8 @@ public static BlockPlacer action(ActionContext context, PositionTarget position, block, placeContext, false, - decrementCount + decrementCount, + null ); } @@ -81,7 +91,19 @@ public static BlockPlacer of(ItemUsageContext context, ItemStackExchanger stackE public static BlockPlacer of(ItemPlacementContext context, ItemStackExchanger stackExchanger, BlockPicker block, boolean operatorOnly, boolean decrementStack) { World world = context.getWorld(); BlockPos blockPos = context.getBlockPos(); - return new BlockPlacer(context.getStack(), stackExchanger, world, blockPos, world.getBlockState(blockPos), context.getPlayer(), block, context, operatorOnly, decrementStack); + return new BlockPlacer( + context.getStack(), + stackExchanger, + world, + blockPos, + world.getBlockState(blockPos), + context.getPlayer(), + block, + context, + operatorOnly, + decrementStack, + null + ); } @Override @@ -126,13 +148,21 @@ private void placed(BlockState blockState) { } BlockSoundGroup blockSoundGroup = blockState.getSoundGroup(); - this.world.playSound(this.player, this.blockPos, blockSoundGroup.getPlaceSound(), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); + this.world.playSound(this.player, this.blockPos, this.placeSound(blockSoundGroup), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); this.world.emitGameEvent(GameEvent.BLOCK_PLACE, this.blockPos, GameEvent.Emitter.of(this.player, blockState)); if (this.decrementStack) { this.tryDecrementStack(); } } + private SoundEvent placeSound(BlockSoundGroup group) { + if (this.placeSound != null) { + return this.placeSound.value(); + } + + return group.getPlaceSound(); + } + @Nullable private BlockState getPlacementState() { if (this.operatorOnly && this.player != null && !this.player.isCreativeLevelTwoOp()) { diff --git a/src/main/java/net/errorcraft/itematic/item/placement/FluidPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/FluidPlacer.java deleted file mode 100644 index 1f8d381b..00000000 --- a/src/main/java/net/errorcraft/itematic/item/placement/FluidPlacer.java +++ /dev/null @@ -1,187 +0,0 @@ -package net.errorcraft.itematic.item.placement; - -import net.errorcraft.itematic.fluid.FluidKeys; -import net.errorcraft.itematic.item.ItemResult; -import net.errorcraft.itematic.world.action.context.ItemStackExchanger; -import net.minecraft.advancement.criterion.Criteria; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.FluidDrainable; -import net.minecraft.block.FluidFillable; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.FlowableFluid; -import net.minecraft.fluid.Fluid; -import net.minecraft.item.ItemStack; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.registry.tag.FluidTags; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvent; -import net.minecraft.sound.SoundEvents; -import net.minecraft.stat.Stats; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; -import net.minecraft.world.event.GameEvent; - -public class FluidPlacer extends Placer { - private final RegistryEntry fluid; - private final RegistryEntry emptyingSound; - private final Direction direction; - private final boolean allowOffset; - - private FluidPlacer(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockPos blockPos, BlockState blockState, PlayerEntity player, RegistryEntry fluid, RegistryEntry emptyingSound, Direction direction, boolean allowOffset) { - super(stack, stackExchanger, world, blockPos, blockState, player); - this.fluid = fluid; - this.emptyingSound = emptyingSound; - this.direction = direction; - this.allowOffset = allowOffset; - } - - public static FluidPlacer of(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockHitResult hitResult, PlayerEntity player, RegistryEntry fluid, RegistryEntry emptyingSound) { - BlockPos blockPos = hitResult.getBlockPos(); - return new FluidPlacer(stack, stackExchanger, world, blockPos, world.getBlockState(blockPos), player, fluid, emptyingSound, hitResult.getSide(), !hitResult.isInsideBlock()); - } - - @Override - public ItemResult place() { - BlockPos offset = this.blockPos.offset(this.direction); - if (this.player != null && (!this.world.canEntityModifyAt(this.player, this.blockPos) || !this.player.canPlaceOn(offset, this.direction, this.stack))) { - return ItemResult.PASS; - } - - if (this.fluid.matchesKey(FluidKeys.EMPTY)) { - return this.tryDrainFluid(); - } - - BlockPos actualBlockPos = this.getActualPosition(offset); - if (!this.tryPlaceFluid(actualBlockPos, this.allowOffset)) { - return ItemResult.PASS; - } - - return ItemResult.SUCCEED; - } - - private BlockPos getActualPosition(BlockPos offset) { - if (!this.allowOffset) { - return this.blockPos; - } - - if (this.blockState.getBlock() instanceof FluidFillable && this.fluid.matchesKey(FluidKeys.WATER)) { - return this.blockPos; - } - - return offset; - } - - private ItemResult tryDrainFluid() { - if (!(this.blockState.getBlock() instanceof FluidDrainable fluidDrainable)) { - return ItemResult.PASS; - } - - ItemStack drainedItemStack = fluidDrainable.tryDrainFluid(this.player, this.world, this.blockPos, this.blockState); - if (drainedItemStack.isEmpty()) { - return ItemResult.PASS; - } - - this.applyPlayerEffects(fluidDrainable, drainedItemStack); - this.world.emitGameEvent(this.player, GameEvent.FLUID_PICKUP, this.blockPos); - this.stackExchanger.exchange(drainedItemStack); - return ItemResult.SUCCEED; - } - - private void applyPlayerEffects(FluidDrainable fluidDrainable, ItemStack drainedItemStack) { - if (this.player == null) { - return; - } - - this.player.incrementStat(Stats.USED.itematic$getOrCreateStat(stack.getRegistryEntry())); - fluidDrainable.getBucketFillSound().ifPresent(sound -> this.player.playSound(sound, 1.0f, 1.0f)); - if (this.player instanceof ServerPlayerEntity serverPlayer) { - Criteria.FILLED_BUCKET.trigger(serverPlayer, drainedItemStack); - } - } - - @SuppressWarnings("deprecation") - private boolean tryPlaceFluid(BlockPos pos, boolean allowOffset) { - Fluid fluid = this.fluid.value(); - if (!(fluid instanceof FlowableFluid flowableFluid)) { - return false; - } - - BlockState blockState = this.world.getBlockState(pos); - boolean canPlace = blockState.canBucketPlace(fluid); - if (!blockState.isAir() && !canPlace && !(blockState.getBlock() instanceof FluidFillable fluidFillable && fluidFillable.canFillWithFluid(this.player, this.world, pos, blockState, fluid))) { - return allowOffset && this.tryPlaceFluid(this.blockPos.offset(this.direction), false); - } - - if (this.tryEvaporate(pos)) { - return true; - } - - if (this.tryFillWater(blockState, pos, flowableFluid)) { - return true; - } - - if (!this.world.isClient() && canPlace && !blockState.isLiquid()) { - this.world.breakBlock(pos, true); - } - - if (this.world.setBlockState(pos, fluid.getDefaultState().getBlockState(), Block.NOTIFY_ALL_AND_REDRAW) || blockState.getFluidState().isStill()) { - this.playEmptyingSound(pos); - return true; - } - - return false; - } - - private boolean tryEvaporate(BlockPos pos) { - if (!this.world.getDimension().ultrawarm()) { - return false; - } - - if (!this.fluid.isIn(FluidTags.WATER)) { - return false; - } - - this.world.playSound(this.player, pos, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5f, 2.6f + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.8f); - for (int i = 0; i < 8; i++) { - this.world.addParticleClient( - ParticleTypes.LARGE_SMOKE, - pos.getX() + Math.random(), - pos.getY() + Math.random(), - pos.getZ() + Math.random(), - 0.0d, - 0.0d, - 0.0d - ); - } - - return true; - } - - private boolean tryFillWater(BlockState blockState, BlockPos pos, FlowableFluid flowableFluid) { - if (!(blockState.getBlock() instanceof FluidFillable fluidFillable)) { - return false; - } - - if (!this.fluid.matchesKey(FluidKeys.WATER)) { - return false; - } - - fluidFillable.tryFillWithFluid(this.world, pos, blockState, flowableFluid.getStill(false)); - this.playEmptyingSound(pos); - return true; - } - - private void playEmptyingSound(BlockPos pos) { - if (this.emptyingSound == null) { - return; - } - - this.world.playSound(this.player, pos, this.emptyingSound.value(), SoundCategory.BLOCKS, 1.0f, 1.0f); - this.world.emitGameEvent(this.player, GameEvent.FLUID_PLACE, pos); - } -} diff --git a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java new file mode 100644 index 00000000..62e844ed --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java @@ -0,0 +1,74 @@ +package net.errorcraft.itematic.item.placement.fluid; + +import net.errorcraft.itematic.fluid.FluidUtil; +import net.errorcraft.itematic.item.ItemStackUtil; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.advancement.criterion.Criteria; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidDrainable; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.stat.Stats; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.event.GameEvent; +import org.jetbrains.annotations.Nullable; + +public class FluidDrainer { + private final ActionContext context; + private final PositionTarget position; + + public FluidDrainer(ActionContext context, PositionTarget position) { + this.context = context; + this.position = position; + } + + @Nullable + public ItemStack drain() { + BlockPos pos = FluidUtil.getPlacementPosition(this.context, this.position); + if (pos == null) { + return null; + } + + ServerWorld world = this.context.world(); + BlockState state = world.getBlockState(pos); + if (!(state.getBlock() instanceof FluidDrainable fluidDrainable)) { + return null; + } + + Entity placer = this.context.get(LootContextParameters.THIS_ENTITY); + ItemStack drainedItemStack = fluidDrainable.tryDrainFluid( + placer instanceof LivingEntity livingPlacer ? livingPlacer : null, + world, + pos, + state + ); + if (drainedItemStack.isEmpty()) { + return null; + } + + if (placer instanceof PlayerEntity playerPlacer) { + this.applyPlayerEffects(playerPlacer, fluidDrainable, drainedItemStack); + } + + world.emitGameEvent(placer, GameEvent.FLUID_PICKUP, pos); + return drainedItemStack; + } + + private void applyPlayerEffects(PlayerEntity player, FluidDrainable fluidDrainable, ItemStack drainedItemStack) { + ItemStack stack = this.context.get(LootContextParameters.TOOL); + if (!ItemStackUtil.isNullOrEmpty(stack)) { + player.incrementStat(Stats.USED.itematic$getOrCreateStat(stack.getRegistryEntry())); + } + + fluidDrainable.getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1.0f, 1.0f)); + if (player instanceof ServerPlayerEntity serverPlayer) { + Criteria.FILLED_BUCKET.trigger(serverPlayer, drainedItemStack); + } + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java new file mode 100644 index 00000000..13cc4ed3 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java @@ -0,0 +1,175 @@ +package net.errorcraft.itematic.item.placement.fluid; + +import net.errorcraft.itematic.fluid.FluidKeys; +import net.errorcraft.itematic.fluid.FluidUtil; +import net.errorcraft.itematic.util.context.ItematicContextParameters; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidFillable; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.Fluid; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.tag.FluidTags; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.event.GameEvent; + +public class FluidPlacer { + private final ActionContext context; + private final PositionTarget position; + private final RegistryEntry fluid; + private final RegistryEntry placeSound; + private final boolean mayOffset; + + public FluidPlacer(ActionContext context, PositionTarget position, RegistryEntry fluid, RegistryEntry placeSound, boolean mayOffset) { + this.context = context; + this.position = position; + this.fluid = fluid; + this.placeSound = placeSound; + this.mayOffset = mayOffset; + } + + public boolean place() { + BlockPos pos = FluidUtil.getPlacementPosition(this.context, this.position); + if (pos == null) { + return false; + } + + if (!this.shouldOffset(pos)) { + return this.tryPlaceFluid(pos); + } + + Direction direction = this.context.get(ItematicContextParameters.SIDE); + if (direction == null) { + return false; + } + + return this.tryPlaceFluid(pos.offset(direction)); + } + + private boolean shouldOffset(BlockPos pos) { + if (!this.mayOffset) { + return false; + } + + if (!this.fluid.matchesKey(FluidKeys.WATER)) { + return true; + } + + ServerWorld world = this.context.world(); + BlockState state = world.getBlockState(pos); + if (!(state.getBlock() instanceof FluidFillable fluidFillable)) { + return true; + } + + LivingEntity filler = this.context.get(LootContextParameters.THIS_ENTITY, LivingEntity.class); + return !fluidFillable.canFillWithFluid(filler, world, pos, state, this.fluid.value()); + } + + private boolean tryPlaceFluid(BlockPos pos) { + if (!(this.fluid.value() instanceof FlowableFluid flowableFluid)) { + return false; + } + + BlockState state = this.context.world().getBlockState(pos); + if (this.tryEvaporate(pos)) { + return true; + } + + if (this.tryFillWater(state, pos, flowableFluid)) { + return true; + } + + return this.tryPlaceFluidBlock(pos, state, flowableFluid); + } + + private boolean tryEvaporate(BlockPos pos) { + ServerWorld world = this.context.world(); + if (!world.getDimension().ultrawarm()) { + return false; + } + + if (!this.fluid.isIn(FluidTags.WATER)) { + return false; + } + + world.playSound( + this.context.get(LootContextParameters.THIS_ENTITY), + pos, + SoundEvents.BLOCK_FIRE_EXTINGUISH, + SoundCategory.BLOCKS, + 0.5f, + 2.6f + (world.random.nextFloat() - world.random.nextFloat()) * 0.8f + ); + + for (int i = 0; i < 8; i++) { + world.spawnParticles( + ParticleTypes.LARGE_SMOKE, + pos.getX() + Math.random(), + pos.getY() + Math.random(), + pos.getZ() + Math.random(), + 0, + 0.0d, + 0.0d, + 0.0d, + 0.0d + ); + } + + return true; + } + + private boolean tryFillWater(BlockState blockState, BlockPos pos, FlowableFluid flowableFluid) { + if (!(blockState.getBlock() instanceof FluidFillable fluidFillable)) { + return false; + } + + if (!this.fluid.matchesKey(FluidKeys.WATER)) { + return false; + } + + fluidFillable.tryFillWithFluid(this.context.world(), pos, blockState, flowableFluid.getStill(false)); + this.playPlaceSound(pos); + return true; + } + + @SuppressWarnings("deprecation") + private boolean tryPlaceFluidBlock(BlockPos pos, BlockState state, Fluid fluid) { + if (!state.canBucketPlace(fluid)) { + return false; + } + + ServerWorld world = this.context.world(); + if (!state.isAir() && !state.isLiquid()) { + world.breakBlock(pos, true); + } + + if (world.setBlockState(pos, fluid.getDefaultState().getBlockState(), Block.NOTIFY_ALL_AND_REDRAW) || state.getFluidState().isStill()) { + this.playPlaceSound(pos); + return true; + } + + return false; + } + + private void playPlaceSound(BlockPos pos) { + if (this.placeSound == null) { + return; + } + + ServerWorld world = this.context.world(); + Entity possiblePlacer = this.context.get(LootContextParameters.THIS_ENTITY); + world.playSound(possiblePlacer, pos, this.placeSound.value(), SoundCategory.BLOCKS, 1.0f, 1.0f); + world.emitGameEvent(possiblePlacer, GameEvent.FLUID_PLACE, pos); + } +} diff --git a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java index 5e9d8dcc..ec1f6ac3 100644 --- a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java +++ b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java @@ -1,5 +1,7 @@ package net.errorcraft.itematic.registry; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.event.ItemEvent; @@ -34,6 +36,7 @@ public class ItematicRegistries { public static final Registry> INTEGER_PROVIDER_TYPE = RegistriesAccessor.create(ItematicRegistryKeys.INTEGER_PROVIDER_TYPE, r -> IntegerProviderTypes.CONSTANT); public static final Registry> ITEM_HOLDER_RULE_TYPE = RegistriesAccessor.create(ItematicRegistryKeys.ITEM_HOLDER_RULE_TYPE, r -> ItemHolderRuleTypes.REJECT); public static final Registry> SHOOTER_METHOD_TYPE = RegistriesAccessor.create(ItematicRegistryKeys.SHOOTER_METHOD_TYPE, r -> ShooterMethodTypes.DIRECT); + public static final Registry> WORLD_MODIFICATION_TYPE = RegistriesAccessor.create(ItematicRegistryKeys.WORLD_MODIFICATION_TYPE, r -> WorldModificationTypes.DRAIN_FLUID); private ItematicRegistries() {} } diff --git a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java index 5bff8b39..b279cc1c 100644 --- a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java +++ b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java @@ -1,5 +1,6 @@ package net.errorcraft.itematic.registry; +import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.dispense.behavior.DispenseBehavior; import net.errorcraft.itematic.item.event.ItemEvent; @@ -33,6 +34,7 @@ public class ItematicRegistryKeys { public static final RegistryKey>> INTEGER_PROVIDER_TYPE = RegistryKey.ofRegistry(Identifier.ofVanilla("integer_provider_type")); public static final RegistryKey>> ITEM_HOLDER_RULE_TYPE = RegistryKey.ofRegistry(Identifier.ofVanilla("item_holder_rule_type")); public static final RegistryKey>> SHOOTER_METHOD_TYPE = RegistryKey.ofRegistry(Identifier.ofVanilla("shooter_method_type")); + public static final RegistryKey>> WORLD_MODIFICATION_TYPE = RegistryKey.ofRegistry(Identifier.ofVanilla("fluid_modification_type")); private ItematicRegistryKeys() {} } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/UseBucketAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/UseBucketAction.java index 790ee191..9e16fcb3 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/UseBucketAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/UseBucketAction.java @@ -3,21 +3,13 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.errorcraft.itematic.item.component.ItemComponentTypes; -import net.errorcraft.itematic.item.component.components.BucketItemComponent; -import net.errorcraft.itematic.util.context.ItematicContextParameters; import net.errorcraft.itematic.world.action.Action; import net.errorcraft.itematic.world.action.ActionType; import net.errorcraft.itematic.world.action.ActionTypes; import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.PositionTarget; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; public record UseBucketAction(PositionTarget position) implements Action { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -37,30 +29,7 @@ public ActionType type() { public boolean execute(ActionContext context) { ItemStack stack = context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY); return stack.itematic$getBehavior(ItemComponentTypes.BUCKET) - .map(bucket -> this.place(bucket, stack, context)) + .map(bucket -> bucket.use(context, this.position, false)) .orElse(false); } - - private boolean place(BucketItemComponent bucket, ItemStack stack, ActionContext context) { - Vec3d pos = context.get(this.position.parameter()); - if (pos == null) { - return false; - } - - Direction side = context.get(ItematicContextParameters.SIDE); - if (side == null) { - return false; - } - - Hand hand = context.getOrDefault(ItematicContextParameters.HAND, Hand.MAIN_HAND); - BlockHitResult hitResult = new BlockHitResult(pos, side, BlockPos.ofFloored(pos), true); - return bucket.place( - context.world(), - context.get(LootContextParameters.THIS_ENTITY) instanceof PlayerEntity player ? player : null, - hand, - stack, - context.stackExchanger(), - hitResult - ).succeeds(); - } } diff --git a/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java b/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java index ed85b986..5f1a39a6 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java +++ b/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java @@ -123,7 +123,6 @@ public ServerCommandSource commandSource(CommandFunctionManager functionManager, return source; } - @Nullable public ItemPlacementContext blockPlaceContext(PositionTarget position, BlockPicker block) { Vec3d pos = this.get(position.parameter()); From 8f9c10094a4935cdc5cde0fd2909f386626f4c66 Mon Sep 17 00:00:00 2001 From: ErrorCraft Date: Tue, 19 May 2026 01:00:37 +0200 Subject: [PATCH 2/4] Make BlockPlacer use ActionContext --- .../itematic/gametest/item/SignTestSuite.java | 22 +- .../BlockItemComponentTestSuite.java | 12 +- .../UseableOnFluidItemComponentTestSuite.java | 8 +- .../errorcraft/itematic/util/TestUtil.java | 25 ++- .../data/minecraft/action/light_block.json | 1 - .../net/errorcraft/itematic/Itematic.java | 2 +- .../item/ItemPlacementContextAccess.java | 10 +- ...apeContextUtil.java => ShapeContexts.java} | 8 +- .../modification/WorldModificationTypes.java | 21 -- .../components/BlockItemComponent.java | 44 +++- .../components/BucketItemComponent.java | 16 +- .../itematic/item/placement/BlockPlacer.java | 198 ------------------ .../itematic/item/placement/Placer.java | 35 ---- .../item/placement/block/BlockPlacer.java | 141 +++++++++++++ .../block/UseableOnFluidBlockExtender.java | 8 +- .../item/ItemPlacementContextExtender.java | 19 ++ .../itematic/registry/ItematicRegistries.java | 4 +- .../registry/ItematicRegistryKeys.java | 2 +- .../action/actions/PlaceBlockAction.java | 25 ++- .../actions/PlaceBlockFromItemAction.java | 8 +- .../modification/WorldModification.java | 2 +- .../modification/WorldModificationType.java | 2 +- .../modification/WorldModificationTypes.java | 21 ++ .../type/DrainFluidWorldModification.java} | 16 +- .../type/PlaceBlockWorldModification.java} | 31 ++- .../type/PlaceFluidWorldModification.java} | 20 +- src/main/resources/itematic.classtweaker | 1 + 27 files changed, 348 insertions(+), 354 deletions(-) rename src/main/java/net/errorcraft/itematic/block/{ShapeContextUtil.java => ShapeContexts.java} (59%) delete mode 100644 src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java delete mode 100644 src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java delete mode 100644 src/main/java/net/errorcraft/itematic/item/placement/Placer.java create mode 100644 src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java rename src/main/java/net/errorcraft/itematic/{item/bucket => world}/modification/WorldModification.java (92%) rename src/main/java/net/errorcraft/itematic/{item/bucket => world}/modification/WorldModificationType.java (69%) create mode 100644 src/main/java/net/errorcraft/itematic/world/modification/WorldModificationTypes.java rename src/main/java/net/errorcraft/itematic/{item/bucket/modification/type/DrainFluid.java => world/modification/type/DrainFluidWorldModification.java} (61%) rename src/main/java/net/errorcraft/itematic/{item/bucket/modification/type/PlaceBlock.java => world/modification/type/PlaceBlockWorldModification.java} (57%) rename src/main/java/net/errorcraft/itematic/{item/bucket/modification/type/PlaceFluid.java => world/modification/type/PlaceFluidWorldModification.java} (66%) diff --git a/src/gametest/java/net/errorcraft/itematic/gametest/item/SignTestSuite.java b/src/gametest/java/net/errorcraft/itematic/gametest/item/SignTestSuite.java index 668bdb9f..5b3aa2ed 100644 --- a/src/gametest/java/net/errorcraft/itematic/gametest/item/SignTestSuite.java +++ b/src/gametest/java/net/errorcraft/itematic/gametest/item/SignTestSuite.java @@ -27,11 +27,11 @@ public class SignTestSuite { @GameTest(structure = "itematic:item.sign.platform") public void placingSignOpensSignMenu(TestContext context) { ServerWorld world = context.getWorld(); - ItemStack oakSign = world.itematic$createStack(ItemKeys.OAK_SIGN); PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); - player.setStackInHand(Hand.MAIN_HAND, oakSign); + player.setPitch(90.0f); + player.setStackInHand(Hand.MAIN_HAND, world.itematic$createStack(ItemKeys.OAK_SIGN)); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, oakSign, GROUND_POSITION, Direction.UP); + TestUtil.useBlock(context, GROUND_POSITION, player, Direction.UP); context.addFinalTask(() -> { Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.OAK_SIGN); @@ -49,12 +49,13 @@ public void placingSignOpensSignMenu(TestContext context) { @SuppressWarnings("DataFlowIssue") public void placingSignWithBlockEntityDataDoesNotOpenSignMenu(TestContext context) { ServerWorld world = context.getWorld(); + PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); + player.setPitch(90.0f); ItemStack oakSign = world.itematic$createStack(ItemKeys.OAK_SIGN); NbtComponent.set(DataComponentTypes.BLOCK_ENTITY_DATA, oakSign, nbt -> nbt.putString(Entity.ID_KEY, Registries.BLOCK_ENTITY_TYPE.getId(BlockEntityType.SIGN).toString())); - PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); player.setStackInHand(Hand.MAIN_HAND, oakSign); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, oakSign, GROUND_POSITION, Direction.UP); + TestUtil.useBlock(context, GROUND_POSITION, player, Direction.UP); context.addFinalTaskWithDuration(1, () -> { Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.OAK_SIGN); @@ -71,11 +72,11 @@ public void placingSignWithBlockEntityDataDoesNotOpenSignMenu(TestContext contex @GameTest(structure = "itematic:item.sign.platform.ceiling") public void placingHangingSignOpensSignMenu(TestContext context) { ServerWorld world = context.getWorld(); - ItemStack oakHangingSign = world.itematic$createStack(ItemKeys.OAK_HANGING_SIGN); PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); - player.setStackInHand(Hand.MAIN_HAND, oakHangingSign); + player.setPitch(-90.0f); + player.setStackInHand(Hand.MAIN_HAND, world.itematic$createStack(ItemKeys.OAK_HANGING_SIGN)); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, oakHangingSign, ABOVE_PLACED_BLOCK_POSITION, Direction.DOWN); + TestUtil.useBlock(context, ABOVE_PLACED_BLOCK_POSITION, player, Direction.DOWN); context.addFinalTask(() -> { Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.OAK_HANGING_SIGN); @@ -93,12 +94,13 @@ public void placingHangingSignOpensSignMenu(TestContext context) { @SuppressWarnings("DataFlowIssue") public void placingHangingSignWithBlockEntityDataDoesNotOpenSignMenu(TestContext context) { ServerWorld world = context.getWorld(); + PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); + player.setPitch(-90.0f); ItemStack oakHangingSign = world.itematic$createStack(ItemKeys.OAK_HANGING_SIGN); NbtComponent.set(DataComponentTypes.BLOCK_ENTITY_DATA, oakHangingSign, nbt -> nbt.putString(Entity.ID_KEY, Registries.BLOCK_ENTITY_TYPE.getId(BlockEntityType.SIGN).toString())); - PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); player.setStackInHand(Hand.MAIN_HAND, oakHangingSign); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, oakHangingSign, ABOVE_PLACED_BLOCK_POSITION, Direction.DOWN); + TestUtil.useBlock(context, ABOVE_PLACED_BLOCK_POSITION, player, Direction.DOWN); context.addFinalTaskWithDuration(1, () -> { Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.OAK_HANGING_SIGN); diff --git a/src/gametest/java/net/errorcraft/itematic/gametest/item/component/BlockItemComponentTestSuite.java b/src/gametest/java/net/errorcraft/itematic/gametest/item/component/BlockItemComponentTestSuite.java index ed9ff439..45033da6 100644 --- a/src/gametest/java/net/errorcraft/itematic/gametest/item/component/BlockItemComponentTestSuite.java +++ b/src/gametest/java/net/errorcraft/itematic/gametest/item/component/BlockItemComponentTestSuite.java @@ -108,11 +108,11 @@ public void usingTallGrassOnGroundWhileBlockedOffDoesNotPlaceTallGrass(TestConte @GameTest(structure = "itematic:item.component.block.platform") public void usingSkeletonSkullOnGroundPlacesSkeletonSkull(TestContext context) { ServerWorld world = context.getWorld(); - ItemStack skeletonSkull = world.itematic$createStack(ItemKeys.SKELETON_SKULL); PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); - player.setStackInHand(Hand.MAIN_HAND, skeletonSkull); + player.setPitch(90.0f); + player.setStackInHand(Hand.MAIN_HAND, world.itematic$createStack(ItemKeys.SKELETON_SKULL)); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, skeletonSkull, GROUND_POSITION, Direction.UP); + TestUtil.useBlock(context, GROUND_POSITION, player, Direction.UP); context.addFinalTask(() -> Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.SKELETON_SKULL)); } @@ -132,11 +132,11 @@ public void usingSkeletonSkullOnWallPlacesSkeletonWallSkull(TestContext context) @GameTest(structure = "itematic:item.component.block.platform.ceiling") public void usingOakHangingSignOnCeilingPlacesOakHangingSign(TestContext context) { ServerWorld world = context.getWorld(); - ItemStack oakHangingSign = world.itematic$createStack(ItemKeys.OAK_HANGING_SIGN); PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); - player.setStackInHand(Hand.MAIN_HAND, oakHangingSign); + player.setPitch(-90.0f); + player.setStackInHand(Hand.MAIN_HAND, world.itematic$createStack(ItemKeys.OAK_HANGING_SIGN)); world.spawnEntity(player); - TestUtil.useStackOnBlockInside(context, player, oakHangingSign, ABOVE_PLACED_BLOCK_POSITION, Direction.DOWN); + TestUtil.useBlock(context, ABOVE_PLACED_BLOCK_POSITION, player, Direction.DOWN); context.addFinalTask(() -> Assert.blockState(context, PLACED_BLOCK_POSITION) .is(Blocks.OAK_HANGING_SIGN)); } diff --git a/src/gametest/java/net/errorcraft/itematic/gametest/item/component/UseableOnFluidItemComponentTestSuite.java b/src/gametest/java/net/errorcraft/itematic/gametest/item/component/UseableOnFluidItemComponentTestSuite.java index 3ff68041..b4c28ac3 100644 --- a/src/gametest/java/net/errorcraft/itematic/gametest/item/component/UseableOnFluidItemComponentTestSuite.java +++ b/src/gametest/java/net/errorcraft/itematic/gametest/item/component/UseableOnFluidItemComponentTestSuite.java @@ -30,9 +30,11 @@ public class UseableOnFluidItemComponentTestSuite { @GameTest(structure = "itematic:item.component.useable_on_fluid.water_hole") public void usingLilyPadWhileLookingAtWaterPlacesLilyPad(TestContext context) { - PlayerEntity player = context.createMockPlayer(GameMode.SURVIVAL); - TestUtil.setEntityPos(context, player, SPAWN_POSITION_ON_LAND); - player.lookAt(EntityAnchorArgumentType.EntityAnchor.EYES, Vec3d.ofBottomCenter(context.getAbsolutePos(LOOK_AT_WATER_POSITION_ON_LAND))); + PlayerEntity player = TestUtil.createMockPlayer(context, GameMode.SURVIVAL, SPAWN_POSITION_ON_LAND); + player.lookAt( + EntityAnchorArgumentType.EntityAnchor.EYES, + Vec3d.ofBottomCenter(context.getAbsolutePos(LOOK_AT_WATER_POSITION_ON_LAND)) + ); ServerWorld world = context.getWorld(); ItemStack lilyPad = world.itematic$createStack(ItemKeys.LILY_PAD); player.setStackInHand(Hand.MAIN_HAND, lilyPad); diff --git a/src/gametest/java/net/errorcraft/itematic/util/TestUtil.java b/src/gametest/java/net/errorcraft/itematic/util/TestUtil.java index 828a1fa8..e2cd7319 100644 --- a/src/gametest/java/net/errorcraft/itematic/util/TestUtil.java +++ b/src/gametest/java/net/errorcraft/itematic/util/TestUtil.java @@ -127,8 +127,18 @@ public static void setEntityPos(TestContext context, Entity entity, BlockPos pos public static Optional useStackOnBlockInside(TestContext context, PlayerEntity player, ItemStack stack, BlockPos pos, Direction direction) { BlockPos absolutePos = context.getAbsolutePos(pos); - BlockHitResult hitResult = new BlockHitResult(Vec3d.ofCenter(absolutePos), direction, absolutePos, true); - ActionResult result = stack.useOnBlock(new ItemUsageContext(player, Hand.MAIN_HAND, hitResult)); + ActionResult result = stack.useOnBlock( + new ItemUsageContext( + player, + Hand.MAIN_HAND, + new BlockHitResult( + Vec3d.ofCenter(absolutePos), + direction, + absolutePos, + false + ) + ) + ); if (result instanceof ActionResult.Success success) { return Optional.ofNullable(success.getNewHandStack()); } @@ -138,7 +148,16 @@ public static Optional useStackOnBlockInside(TestContext context, Pla public static void useBlock(TestContext context, BlockPos pos, PlayerEntity player, Direction direction) { BlockPos absolutePos = context.getAbsolutePos(pos); - context.useBlock(pos, player, new BlockHitResult(Vec3d.ofCenter(absolutePos), direction, absolutePos, true)); + context.useBlock( + pos, + player, + new BlockHitResult( + Vec3d.ofCenter(absolutePos), + direction, + absolutePos, + false + ) + ); } @SuppressWarnings("unchecked") diff --git a/src/main/generated/data/minecraft/action/light_block.json b/src/main/generated/data/minecraft/action/light_block.json index 2bb2d3d1..862b27aa 100644 --- a/src/main/generated/data/minecraft/action/light_block.json +++ b/src/main/generated/data/minecraft/action/light_block.json @@ -84,7 +84,6 @@ "action": { "type": "minecraft:place_block", "block": "minecraft:fire", - "decrement_count": false, "position": "interacted" } } diff --git a/src/main/java/net/errorcraft/itematic/Itematic.java b/src/main/java/net/errorcraft/itematic/Itematic.java index 407de364..09c6a5e5 100644 --- a/src/main/java/net/errorcraft/itematic/Itematic.java +++ b/src/main/java/net/errorcraft/itematic/Itematic.java @@ -1,7 +1,6 @@ package net.errorcraft.itematic; import net.errorcraft.itematic.component.ItematicDataComponentTypes; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.event.ItemEvents; import net.errorcraft.itematic.item.holder.rule.ItemHolderRuleTypes; @@ -22,6 +21,7 @@ import net.errorcraft.itematic.village.trade.modifier.TradeModifierTypes; import net.errorcraft.itematic.world.action.ActionTypes; import net.errorcraft.itematic.world.action.sequence.handler.SequenceHandlerTypes; +import net.errorcraft.itematic.world.modification.WorldModificationTypes; import net.fabricmc.api.ModInitializer; public class Itematic implements ModInitializer { diff --git a/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java b/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java index 2a95dce5..808d3709 100644 --- a/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java +++ b/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java @@ -1,7 +1,15 @@ package net.errorcraft.itematic.access.item; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.ItemStackExchanger; import net.minecraft.item.ItemPlacementContext; +import net.minecraft.server.world.ServerWorld; public interface ItemPlacementContextAccess { - ItemPlacementContext itematic$offset(int x, int y, int z); + default ItemPlacementContext itematic$offset(int x, int y, int z) { + return null; + } + default ActionContext itematic$actionContext(ServerWorld world, ItemStackExchanger stackExchanger) { + return null; + } } diff --git a/src/main/java/net/errorcraft/itematic/block/ShapeContextUtil.java b/src/main/java/net/errorcraft/itematic/block/ShapeContexts.java similarity index 59% rename from src/main/java/net/errorcraft/itematic/block/ShapeContextUtil.java rename to src/main/java/net/errorcraft/itematic/block/ShapeContexts.java index 3ea01a02..68e1a1f7 100644 --- a/src/main/java/net/errorcraft/itematic/block/ShapeContextUtil.java +++ b/src/main/java/net/errorcraft/itematic/block/ShapeContexts.java @@ -2,14 +2,16 @@ import net.minecraft.block.ShapeContext; import net.minecraft.entity.Entity; +import org.jetbrains.annotations.Nullable; -public class ShapeContextUtil { - private ShapeContextUtil() {} +public class ShapeContexts { + private ShapeContexts() {} - public static ShapeContext ofNullable(Entity entity) { + public static ShapeContext ofNullable(@Nullable Entity entity) { if (entity == null) { return ShapeContext.absent(); } + return ShapeContext.of(entity); } } diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java b/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java deleted file mode 100644 index f45e6005..00000000 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationTypes.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.errorcraft.itematic.item.bucket.modification; - -import net.errorcraft.itematic.item.bucket.modification.type.DrainFluid; -import net.errorcraft.itematic.item.bucket.modification.type.PlaceBlock; -import net.errorcraft.itematic.item.bucket.modification.type.PlaceFluid; -import net.errorcraft.itematic.registry.ItematicRegistries; -import net.minecraft.registry.Registry; - -public class WorldModificationTypes { - public static final WorldModificationType DRAIN_FLUID = register("drain_fluid", new WorldModificationType<>(DrainFluid.CODEC)); - public static final WorldModificationType PLACE_FLUID = register("place_fluid", new WorldModificationType<>(PlaceFluid.CODEC)); - public static final WorldModificationType PLACE_BLOCK = register("place_block", new WorldModificationType<>(PlaceBlock.CODEC)); - - private WorldModificationTypes() {} - - public static void init() {} - - private static WorldModificationType register(String id, WorldModificationType type) { - return Registry.register(ItematicRegistries.WORLD_MODIFICATION_TYPE, id, type); - } -} diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java index 6939165a..3cc7becb 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java @@ -6,24 +6,30 @@ import net.errorcraft.itematic.item.component.ItemComponent; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.component.ItemComponentTypes; -import net.errorcraft.itematic.item.placement.BlockPlacer; +import net.errorcraft.itematic.item.placement.block.BlockPlacer; import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; import net.errorcraft.itematic.item.placement.block.picker.pickers.AttachedToSideBlockPicker; import net.errorcraft.itematic.item.placement.block.picker.pickers.SimpleBlockPicker; import net.errorcraft.itematic.mixin.item.ItemAccessor; import net.errorcraft.itematic.serialization.SetCodec; +import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.ItemStackExchanger; +import net.errorcraft.itematic.world.action.context.PositionTarget; import net.minecraft.block.Block; import net.minecraft.block.ShulkerBoxBlock; import net.minecraft.component.ComponentMap; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ContainerComponent; import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsage; import net.minecraft.item.ItemUsageContext; +import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Hand; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.hit.BlockHitResult; @@ -115,9 +121,41 @@ private boolean isUnuseable(Pass pass) { return !this.passes.contains(pass); } + public boolean place(ActionContext context, PositionTarget position, boolean decrementCount) { + BlockPlacer placer = BlockPlacer.of( + context, + position, + this.block, + this.operatorOnly, + null + ); + if (!placer.place()) { + return false; + } + + if (decrementCount) { + context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY) + .decrementUnlessCreative( + 1, + context.get(LootContextParameters.THIS_ENTITY, LivingEntity.class) + ); + } + + return true; + } + private ItemResult place(ItemUsageContext context, ItemStackExchanger stackExchanger) { - return BlockPlacer.of(context, stackExchanger, this.block, this.operatorOnly, true) - .place(); + if (!(context.getWorld() instanceof ServerWorld world)) { + return ItemResult.SUCCEED; + } + + ActionContext actionContext = new ItemPlacementContext(context) + .itematic$actionContext(world, stackExchanger); + if (this.place(actionContext, PositionTarget.INTERACTED_POSITION, true)) { + return ItemResult.SUCCEED; + } + + return ItemResult.PASS; } public enum Pass implements StringIdentifiable { diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java index f5edf3e8..f1e541cb 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java @@ -5,10 +5,6 @@ import net.errorcraft.itematic.item.ItemKeys; import net.errorcraft.itematic.item.ItemResult; import net.errorcraft.itematic.item.ItemStackUtil; -import net.errorcraft.itematic.item.bucket.modification.WorldModification; -import net.errorcraft.itematic.item.bucket.modification.type.DrainFluid; -import net.errorcraft.itematic.item.bucket.modification.type.PlaceBlock; -import net.errorcraft.itematic.item.bucket.modification.type.PlaceFluid; import net.errorcraft.itematic.item.component.ItemComponent; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.component.ItemComponentTypes; @@ -21,6 +17,10 @@ import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.ItemStackExchanger; import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.errorcraft.itematic.world.modification.WorldModification; +import net.errorcraft.itematic.world.modification.type.DrainFluidWorldModification; +import net.errorcraft.itematic.world.modification.type.PlaceBlockWorldModification; +import net.errorcraft.itematic.world.modification.type.PlaceFluidWorldModification; import net.minecraft.block.Block; import net.minecraft.component.ComponentMap; import net.minecraft.component.DataComponentTypes; @@ -54,7 +54,7 @@ public static ItemComponent[] drainFluid(RegistryEntryLookup[] { StackableItemComponent.of(16), new BucketItemComponent( - DrainFluid.INSTANCE, + DrainFluidWorldModification.INSTANCE, Optional.empty() ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) @@ -65,7 +65,7 @@ public static ItemComponent[] placeFluid(RegistryEntry fluid, Registry return new ItemComponent[] { StackableItemComponent.of(1), new BucketItemComponent( - new PlaceFluid(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + new PlaceFluidWorldModification(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), Optional.empty() ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) @@ -76,7 +76,7 @@ public static ItemComponent[] placeFluidWithEntity(RegistryEntry fluid return new ItemComponent[] { StackableItemComponent.of(1), new BucketItemComponent( - new PlaceFluid(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + new PlaceFluidWorldModification(fluid, emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), Optional.of(entity) ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) @@ -87,7 +87,7 @@ public static ItemComponent[] placeBlock(RegistryEntry block, Registry return new ItemComponent[] { StackableItemComponent.of(1), new BucketItemComponent( - new PlaceBlock(new SimpleBlockPicker(block), emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), + new PlaceBlockWorldModification(new SimpleBlockPicker(block), emptyingSound, items.getOrThrow(ItemKeys.BUCKET)), Optional.empty() ), DispensableItemComponent.of(dispenseBehaviors.getOrThrow(DispenseBehaviors.USE_BUCKET)) diff --git a/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java deleted file mode 100644 index 83b9f083..00000000 --- a/src/main/java/net/errorcraft/itematic/item/placement/BlockPlacer.java +++ /dev/null @@ -1,198 +0,0 @@ -package net.errorcraft.itematic.item.placement; - -import net.errorcraft.itematic.block.ShapeContextUtil; -import net.errorcraft.itematic.item.ItemResult; -import net.errorcraft.itematic.item.event.ItemEvents; -import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; -import net.errorcraft.itematic.mixin.block.BlockItemAccessor; -import net.errorcraft.itematic.util.context.ItematicContextParameters; -import net.errorcraft.itematic.world.action.context.ActionContext; -import net.errorcraft.itematic.world.action.context.ItemStackExchanger; -import net.errorcraft.itematic.world.action.context.PositionTarget; -import net.minecraft.advancement.criterion.Criteria; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ShapeContext; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.component.type.BlockStateComponent; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.AutomaticItemPlacementContext; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUsageContext; -import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.sound.BlockSoundGroup; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvent; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; -import net.minecraft.world.event.GameEvent; -import org.jetbrains.annotations.Nullable; - -public class BlockPlacer extends Placer { - private final BlockPicker block; - private final ItemPlacementContext context; - private final boolean operatorOnly; - private final boolean decrementStack; - @Nullable - private final RegistryEntry placeSound; - - private BlockPlacer(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockPos blockPos, BlockState blockState, PlayerEntity player, BlockPicker block, ItemPlacementContext context, boolean operatorOnly, boolean decrementStack, @Nullable RegistryEntry placeSound) { - super(stack, stackExchanger, world, blockPos, blockState, player); - this.block = block; - this.context = context; - this.operatorOnly = operatorOnly; - this.decrementStack = decrementStack; - this.placeSound = placeSound; - } - - public static BlockPlacer action(ActionContext context, PositionTarget position, BlockPicker block, boolean decrementCount) { - return action(context, position, block, decrementCount, null); - } - - public static BlockPlacer action(ActionContext context, PositionTarget position, BlockPicker block, boolean decrementCount, RegistryEntry placeSound) { - ItemPlacementContext placeContext = context.blockPlaceContext(position, block); - if (placeContext == null) { - return null; - } - - BlockPos pos = context.getBlockPos(position.parameter()); - if (pos == null) { - return null; - } - - return new BlockPlacer( - context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY), - context.stackExchanger(), - context.world(), - pos, - context.world().getBlockState(pos), - context.get(LootContextParameters.THIS_ENTITY) instanceof PlayerEntity player ? player : null, - block, - placeContext, - false, - decrementCount, - null - ); - } - - public static BlockPlacer of(ItemUsageContext context, ItemStackExchanger stackExchanger, BlockPicker block, boolean operatorOnly, boolean decrementStack) { - World world = context.getWorld(); - BlockPos pos = context.getBlockPos(); - Direction side = context.getSide(); - ItemPlacementContext placementContext = block.placementContext(context.getPlayer() != null ? new ItemPlacementContext(context) : new AutomaticItemPlacementContext(world, pos, side, context.getStack(), world.isAir(pos.down()) ? side : Direction.UP)); - return of(placementContext, stackExchanger, block, operatorOnly, decrementStack); - } - - public static BlockPlacer of(ItemPlacementContext context, ItemStackExchanger stackExchanger, BlockPicker block, boolean operatorOnly, boolean decrementStack) { - World world = context.getWorld(); - BlockPos blockPos = context.getBlockPos(); - return new BlockPlacer( - context.getStack(), - stackExchanger, - world, - blockPos, - world.getBlockState(blockPos), - context.getPlayer(), - block, - context, - operatorOnly, - decrementStack, - null - ); - } - - @Override - public ItemResult place() { - if (!this.context.canPlace()) { - return ItemResult.PASS; - } - - BlockState blockState = this.getPlacementState(); - if (blockState == null) { - return ItemResult.PASS; - } - - if (!this.world.setBlockState(this.blockPos, blockState, Block.NOTIFY_ALL_AND_REDRAW)) { - return ItemResult.PASS; - } - - this.placed(blockState); - return ItemResult.SUCCEED; - } - - private void placed(BlockState blockState) { - blockState = this.placeFromNbt(blockState); - BlockEntity blockEntity = this.world.getBlockEntity(this.blockPos); - if (blockEntity != null) { - blockEntity.itematic$placedFromItemStack(this.world, this.player, blockState, this.blockPos, this.stack); - } - - BlockItemAccessor.copyComponentsToBlockEntity(this.world, this.blockPos, this.stack); - blockState.getBlock().onPlaced(this.world, this.blockPos, blockState, this.player, this.stack); - if (this.player instanceof ServerPlayerEntity serverPlayer) { - Criteria.PLACED_BLOCK.trigger(serverPlayer, this.blockPos, this.stack); - ActionContext context = ActionContext.builder(serverPlayer.getServerWorld()) - .stackExchanger(this.stackExchanger) - .add(LootContextParameters.THIS_ENTITY, serverPlayer) - .add(LootContextParameters.ORIGIN, serverPlayer.getPos()) - .add(ItematicContextParameters.INTERACTED_POSITION, this.blockPos.toCenterPos()) - .add(LootContextParameters.TOOL, this.stack) - .add(ItematicContextParameters.HAND, this.context.getHand()) - .build(); - this.stack.itematic$invokeEvent(ItemEvents.PLACED_BLOCK, context); - } - - BlockSoundGroup blockSoundGroup = blockState.getSoundGroup(); - this.world.playSound(this.player, this.blockPos, this.placeSound(blockSoundGroup), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); - this.world.emitGameEvent(GameEvent.BLOCK_PLACE, this.blockPos, GameEvent.Emitter.of(this.player, blockState)); - if (this.decrementStack) { - this.tryDecrementStack(); - } - } - - private SoundEvent placeSound(BlockSoundGroup group) { - if (this.placeSound != null) { - return this.placeSound.value(); - } - - return group.getPlaceSound(); - } - - @Nullable - private BlockState getPlacementState() { - if (this.operatorOnly && this.player != null && !this.player.isCreativeLevelTwoOp()) { - return null; - } - - BlockState state = this.block.placementState(this.context); - return this.canPlace(state) ? state : null; - } - - private boolean canPlace(BlockState state) { - if (state == null) { - return false; - } - - ShapeContext shapeContext = ShapeContextUtil.ofNullable(this.player); - return state.canPlaceAt(this.world, this.blockPos) && this.world.canPlace(state, this.blockPos, shapeContext); - } - - private BlockState placeFromNbt(BlockState state) { - BlockStateComponent blockStateProperties = this.stack.getOrDefault(DataComponentTypes.BLOCK_STATE, BlockStateComponent.DEFAULT); - if (blockStateProperties.isEmpty()) { - return state; - } - - BlockState modifiedState = blockStateProperties.applyToState(state); - if (modifiedState != state) { - this.world.setBlockState(this.blockPos, modifiedState, Block.NOTIFY_LISTENERS); - } - - return modifiedState; - } -} diff --git a/src/main/java/net/errorcraft/itematic/item/placement/Placer.java b/src/main/java/net/errorcraft/itematic/item/placement/Placer.java deleted file mode 100644 index 8ab192c6..00000000 --- a/src/main/java/net/errorcraft/itematic/item/placement/Placer.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.errorcraft.itematic.item.placement; - -import net.errorcraft.itematic.item.ItemResult; -import net.errorcraft.itematic.world.action.context.ItemStackExchanger; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import org.jetbrains.annotations.Nullable; - -public abstract class Placer { - protected final ItemStack stack; - protected final ItemStackExchanger stackExchanger; - protected final World world; - protected final BlockPos blockPos; - protected final BlockState blockState; - @Nullable - protected final PlayerEntity player; - - protected Placer(ItemStack stack, ItemStackExchanger stackExchanger, World world, BlockPos blockPos, BlockState blockState, @Nullable PlayerEntity player) { - this.stack = stack; - this.stackExchanger = stackExchanger; - this.world = world; - this.blockPos = blockPos; - this.blockState = blockState; - this.player = player; - } - - public abstract ItemResult place(); - - protected void tryDecrementStack() { - this.stack.decrementUnlessCreative(1, this.player); - } -} diff --git a/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java new file mode 100644 index 00000000..2eed452f --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java @@ -0,0 +1,141 @@ +package net.errorcraft.itematic.item.placement.block; + +import net.errorcraft.itematic.block.ShapeContexts; +import net.errorcraft.itematic.item.event.ItemEvents; +import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; +import net.errorcraft.itematic.mixin.block.BlockItemAccessor; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.minecraft.advancement.criterion.Criteria; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.BlockStateComponent; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.event.GameEvent; +import org.jetbrains.annotations.Nullable; + +public class BlockPlacer { + private final ActionContext context; + private final BlockPicker block; + private final ItemPlacementContext placementContext; + private final boolean operatorOnly; + @Nullable + private final RegistryEntry placeSound; + + public BlockPlacer(ActionContext context, PositionTarget position, BlockPicker block, ItemPlacementContext placementContext, boolean operatorOnly, @Nullable RegistryEntry placeSound) { + this.context = context; + this.block = block; + this.placementContext = placementContext; + this.operatorOnly = operatorOnly; + this.placeSound = placeSound; + } + + public static BlockPlacer of(ActionContext context, PositionTarget position, BlockPicker block, boolean operatorOnly, RegistryEntry placeSound) { + return new BlockPlacer( + context, + position, + block, + context.blockPlaceContext(position, block), + operatorOnly, + placeSound + ); + } + + public boolean place() { + if (!this.placementContext.canPlace()) { + return false; + } + + BlockPos pos = this.placementContext.getBlockPos(); + LivingEntity placer = this.context.get(LootContextParameters.THIS_ENTITY, LivingEntity.class); + BlockState blockState = this.getPlacementState(pos, placer); + if (blockState == null) { + return false; + } + + if (!this.context.world().setBlockState(pos, blockState, Block.NOTIFY_ALL_AND_REDRAW)) { + return false; + } + + this.placed(blockState, pos, placer); + return true; + } + + private void placed(BlockState blockState, BlockPos pos, @Nullable LivingEntity placer) { + ServerWorld world = this.context.world(); + ItemStack stack = this.context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY); + blockState = this.placeFromNbt(blockState, pos, stack); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity != null && placer instanceof PlayerEntity playerPlacer) { + blockEntity.itematic$placedFromItemStack(world, playerPlacer, blockState, pos, stack); + } + + BlockItemAccessor.copyComponentsToBlockEntity(world, pos, stack); + blockState.getBlock().onPlaced(world, pos, blockState, placer, stack); + if (placer instanceof ServerPlayerEntity playerPlacer) { + Criteria.PLACED_BLOCK.trigger(playerPlacer, pos, stack); + } + + stack.itematic$invokeEvent(ItemEvents.PLACED_BLOCK, this.context); + BlockSoundGroup blockSoundGroup = blockState.getSoundGroup(); + world.playSound(placer, pos, this.placeSound(blockSoundGroup), SoundCategory.BLOCKS, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F); + world.emitGameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Emitter.of(placer, blockState)); + } + + private SoundEvent placeSound(BlockSoundGroup group) { + if (this.placeSound != null) { + return this.placeSound.value(); + } + + return group.getPlaceSound(); + } + + @Nullable + private BlockState getPlacementState(BlockPos pos, @Nullable LivingEntity placer) { + if (this.operatorOnly && placer instanceof PlayerEntity playerPlacer && !playerPlacer.isCreativeLevelTwoOp()) { + return null; + } + + BlockState state = this.block.placementState(this.placementContext); + return this.canPlace(state, pos, placer) ? state : null; + } + + private boolean canPlace(BlockState state, BlockPos pos, @Nullable LivingEntity placer) { + if (state == null) { + return false; + } + + ShapeContext shapeContext = ShapeContexts.ofNullable(placer); + ServerWorld world = this.context.world(); + return state.canPlaceAt(world, pos) && + world.canPlace(state, pos, shapeContext); + } + + private BlockState placeFromNbt(BlockState state, BlockPos pos, ItemStack stack) { + BlockStateComponent blockStateProperties = stack.getOrDefault(DataComponentTypes.BLOCK_STATE, BlockStateComponent.DEFAULT); + if (blockStateProperties.isEmpty()) { + return state; + } + + BlockState modifiedState = blockStateProperties.applyToState(state); + if (modifiedState != state) { + this.context.world().setBlockState(pos, modifiedState, Block.NOTIFY_LISTENERS); + } + + return modifiedState; + } +} diff --git a/src/main/java/net/errorcraft/itematic/mixin/block/UseableOnFluidBlockExtender.java b/src/main/java/net/errorcraft/itematic/mixin/block/UseableOnFluidBlockExtender.java index 1afb23b5..0b8cfab1 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/block/UseableOnFluidBlockExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/block/UseableOnFluidBlockExtender.java @@ -1,16 +1,18 @@ package net.errorcraft.itematic.mixin.block; import net.errorcraft.itematic.access.block.AbstractBlockAccess; -import net.errorcraft.itematic.access.item.ItemPlacementContextAccess; import net.minecraft.block.FrogspawnBlock; import net.minecraft.block.LilyPadBlock; import net.minecraft.item.ItemPlacementContext; import org.spongepowered.asm.mixin.Mixin; -@Mixin({ LilyPadBlock.class, FrogspawnBlock.class }) +@Mixin({ + LilyPadBlock.class, + FrogspawnBlock.class +}) public class UseableOnFluidBlockExtender implements AbstractBlockAccess { @Override public ItemPlacementContext itematic$placementContext(ItemPlacementContext context) { - return ((ItemPlacementContextAccess) context).itematic$offset(0, 1, 0); + return context.itematic$offset(0, 1, 0); } } diff --git a/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java b/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java index f45f70c4..e6f37fd2 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java @@ -1,9 +1,15 @@ package net.errorcraft.itematic.mixin.item; import net.errorcraft.itematic.access.item.ItemPlacementContextAccess; +import net.errorcraft.itematic.util.context.ItematicContextParameters; +import net.errorcraft.itematic.world.action.context.ActionContext; +import net.errorcraft.itematic.world.action.context.ItemStackExchanger; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemUsageContext; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import org.spongepowered.asm.mixin.Mixin; @@ -20,4 +26,17 @@ public ItemPlacementContextExtender(PlayerEntity player, Hand hand, BlockHitResu BlockHitResult newHit = hit.withBlockPos(hit.getBlockPos().add(x, y, z)); return new ItemPlacementContext(this.getWorld(), this.getPlayer(), this.getHand(), this.getStack(), newHit); } + + @Override + public ActionContext itematic$actionContext(ServerWorld world, ItemStackExchanger stackExchanger) { + return ActionContext.builder(world) + .stackExchanger(stackExchanger) + .addOptional(LootContextParameters.THIS_ENTITY, this.getPlayer()) + .addOptional(LootContextParameters.ORIGIN, this.getPlayer(), Entity::getPos) + .add(ItematicContextParameters.INTERACTED_POSITION, this.getBlockPos().toCenterPos()) + .add(LootContextParameters.TOOL, this.getStack()) + .add(ItematicContextParameters.HAND, this.getHand()) + .add(ItematicContextParameters.SIDE, this.getSide()) + .build(); + } } diff --git a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java index ec1f6ac3..f51ab6a5 100644 --- a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java +++ b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistries.java @@ -1,7 +1,5 @@ package net.errorcraft.itematic.registry; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.event.ItemEvent; @@ -23,6 +21,8 @@ import net.errorcraft.itematic.world.action.ActionTypes; import net.errorcraft.itematic.world.action.sequence.handler.SequenceHandlerType; import net.errorcraft.itematic.world.action.sequence.handler.SequenceHandlerTypes; +import net.errorcraft.itematic.world.modification.WorldModificationType; +import net.errorcraft.itematic.world.modification.WorldModificationTypes; import net.minecraft.registry.Registry; public class ItematicRegistries { diff --git a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java index b279cc1c..fd9b2fb9 100644 --- a/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java +++ b/src/main/java/net/errorcraft/itematic/registry/ItematicRegistryKeys.java @@ -1,6 +1,5 @@ package net.errorcraft.itematic.registry; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; import net.errorcraft.itematic.item.component.ItemComponentType; import net.errorcraft.itematic.item.dispense.behavior.DispenseBehavior; import net.errorcraft.itematic.item.event.ItemEvent; @@ -15,6 +14,7 @@ import net.errorcraft.itematic.world.action.ActionEntry; import net.errorcraft.itematic.world.action.ActionType; import net.errorcraft.itematic.world.action.sequence.handler.SequenceHandlerType; +import net.errorcraft.itematic.world.modification.WorldModificationType; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockAction.java index 708b681f..928483f3 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockAction.java @@ -1,9 +1,8 @@ package net.errorcraft.itematic.world.action.actions; -import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.errorcraft.itematic.item.placement.BlockPlacer; +import net.errorcraft.itematic.item.placement.block.BlockPlacer; import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; import net.errorcraft.itematic.item.placement.block.picker.pickers.SimpleBlockPicker; import net.errorcraft.itematic.world.action.Action; @@ -13,16 +12,19 @@ import net.errorcraft.itematic.world.action.context.PositionTarget; import net.minecraft.block.Block; import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.sound.SoundEvent; -public record PlaceBlockAction(BlockPicker block, PositionTarget position, boolean decrementCount) implements Action { +import java.util.Optional; + +public record PlaceBlockAction(BlockPicker block, PositionTarget position, Optional> placeSound) implements Action { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( BlockPicker.CODEC.fieldOf("block").forGetter(PlaceBlockAction::block), PositionTarget.CODEC.fieldOf("position").forGetter(PlaceBlockAction::position), - Codec.BOOL.optionalFieldOf("decrement_count", true).forGetter(PlaceBlockAction::decrementCount) + SoundEvent.ENTRY_CODEC.optionalFieldOf("place_sound").forGetter(PlaceBlockAction::placeSound) ).apply(instance, PlaceBlockAction::new)); public static PlaceBlockAction of(RegistryEntry block, PositionTarget position) { - return new PlaceBlockAction(new SimpleBlockPicker(block), position, false); + return new PlaceBlockAction(new SimpleBlockPicker(block), position, Optional.empty()); } @Override @@ -32,11 +34,12 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - BlockPlacer placer = BlockPlacer.action(context, this.position, this.block, this.decrementCount); - if (placer == null) { - return false; - } - - return placer.place().succeeds(); + return BlockPlacer.of( + context, + this.position, + this.block, + false, + this.placeSound.orElse(null) + ).place(); } } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockFromItemAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockFromItemAction.java index 2eef0990..ab7a22ff 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockFromItemAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceBlockFromItemAction.java @@ -5,7 +5,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.errorcraft.itematic.item.component.ItemComponentTypes; import net.errorcraft.itematic.item.component.components.BlockItemComponent; -import net.errorcraft.itematic.item.placement.BlockPlacer; import net.errorcraft.itematic.world.action.Action; import net.errorcraft.itematic.world.action.ActionType; import net.errorcraft.itematic.world.action.ActionTypes; @@ -38,11 +37,6 @@ public boolean execute(ActionContext context) { return false; } - BlockPlacer placer = BlockPlacer.action(context, this.position, block.block(), this.decrementCount); - if (placer == null) { - return false; - } - - return placer.place().succeeds(); + return block.place(context, this.position, this.decrementCount); } } diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java b/src/main/java/net/errorcraft/itematic/world/modification/WorldModification.java similarity index 92% rename from src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java rename to src/main/java/net/errorcraft/itematic/world/modification/WorldModification.java index 08233618..f47ee4c6 100644 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModification.java +++ b/src/main/java/net/errorcraft/itematic/world/modification/WorldModification.java @@ -1,4 +1,4 @@ -package net.errorcraft.itematic.item.bucket.modification; +package net.errorcraft.itematic.world.modification; import com.mojang.serialization.Codec; import net.errorcraft.itematic.registry.ItematicRegistries; diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java b/src/main/java/net/errorcraft/itematic/world/modification/WorldModificationType.java similarity index 69% rename from src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java rename to src/main/java/net/errorcraft/itematic/world/modification/WorldModificationType.java index 5cf48b6c..82c0ee60 100644 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/WorldModificationType.java +++ b/src/main/java/net/errorcraft/itematic/world/modification/WorldModificationType.java @@ -1,4 +1,4 @@ -package net.errorcraft.itematic.item.bucket.modification; +package net.errorcraft.itematic.world.modification; import com.mojang.serialization.MapCodec; diff --git a/src/main/java/net/errorcraft/itematic/world/modification/WorldModificationTypes.java b/src/main/java/net/errorcraft/itematic/world/modification/WorldModificationTypes.java new file mode 100644 index 00000000..23329999 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/world/modification/WorldModificationTypes.java @@ -0,0 +1,21 @@ +package net.errorcraft.itematic.world.modification; + +import net.errorcraft.itematic.registry.ItematicRegistries; +import net.errorcraft.itematic.world.modification.type.DrainFluidWorldModification; +import net.errorcraft.itematic.world.modification.type.PlaceBlockWorldModification; +import net.errorcraft.itematic.world.modification.type.PlaceFluidWorldModification; +import net.minecraft.registry.Registry; + +public class WorldModificationTypes { + public static final WorldModificationType DRAIN_FLUID = register("drain_fluid", new WorldModificationType<>(DrainFluidWorldModification.CODEC)); + public static final WorldModificationType PLACE_FLUID = register("place_fluid", new WorldModificationType<>(PlaceFluidWorldModification.CODEC)); + public static final WorldModificationType PLACE_BLOCK = register("place_block", new WorldModificationType<>(PlaceBlockWorldModification.CODEC)); + + private WorldModificationTypes() {} + + public static void init() {} + + private static WorldModificationType register(String id, WorldModificationType type) { + return Registry.register(ItematicRegistries.WORLD_MODIFICATION_TYPE, id, type); + } +} diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java b/src/main/java/net/errorcraft/itematic/world/modification/type/DrainFluidWorldModification.java similarity index 61% rename from src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java rename to src/main/java/net/errorcraft/itematic/world/modification/type/DrainFluidWorldModification.java index 72233901..edbec21f 100644 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/DrainFluid.java +++ b/src/main/java/net/errorcraft/itematic/world/modification/type/DrainFluidWorldModification.java @@ -1,22 +1,22 @@ -package net.errorcraft.itematic.item.bucket.modification.type; +package net.errorcraft.itematic.world.modification.type; import com.mojang.serialization.MapCodec; -import net.errorcraft.itematic.item.bucket.modification.WorldModification; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.placement.fluid.FluidDrainer; import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.errorcraft.itematic.world.modification.WorldModification; +import net.errorcraft.itematic.world.modification.WorldModificationType; +import net.errorcraft.itematic.world.modification.WorldModificationTypes; import net.minecraft.item.ItemStack; import net.minecraft.world.RaycastContext; import java.util.Optional; -public class DrainFluid implements WorldModification { - public static final DrainFluid INSTANCE = new DrainFluid(); - public static final MapCodec CODEC = MapCodec.unit(INSTANCE); +public class DrainFluidWorldModification implements WorldModification { + public static final DrainFluidWorldModification INSTANCE = new DrainFluidWorldModification(); + public static final MapCodec CODEC = MapCodec.unit(INSTANCE); - private DrainFluid() {} + private DrainFluidWorldModification() {} @Override public WorldModificationType type() { diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java b/src/main/java/net/errorcraft/itematic/world/modification/type/PlaceBlockWorldModification.java similarity index 57% rename from src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java rename to src/main/java/net/errorcraft/itematic/world/modification/type/PlaceBlockWorldModification.java index 3943d687..701c6737 100644 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceBlock.java +++ b/src/main/java/net/errorcraft/itematic/world/modification/type/PlaceBlockWorldModification.java @@ -1,14 +1,14 @@ -package net.errorcraft.itematic.item.bucket.modification.type; +package net.errorcraft.itematic.world.modification.type; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.errorcraft.itematic.item.bucket.modification.WorldModification; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; -import net.errorcraft.itematic.item.placement.BlockPlacer; +import net.errorcraft.itematic.item.placement.block.BlockPlacer; import net.errorcraft.itematic.item.placement.block.picker.BlockPicker; import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.errorcraft.itematic.world.modification.WorldModification; +import net.errorcraft.itematic.world.modification.WorldModificationType; +import net.errorcraft.itematic.world.modification.WorldModificationTypes; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.registry.RegistryKeys; @@ -19,12 +19,12 @@ import java.util.Optional; -public record PlaceBlock(BlockPicker block, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - BlockPicker.CODEC.fieldOf("block").forGetter(PlaceBlock::block), - SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceBlock::placeSound), - RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceBlock::transformsInto) - ).apply(instance, PlaceBlock::new)); +public record PlaceBlockWorldModification(BlockPicker block, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + BlockPicker.CODEC.fieldOf("block").forGetter(PlaceBlockWorldModification::block), + SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceBlockWorldModification::placeSound), + RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceBlockWorldModification::transformsInto) + ).apply(instance, PlaceBlockWorldModification::new)); @Override public WorldModificationType type() { @@ -33,18 +33,15 @@ public WorldModificationType type() { @Override public Optional modify(ActionContext context, PositionTarget position, boolean mayOffset) { - BlockPlacer placer = BlockPlacer.action( + BlockPlacer placer = BlockPlacer.of( context, - PositionTarget.INTERACTED_POSITION, + position, this.block, false, this.placeSound ); - if (placer == null) { - return Optional.empty(); - } - if (!placer.place().succeeds()) { + if (!placer.place()) { return Optional.empty(); } diff --git a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java b/src/main/java/net/errorcraft/itematic/world/modification/type/PlaceFluidWorldModification.java similarity index 66% rename from src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java rename to src/main/java/net/errorcraft/itematic/world/modification/type/PlaceFluidWorldModification.java index 8a8e1a38..223dcf6b 100644 --- a/src/main/java/net/errorcraft/itematic/item/bucket/modification/type/PlaceFluid.java +++ b/src/main/java/net/errorcraft/itematic/world/modification/type/PlaceFluidWorldModification.java @@ -1,13 +1,13 @@ -package net.errorcraft.itematic.item.bucket.modification.type; +package net.errorcraft.itematic.world.modification.type; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.errorcraft.itematic.item.bucket.modification.WorldModification; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationType; -import net.errorcraft.itematic.item.bucket.modification.WorldModificationTypes; import net.errorcraft.itematic.item.placement.fluid.FluidPlacer; import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.PositionTarget; +import net.errorcraft.itematic.world.modification.WorldModification; +import net.errorcraft.itematic.world.modification.WorldModificationType; +import net.errorcraft.itematic.world.modification.WorldModificationTypes; import net.minecraft.fluid.Fluid; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -19,12 +19,12 @@ import java.util.Optional; -public record PlaceFluid(RegistryEntry fluid, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - RegistryFixedCodec.of(RegistryKeys.FLUID).fieldOf("fluid").forGetter(PlaceFluid::fluid), - SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceFluid::placeSound), - RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceFluid::transformsInto) - ).apply(instance, PlaceFluid::new)); +public record PlaceFluidWorldModification(RegistryEntry fluid, RegistryEntry placeSound, RegistryEntry transformsInto) implements WorldModification { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + RegistryFixedCodec.of(RegistryKeys.FLUID).fieldOf("fluid").forGetter(PlaceFluidWorldModification::fluid), + SoundEvent.ENTRY_CODEC.fieldOf("place_sound").forGetter(PlaceFluidWorldModification::placeSound), + RegistryFixedCodec.of(RegistryKeys.ITEM).fieldOf("transforms_into").forGetter(PlaceFluidWorldModification::transformsInto) + ).apply(instance, PlaceFluidWorldModification::new)); @Override public WorldModificationType type() { diff --git a/src/main/resources/itematic.classtweaker b/src/main/resources/itematic.classtweaker index d2fd35f6..e1a63634 100644 --- a/src/main/resources/itematic.classtweaker +++ b/src/main/resources/itematic.classtweaker @@ -22,3 +22,4 @@ inject-interface net/minecraft/block/entity/BlockEntity net/errorcraft/ite inject-interface net/minecraft/village/VillagerData net/errorcraft/itematic/access/village/VillagerDataAccess inject-interface net/minecraft/village/VillagerProfession net/errorcraft/itematic/access/village/VillagerProfessionAccess inject-interface net/minecraft/client/gui/screen/GameModeSwitcherScreen$GameModeSelection net/errorcraft/itematic/access/client/gui/screen/GameModeSwitcherScreenAccess$GameModeSelectionAccess +inject-interface net/minecraft/item/ItemPlacementContext net/errorcraft/itematic/access/item/ItemPlacementContextAccess From d8dbce611440470da9fb89386493661891ee454d Mon Sep 17 00:00:00 2001 From: ErrorCraft Date: Wed, 20 May 2026 17:22:53 +0200 Subject: [PATCH 3/4] Move to mixin and class tweaker enum extensions --- build.gradle | 7 +-- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../recipebook/BrewingRecipeBookWidget.java | 4 +- .../ItematicSearchRecipeBookTypes.java | 10 ---- .../GameModeSwitcherScreenExtender.java | 8 ++- .../recipebook/RecipeBookTypeExtender.java | 15 ++++++ .../resources/itematic.client.mixins.json | 1 + .../itematic/access/util/DyeColorAccess.java | 5 +- .../errorcraft/itematic/item/ItemUtil.java | 3 +- .../loot/context/LootContextExtender.java | 18 +++++++ .../book/RecipeBookOptionsExtender.java | 3 +- .../recipe/book/RecipeBookTypeExtender.java | 13 +++++ .../itematic/mixin/util/DyeColorExtender.java | 50 +++++++++++-------- .../itematic/mm/ItematicEarlyRiser.java | 22 -------- .../mm/client/ItematicClientEarlyRiser.java | 31 ------------ .../recipe/book/ItematicRecipeBookTypes.java | 10 ---- .../screen/BrewingStandMenuDelegate.java | 3 +- .../action/context/ItematicEntityTargets.java | 10 ---- src/main/resources/fabric.mod.json | 6 +-- src/main/resources/itematic.classtweaker | 6 ++- src/main/resources/itematic.mixins.json | 2 + 22 files changed, 102 insertions(+), 129 deletions(-) delete mode 100644 src/client/java/net/errorcraft/itematic/client/recipebook/ItematicSearchRecipeBookTypes.java create mode 100644 src/client/java/net/errorcraft/itematic/mixin/client/recipebook/RecipeBookTypeExtender.java create mode 100644 src/main/java/net/errorcraft/itematic/mixin/loot/context/LootContextExtender.java create mode 100644 src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookTypeExtender.java delete mode 100644 src/main/java/net/errorcraft/itematic/mm/ItematicEarlyRiser.java delete mode 100644 src/main/java/net/errorcraft/itematic/mm/client/ItematicClientEarlyRiser.java delete mode 100644 src/main/java/net/errorcraft/itematic/recipe/book/ItematicRecipeBookTypes.java delete mode 100644 src/main/java/net/errorcraft/itematic/world/action/context/ItematicEntityTargets.java diff --git a/build.gradle b/build.gradle index 489c2c40..2fbb7971 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.14-SNAPSHOT' + id 'fabric-loom' version '1.16-SNAPSHOT' id 'maven-publish' } @@ -12,8 +12,6 @@ repositories { // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. - - maven { url 'https://jitpack.io' } } dependencies { @@ -24,9 +22,6 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - - modImplementation "com.github.Chocohead:Fabric-ASM:v2.3" - include "com.github.Chocohead:Fabric-ASM:v2.3" } processResources { diff --git a/gradle.properties b/gradle.properties index b4973748..5a9edd75 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx1G # check these on https://fabricmc.net/develop minecraft_version=1.21.5 yarn_mappings=1.21.5+build.1 - loader_version=0.18.4 + loader_version=0.19.2 # Mod Properties mod_version = 0.6.0-preview.1+1.21.5 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dbc3ce4a..5dd3c012 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/client/java/net/errorcraft/itematic/client/gui/screen/recipebook/BrewingRecipeBookWidget.java b/src/client/java/net/errorcraft/itematic/client/gui/screen/recipebook/BrewingRecipeBookWidget.java index 6f119e73..b75e6492 100644 --- a/src/client/java/net/errorcraft/itematic/client/gui/screen/recipebook/BrewingRecipeBookWidget.java +++ b/src/client/java/net/errorcraft/itematic/client/gui/screen/recipebook/BrewingRecipeBookWidget.java @@ -1,6 +1,5 @@ package net.errorcraft.itematic.client.gui.screen.recipebook; -import net.errorcraft.itematic.client.recipebook.ItematicSearchRecipeBookTypes; import net.errorcraft.itematic.mixin.client.gui.screen.recipebook.GhostRecipeAccessor; import net.errorcraft.itematic.recipe.book.ItematicRecipeBookCategories; import net.errorcraft.itematic.recipe.display.BrewingRecipeDisplay; @@ -9,6 +8,7 @@ import net.minecraft.client.gui.screen.recipebook.GhostRecipe; import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget; import net.minecraft.client.gui.screen.recipebook.RecipeResultCollection; +import net.minecraft.client.recipebook.RecipeBookType; import net.minecraft.item.Items; import net.minecraft.recipe.RecipeFinder; import net.minecraft.recipe.display.RecipeDisplay; @@ -28,7 +28,7 @@ public class BrewingRecipeBookWidget extends RecipeBookWidget TABS = List.of( - new Tab(ItematicSearchRecipeBookTypes.BREWING), + new Tab(RecipeBookType.ITEMATIC_BREWING), // Item references are intended as key conversion is handled by a mixin new Tab(Items.NETHER_WART, Items.MAGMA_CREAM, ItematicRecipeBookCategories.BREWING_MODIFY), new Tab(Items.SPLASH_POTION, Items.LINGERING_POTION, ItematicRecipeBookCategories.BREWING_AMPLIFY) diff --git a/src/client/java/net/errorcraft/itematic/client/recipebook/ItematicSearchRecipeBookTypes.java b/src/client/java/net/errorcraft/itematic/client/recipebook/ItematicSearchRecipeBookTypes.java deleted file mode 100644 index 9f29de39..00000000 --- a/src/client/java/net/errorcraft/itematic/client/recipebook/ItematicSearchRecipeBookTypes.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.errorcraft.itematic.client.recipebook; - -import com.chocohead.mm.api.ClassTinkerers; -import net.minecraft.client.recipebook.RecipeBookType; - -public class ItematicSearchRecipeBookTypes { - public static final RecipeBookType BREWING = ClassTinkerers.getEnum(RecipeBookType.class, "ITEMATIC$BREWING"); - - private ItematicSearchRecipeBookTypes() {} -} diff --git a/src/client/java/net/errorcraft/itematic/mixin/client/gui/screen/GameModeSwitcherScreenExtender.java b/src/client/java/net/errorcraft/itematic/mixin/client/gui/screen/GameModeSwitcherScreenExtender.java index 52617d07..5f43d449 100644 --- a/src/client/java/net/errorcraft/itematic/mixin/client/gui/screen/GameModeSwitcherScreenExtender.java +++ b/src/client/java/net/errorcraft/itematic/mixin/client/gui/screen/GameModeSwitcherScreenExtender.java @@ -18,7 +18,9 @@ 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class GameModeSwitcherScreenExtender { @Mixin(GameModeSwitcherScreen.ButtonWidget.class) @@ -62,7 +64,11 @@ public static class GameModeSelectionExtender implements GameModeSwitcherScreenA @Unique private RegistryKey icon; - static { + @Inject( + method = "", + at = @At("TAIL") + ) + private static void setIcons(CallbackInfo info) { CREATIVE.itematic$setIcon(ItemKeys.GRASS_BLOCK); SURVIVAL.itematic$setIcon(ItemKeys.IRON_SWORD); ADVENTURE.itematic$setIcon(ItemKeys.MAP); diff --git a/src/client/java/net/errorcraft/itematic/mixin/client/recipebook/RecipeBookTypeExtender.java b/src/client/java/net/errorcraft/itematic/mixin/client/recipebook/RecipeBookTypeExtender.java new file mode 100644 index 00000000..f511c01c --- /dev/null +++ b/src/client/java/net/errorcraft/itematic/mixin/client/recipebook/RecipeBookTypeExtender.java @@ -0,0 +1,15 @@ +package net.errorcraft.itematic.mixin.client.recipebook; + +import net.errorcraft.itematic.recipe.book.ItematicRecipeBookCategories; +import net.minecraft.client.recipebook.RecipeBookType; +import net.minecraft.recipe.book.RecipeBookCategory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(RecipeBookType.class) +public enum RecipeBookTypeExtender { + ITEMATIC_BREWING(ItematicRecipeBookCategories.BREWING_MODIFY, ItematicRecipeBookCategories.BREWING_AMPLIFY); + + @Shadow + RecipeBookTypeExtender(RecipeBookCategory... categories) {} +} diff --git a/src/client/resources/itematic.client.mixins.json b/src/client/resources/itematic.client.mixins.json index 87426a16..b5fb71d9 100644 --- a/src/client/resources/itematic.client.mixins.json +++ b/src/client/resources/itematic.client.mixins.json @@ -44,6 +44,7 @@ "option.HotbarStorageEntryExtender", "particle.CrackParticleExtender$SlimeballFactoryExtender", "particle.CrackParticleExtender$SnowballFactoryExtender", + "recipebook.RecipeBookTypeExtender", "recipebook.RecipeBookWidgetExtender$TabExtender", "render.block.entity.DecoratedPotBlockEntityRendererExtender", "render.entity.AbstractSkeletonEntityRendererExtender", diff --git a/src/main/java/net/errorcraft/itematic/access/util/DyeColorAccess.java b/src/main/java/net/errorcraft/itematic/access/util/DyeColorAccess.java index dd4da725..675aca90 100644 --- a/src/main/java/net/errorcraft/itematic/access/util/DyeColorAccess.java +++ b/src/main/java/net/errorcraft/itematic/access/util/DyeColorAccess.java @@ -4,5 +4,8 @@ import net.minecraft.registry.RegistryKey; public interface DyeColorAccess { - RegistryKey itematic$itemKey(); + default RegistryKey itematic$itemKey() { + return null; + } + default void itematic$setItemKey(RegistryKey item) {} } diff --git a/src/main/java/net/errorcraft/itematic/item/ItemUtil.java b/src/main/java/net/errorcraft/itematic/item/ItemUtil.java index 5b461c02..9202c52d 100644 --- a/src/main/java/net/errorcraft/itematic/item/ItemUtil.java +++ b/src/main/java/net/errorcraft/itematic/item/ItemUtil.java @@ -32,7 +32,6 @@ import net.errorcraft.itematic.world.action.Actions; import net.errorcraft.itematic.world.action.actions.*; import net.errorcraft.itematic.world.action.context.ItemStackTarget; -import net.errorcraft.itematic.world.action.context.ItematicEntityTargets; import net.errorcraft.itematic.world.action.context.PositionTarget; import net.errorcraft.itematic.world.action.sequence.handler.handlers.FirstToPassRequirementsSequenceHandler; import net.errorcraft.itematic.world.action.sequence.handler.handlers.PassingSequenceHandler; @@ -11396,7 +11395,7 @@ private void bootstrapMiscellaneous() { ItemEventMap.builder() .add(ItemEvents.USE_ON_ENTITY, ActionEntry.of( PassingSequenceHandler.builder() - .add(SetEntityNameFromItemAction.of(ItematicEntityTargets.TARGET_ENTITY)) + .add(SetEntityNameFromItemAction.of(LootContext.EntityTarget.ITEMATIC_TARGET_ENTITY)) .add(DecrementItemAction.of(1)) .add(SwingHandAction.of(LootContext.EntityTarget.THIS)) )) diff --git a/src/main/java/net/errorcraft/itematic/mixin/loot/context/LootContextExtender.java b/src/main/java/net/errorcraft/itematic/mixin/loot/context/LootContextExtender.java new file mode 100644 index 00000000..6386799d --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/mixin/loot/context/LootContextExtender.java @@ -0,0 +1,18 @@ +package net.errorcraft.itematic.mixin.loot.context; + +import net.errorcraft.itematic.util.context.ItematicContextParameters; +import net.minecraft.entity.Entity; +import net.minecraft.loot.context.LootContext; +import net.minecraft.util.context.ContextParameter; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +public class LootContextExtender { + @Mixin(LootContext.EntityTarget.class) + public enum EntityTargetExtender { + ITEMATIC_TARGET_ENTITY("target_entity", ItematicContextParameters.TARGET_ENTITY); + + @Shadow + EntityTargetExtender(String type, ContextParameter parameter) {} + } +} diff --git a/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookOptionsExtender.java b/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookOptionsExtender.java index d8397421..b2d4c553 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookOptionsExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookOptionsExtender.java @@ -3,7 +3,6 @@ import com.google.common.collect.ImmutableMap; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.datafixers.util.Pair; -import net.errorcraft.itematic.recipe.book.ItematicRecipeBookTypes; import net.minecraft.recipe.book.RecipeBookOptions; import net.minecraft.recipe.book.RecipeBookType; import org.spongepowered.asm.mixin.Mixin; @@ -23,7 +22,7 @@ private static ImmutableMap> addCustomEntri return ImmutableMap.>builder() .putAll(original) .put( - ItematicRecipeBookTypes.BREWING, + RecipeBookType.ITEMATIC_BREWING, Pair.of("isBrewingStandGuiOpen", "isBrewingStandFilteringCraftable") ) .build(); diff --git a/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookTypeExtender.java b/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookTypeExtender.java new file mode 100644 index 00000000..429bd448 --- /dev/null +++ b/src/main/java/net/errorcraft/itematic/mixin/recipe/book/RecipeBookTypeExtender.java @@ -0,0 +1,13 @@ +package net.errorcraft.itematic.mixin.recipe.book; + +import net.minecraft.recipe.book.RecipeBookType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(RecipeBookType.class) +public enum RecipeBookTypeExtender { + ITEMATIC_BREWING; + + @Shadow + RecipeBookTypeExtender() {} +} diff --git a/src/main/java/net/errorcraft/itematic/mixin/util/DyeColorExtender.java b/src/main/java/net/errorcraft/itematic/mixin/util/DyeColorExtender.java index 725a2876..c29cd086 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/util/DyeColorExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/util/DyeColorExtender.java @@ -14,10 +14,8 @@ 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.ModifyArg; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; import java.util.Optional; @@ -25,7 +23,6 @@ import java.util.function.Predicate; @Mixin(DyeColor.class) -@SuppressWarnings("DataFlowIssue") public class DyeColorExtender implements DyeColorAccess { @Shadow @Final @@ -94,23 +91,27 @@ public class DyeColorExtender implements DyeColorAccess { @Unique private RegistryKey itemKey; - static { - ((DyeColorExtender)(Object) WHITE).itemKey = ItemKeys.WHITE_DYE; - ((DyeColorExtender)(Object) ORANGE).itemKey = ItemKeys.ORANGE_DYE; - ((DyeColorExtender)(Object) MAGENTA).itemKey = ItemKeys.MAGENTA_DYE; - ((DyeColorExtender)(Object) LIGHT_BLUE).itemKey = ItemKeys.LIGHT_BLUE_DYE; - ((DyeColorExtender)(Object) YELLOW).itemKey = ItemKeys.YELLOW_DYE; - ((DyeColorExtender)(Object) LIME).itemKey = ItemKeys.LIME_DYE; - ((DyeColorExtender)(Object) PINK).itemKey = ItemKeys.PINK_DYE; - ((DyeColorExtender)(Object) GRAY).itemKey = ItemKeys.GRAY_DYE; - ((DyeColorExtender)(Object) LIGHT_GRAY).itemKey = ItemKeys.LIGHT_GRAY_DYE; - ((DyeColorExtender)(Object) CYAN).itemKey = ItemKeys.CYAN_DYE; - ((DyeColorExtender)(Object) PURPLE).itemKey = ItemKeys.PURPLE_DYE; - ((DyeColorExtender)(Object) BLUE).itemKey = ItemKeys.BLUE_DYE; - ((DyeColorExtender)(Object) BROWN).itemKey = ItemKeys.BROWN_DYE; - ((DyeColorExtender)(Object) GREEN).itemKey = ItemKeys.GREEN_DYE; - ((DyeColorExtender)(Object) RED).itemKey = ItemKeys.RED_DYE; - ((DyeColorExtender)(Object) BLACK).itemKey = ItemKeys.BLACK_DYE; + @Inject( + method = "", + at = @At("TAIL") + ) + private static void setItemKeys(CallbackInfo info) { + WHITE.itematic$setItemKey(ItemKeys.WHITE_DYE); + ORANGE.itematic$setItemKey(ItemKeys.ORANGE_DYE); + MAGENTA.itematic$setItemKey(ItemKeys.MAGENTA_DYE); + LIGHT_BLUE.itematic$setItemKey(ItemKeys.LIGHT_BLUE_DYE); + YELLOW.itematic$setItemKey(ItemKeys.YELLOW_DYE); + LIME.itematic$setItemKey(ItemKeys.LIME_DYE); + PINK.itematic$setItemKey(ItemKeys.PINK_DYE); + GRAY.itematic$setItemKey(ItemKeys.GRAY_DYE); + LIGHT_GRAY.itematic$setItemKey(ItemKeys.LIGHT_GRAY_DYE); + CYAN.itematic$setItemKey(ItemKeys.CYAN_DYE); + PURPLE.itematic$setItemKey(ItemKeys.PURPLE_DYE); + BLUE.itematic$setItemKey(ItemKeys.BLUE_DYE); + BROWN.itematic$setItemKey(ItemKeys.BROWN_DYE); + GREEN.itematic$setItemKey(ItemKeys.GREEN_DYE); + RED.itematic$setItemKey(ItemKeys.RED_DYE); + BLACK.itematic$setItemKey(ItemKeys.BLACK_DYE); } @Redirect( @@ -182,4 +183,9 @@ private static Optional castToDyeItemDoNothing(Optional itematic$itemKey() { return this.itemKey; } + + @Override + public void itematic$setItemKey(RegistryKey item) { + this.itemKey = item; + } } diff --git a/src/main/java/net/errorcraft/itematic/mm/ItematicEarlyRiser.java b/src/main/java/net/errorcraft/itematic/mm/ItematicEarlyRiser.java deleted file mode 100644 index 2985b9f7..00000000 --- a/src/main/java/net/errorcraft/itematic/mm/ItematicEarlyRiser.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.errorcraft.itematic.mm; - -import com.chocohead.mm.api.ClassTinkerers; -import net.errorcraft.itematic.util.context.ItematicContextParameters; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.MappingResolver; - -public class ItematicEarlyRiser implements Runnable { - @Override - public void run() { - MappingResolver remapper = FabricLoader.getInstance().getMappingResolver(); - String recipeBookType = remapper.mapClassName("intermediary", "net.minecraft.class_5421"); - ClassTinkerers.enumBuilder(recipeBookType) - .addEnum("ITEMATIC$BREWING") - .build(); - String lootContextEntityTarget = remapper.mapClassName("intermediary", "net.minecraft.class_47$class_50"); - String contextParameter = 'L' + remapper.mapClassName("intermediary", "net.minecraft.class_169") + ';'; - ClassTinkerers.enumBuilder(lootContextEntityTarget, String.class, contextParameter) - .addEnum("ITEMATIC$TARGET_ENTITY", "target_entity", ItematicContextParameters.TARGET_ENTITY) - .build(); - } -} diff --git a/src/main/java/net/errorcraft/itematic/mm/client/ItematicClientEarlyRiser.java b/src/main/java/net/errorcraft/itematic/mm/client/ItematicClientEarlyRiser.java deleted file mode 100644 index ae668002..00000000 --- a/src/main/java/net/errorcraft/itematic/mm/client/ItematicClientEarlyRiser.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.errorcraft.itematic.mm.client; - -import com.chocohead.mm.api.ClassTinkerers; -import net.errorcraft.itematic.recipe.book.ItematicRecipeBookCategories; -import net.fabricmc.api.EnvType; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.MappingResolver; -import net.minecraft.recipe.book.RecipeBookCategory; - -public class ItematicClientEarlyRiser implements Runnable { - @Override - public void run() { - FabricLoader loader = FabricLoader.getInstance(); - - // There is no early riser client entry point definition, so this check is done in main instead - if (loader.getEnvironmentType() != EnvType.CLIENT) { - return; - } - - MappingResolver remapper = loader.getMappingResolver(); - String recipeBookType = remapper.mapClassName("intermediary", "net.minecraft.class_10331"); - ClassTinkerers.enumBuilder(recipeBookType, RecipeBookCategory[].class) - .addEnum("ITEMATIC$BREWING", () -> new Object[] { - new RecipeBookCategory[] { - ItematicRecipeBookCategories.BREWING_MODIFY, - ItematicRecipeBookCategories.BREWING_AMPLIFY - } - }) - .build(); - } -} diff --git a/src/main/java/net/errorcraft/itematic/recipe/book/ItematicRecipeBookTypes.java b/src/main/java/net/errorcraft/itematic/recipe/book/ItematicRecipeBookTypes.java deleted file mode 100644 index 58915da5..00000000 --- a/src/main/java/net/errorcraft/itematic/recipe/book/ItematicRecipeBookTypes.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.errorcraft.itematic.recipe.book; - -import com.chocohead.mm.api.ClassTinkerers; -import net.minecraft.recipe.book.RecipeBookType; - -public class ItematicRecipeBookTypes { - public static final RecipeBookType BREWING = ClassTinkerers.getEnum(RecipeBookType.class, "ITEMATIC$BREWING"); - - private ItematicRecipeBookTypes() {} -} diff --git a/src/main/java/net/errorcraft/itematic/screen/BrewingStandMenuDelegate.java b/src/main/java/net/errorcraft/itematic/screen/BrewingStandMenuDelegate.java index 8c492742..58f8f456 100644 --- a/src/main/java/net/errorcraft/itematic/screen/BrewingStandMenuDelegate.java +++ b/src/main/java/net/errorcraft/itematic/screen/BrewingStandMenuDelegate.java @@ -1,7 +1,6 @@ package net.errorcraft.itematic.screen; import net.errorcraft.itematic.mixin.screen.BrewingStandScreenHandlerAccessor; -import net.errorcraft.itematic.recipe.book.ItematicRecipeBookTypes; import net.errorcraft.itematic.recipe.brewing.BrewingRecipe; import net.errorcraft.itematic.recipe.input.BrewingRecipeInput; import net.minecraft.entity.player.PlayerEntity; @@ -85,7 +84,7 @@ public void populateRecipeFinder(RecipeFinder finder) { @Override public RecipeBookType getCategory() { - return ItematicRecipeBookTypes.BREWING; + return RecipeBookType.ITEMATIC_BREWING; } @Override diff --git a/src/main/java/net/errorcraft/itematic/world/action/context/ItematicEntityTargets.java b/src/main/java/net/errorcraft/itematic/world/action/context/ItematicEntityTargets.java deleted file mode 100644 index f6536684..00000000 --- a/src/main/java/net/errorcraft/itematic/world/action/context/ItematicEntityTargets.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.errorcraft.itematic.world.action.context; - -import com.chocohead.mm.api.ClassTinkerers; -import net.minecraft.loot.context.LootContext; - -public class ItematicEntityTargets { - public static final LootContext.EntityTarget TARGET_ENTITY = ClassTinkerers.getEnum(LootContext.EntityTarget.class, "ITEMATIC$TARGET_ENTITY"); - - private ItematicEntityTargets() {} -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 38cc8e64..e205a0d6 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -24,10 +24,6 @@ ], "fabric-datagen": [ "net.errorcraft.itematic.data.ItematicData" - ], - "mm:early_risers": [ - "net.errorcraft.itematic.mm.ItematicEarlyRiser", - "net.errorcraft.itematic.mm.client.ItematicClientEarlyRiser" ] }, "mixins": [ @@ -128,7 +124,7 @@ }, "depends": { - "fabricloader": ">=0.18.4", + "fabricloader": ">=0.19.2", "fabric-api": "*", "minecraft": "~1.21-", "java": ">=21" diff --git a/src/main/resources/itematic.classtweaker b/src/main/resources/itematic.classtweaker index e1a63634..655f0381 100644 --- a/src/main/resources/itematic.classtweaker +++ b/src/main/resources/itematic.classtweaker @@ -1,4 +1,4 @@ -classTweaker v1 named +classTweaker v2 named accessible class net/minecraft/registry/Registries$Initializer accessible class net/minecraft/entity/passive/OcelotEntity$OcelotTemptGoal @@ -23,3 +23,7 @@ inject-interface net/minecraft/village/VillagerData net/errorcraft/itemati inject-interface net/minecraft/village/VillagerProfession net/errorcraft/itematic/access/village/VillagerProfessionAccess inject-interface net/minecraft/client/gui/screen/GameModeSwitcherScreen$GameModeSelection net/errorcraft/itematic/access/client/gui/screen/GameModeSwitcherScreenAccess$GameModeSelectionAccess inject-interface net/minecraft/item/ItemPlacementContext net/errorcraft/itematic/access/item/ItemPlacementContextAccess + +extend-enum net/minecraft/recipe/book/RecipeBookType ITEMATIC_BREWING +extend-enum net/minecraft/client/recipebook/RecipeBookType ITEMATIC_BREWING +extend-enum net/minecraft/loot/context/LootContext$EntityTarget ITEMATIC_TARGET_ENTITY diff --git a/src/main/resources/itematic.mixins.json b/src/main/resources/itematic.mixins.json index a342f1e6..b77053f3 100644 --- a/src/main/resources/itematic.mixins.json +++ b/src/main/resources/itematic.mixins.json @@ -291,6 +291,7 @@ "loot.ContainerComponentModifiersExtender$BundleContentsExtender", "loot.condition.LocationCheckLootConditionExtender", "loot.condition.LootConditionTypesAccessor", + "loot.context.LootContextExtender$EntityTargetExtender", "loot.context.LootContextTypesAccessor", "loot.entry.TagEntryExtender", "loot.function.EnchantRandomlyLootFunctionExtender", @@ -341,6 +342,7 @@ "recipe.TransmuteRecipeExtender", "recipe.TransmuteRecipeResultExtender", "recipe.book.RecipeBookOptionsExtender", + "recipe.book.RecipeBookTypeExtender", "recipe.display.SlotDisplayExtender$AnyFuelSlotDisplayExtender", "recipe.display.SlotDisplayExtender$ItemSlotDisplayExtender", "recipe.display.SlotDisplayExtender$StackSlotDisplayExtender", From fd281c8caf508a36bc9ae2b4ba2c0893672e1a65 Mon Sep 17 00:00:00 2001 From: ErrorCraft Date: Tue, 26 May 2026 14:33:21 +0200 Subject: [PATCH 4/4] Allow ActionContext to be used with all worlds --- .../item/ItemPlacementContextAccess.java | 3 +-- .../ArmorStandEntityInitializer.java | 6 ++--- .../DecorationEntityInitializer.java | 3 +-- .../EndCrystalEntityInitializer.java | 5 +++- .../EyeOfEnderEntityInitializer.java | 5 +++- .../MinecartEntityInitializer.java | 4 +-- .../SmallFireballEntityInitializer.java | 4 +-- .../TridentEntityInitializer.java | 4 +-- .../WindChargeEntityInitializer.java | 8 +++--- .../components/BlockItemComponent.java | 8 ++---- .../components/BucketItemComponent.java | 8 +----- .../components/ThrowableItemComponent.java | 14 +++++----- .../itematic/item/placement/EntityPlacer.java | 16 ++++++----- .../item/placement/block/BlockPlacer.java | 9 +++---- .../item/placement/fluid/FluidDrainer.java | 4 +-- .../item/placement/fluid/FluidPlacer.java | 12 ++++++--- .../mixin/entity/EntityTypeExtender.java | 6 ++++- .../item/ItemPlacementContextExtender.java | 5 ++-- .../mixin/item/ItemStackExtender.java | 6 ++++- .../itematic/world/action/ActionEntry.java | 4 +++ .../AttachLeashedEntitiesOnBlockAction.java | 4 +-- .../actions/ChargeRespawnAnchorAction.java | 4 +-- .../action/actions/DisplayParticleAction.java | 5 +++- .../world/action/actions/FertilizeAction.java | 6 ++--- .../action/actions/LightEndPortalAction.java | 4 +-- .../actions/MarkBannerOnItemAction.java | 4 +-- .../actions/ModifyBlockStateAction.java | 4 +-- .../action/actions/ModifyItemAction.java | 4 +++ .../actions/PlaceCarvedPumpkinAction.java | 4 +-- .../world/action/actions/PlaySoundAction.java | 4 +-- .../world/action/actions/PrimeTntAction.java | 5 +++- .../action/actions/RunFunctionAction.java | 8 +++++- .../action/actions/SetBlockStateAction.java | 4 +-- .../action/actions/ShearAtPositionAction.java | 5 +++- .../world/action/actions/TeleportAction.java | 6 ++++- .../world/action/actions/WaxBlockAction.java | 4 +-- .../world/action/context/ActionContext.java | 27 ++++++++++--------- .../action/context/ItemStackExchanger.java | 14 ++++++---- 38 files changed, 146 insertions(+), 104 deletions(-) diff --git a/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java b/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java index 808d3709..754149d9 100644 --- a/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java +++ b/src/main/java/net/errorcraft/itematic/access/item/ItemPlacementContextAccess.java @@ -3,13 +3,12 @@ import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.ItemStackExchanger; import net.minecraft.item.ItemPlacementContext; -import net.minecraft.server.world.ServerWorld; public interface ItemPlacementContextAccess { default ItemPlacementContext itematic$offset(int x, int y, int z) { return null; } - default ActionContext itematic$actionContext(ServerWorld world, ItemStackExchanger stackExchanger) { + default ActionContext itematic$actionContext(ItemStackExchanger stackExchanger) { return null; } } diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/ArmorStandEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/ArmorStandEntityInitializer.java index a9f4ba22..03fd47f2 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/ArmorStandEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/ArmorStandEntityInitializer.java @@ -8,13 +8,13 @@ import net.minecraft.entity.SpawnReason; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; public class ArmorStandEntityInitializer implements EntityInitializer { public static final ArmorStandEntityInitializer INSTANCE = new ArmorStandEntityInitializer(); @@ -32,7 +32,7 @@ public ArmorStandEntity create(ActionContext context, SpawnReason reason) { return null; } - ServerWorld world = context.world(); + World world = context.world(); ArmorStandEntity entity = new ArmorStandEntity(world, position.getX(), position.getY(), position.getZ()); float angle = getRoundedAngle(context); entity.refreshPositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), angle, 0.0f); @@ -45,7 +45,7 @@ private static boolean mayCreate(ActionContext context, Vec3d position) { return true; } - ServerWorld world = context.world(); + World world = context.world(); if (context.get(ItematicContextParameters.SIDE) == Direction.DOWN) { return false; } diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/DecorationEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/DecorationEntityInitializer.java index 23ee260d..b028fa5d 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/DecorationEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/DecorationEntityInitializer.java @@ -13,7 +13,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -51,7 +50,7 @@ public T create(ActionContext context, SpawnReason reason) { ); } - private T create(ServerWorld world, PlayerEntity player, BlockPos pos, Direction facing, ItemStack stack) { + private T create(World world, PlayerEntity player, BlockPos pos, Direction facing, ItemStack stack) { if (player == null || !this.checker.mayPlace(player, pos, facing, stack)) { return null; } diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EndCrystalEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EndCrystalEntityInitializer.java index cab7f7de..c1fbed22 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EndCrystalEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EndCrystalEntityInitializer.java @@ -23,7 +23,10 @@ private EndCrystalEntityInitializer() {} @Override public EndCrystalEntity create(ActionContext context, SpawnReason reason) { - ServerWorld world = context.world(); + if (!(context.world() instanceof ServerWorld world)) { + return null; + } + BlockPos pos = context.getBlockPos(ItematicContextParameters.INTERACTED_POSITION); if (pos == null) { return null; diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EyeOfEnderEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EyeOfEnderEntityInitializer.java index 343ede22..31f668e0 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EyeOfEnderEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/EyeOfEnderEntityInitializer.java @@ -23,7 +23,10 @@ private EyeOfEnderEntityInitializer() {} @Override public EyeOfEnderEntity create(ActionContext context, SpawnReason reason) { - ServerWorld world = context.world(); + if (!(context.world() instanceof ServerWorld world)) { + return null; + } + BlockPos blockPos = this.getBlockPos(context); if (blockPos == null) { return null; diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/MinecartEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/MinecartEntityInitializer.java index 9560dc79..9d2c0bb3 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/MinecartEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/MinecartEntityInitializer.java @@ -15,14 +15,14 @@ import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.tag.BlockTags; -import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public record MinecartEntityInitializer(EntityType type) implements EntityInitializer { @Override public T create(ActionContext context, SpawnReason reason) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.getBlockPos(ItematicContextParameters.INTERACTED_POSITION); if (pos == null) { return null; diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/SmallFireballEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/SmallFireballEntityInitializer.java index 3c52d3a7..387eebf7 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/SmallFireballEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/SmallFireballEntityInitializer.java @@ -7,10 +7,10 @@ import net.minecraft.entity.SpawnReason; import net.minecraft.entity.projectile.SmallFireballEntity; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; public class SmallFireballEntityInitializer implements EntityInitializer { public static final SmallFireballEntityInitializer INSTANCE = new SmallFireballEntityInitializer(); @@ -20,7 +20,7 @@ private SmallFireballEntityInitializer() {} @Override public SmallFireballEntity create(ActionContext context, SpawnReason reason) { - ServerWorld world = context.world(); + World world = context.world(); Random random = world.getRandom(); Direction direction = context.getOrDefault(ItematicContextParameters.SIDE, Direction.UP); double velocityX = random.nextTriangular(direction.getOffsetX(), VELOCITY_DEVIATION); diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/TridentEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/TridentEntityInitializer.java index 6f4c7675..ce8a87d4 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/TridentEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/TridentEntityInitializer.java @@ -11,7 +11,7 @@ import net.minecraft.entity.projectile.TridentEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.World; public class TridentEntityInitializer implements EntityInitializer { public static final TridentEntityInitializer INSTANCE = new TridentEntityInitializer(); @@ -34,7 +34,7 @@ public TridentEntity create(ActionContext context, SpawnReason reason) { return entity; } - private TridentEntity create(ServerWorld world, LivingEntity possibleUser, ItemStack stack) { + private TridentEntity create(World world, LivingEntity possibleUser, ItemStack stack) { if (possibleUser != null) { return new TridentEntity(world, possibleUser, stack); } diff --git a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/WindChargeEntityInitializer.java b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/WindChargeEntityInitializer.java index 87da153e..86f9cd16 100644 --- a/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/WindChargeEntityInitializer.java +++ b/src/main/java/net/errorcraft/itematic/entity/initializer/initializers/WindChargeEntityInitializer.java @@ -7,11 +7,11 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.WindChargeEntity; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; public class WindChargeEntityInitializer implements EntityInitializer { public static final WindChargeEntityInitializer INSTANCE = new WindChargeEntityInitializer(); @@ -21,7 +21,7 @@ private WindChargeEntityInitializer() {} @Override public WindChargeEntity create(ActionContext context, SpawnReason reason) { - ServerWorld world = context.world(); + World world = context.world(); PlayerEntity user = context.get(LootContextParameters.THIS_ENTITY, PlayerEntity.class); if (user != null) { return spawnFromUser(world, user); @@ -36,7 +36,7 @@ public WindChargeEntity create(ActionContext context, SpawnReason reason) { return null; } - private static WindChargeEntity spawnFromUser(ServerWorld world, PlayerEntity user) { + private static WindChargeEntity spawnFromUser(World world, PlayerEntity user) { Vec3d position = user.getEyePos().add(user.getRotationVecClient().multiply(0.8f)); if (!world.getBlockState(BlockPos.ofFloored(position)).isReplaceable()) { position = user.getEyePos().add(user.getRotationVecClient().multiply(0.05f)); @@ -45,7 +45,7 @@ private static WindChargeEntity spawnFromUser(ServerWorld world, PlayerEntity us return new WindChargeEntity(user, world, position.getX(), position.getY(), position.getZ()); } - private static WindChargeEntity spawnFromSide(ServerWorld world, Direction direction, Vec3d position) { + private static WindChargeEntity spawnFromSide(World world, Direction direction, Vec3d position) { Random random = world.getRandom(); double velocityX = random.nextTriangular(direction.getOffsetX(), VELOCITY_DEVIATION); double velocityY = random.nextTriangular(direction.getOffsetY(), VELOCITY_DEVIATION); diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java index 3cc7becb..512f6282 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/BlockItemComponent.java @@ -29,7 +29,6 @@ import net.minecraft.item.ItemUsageContext; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Hand; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.hit.BlockHitResult; @@ -145,12 +144,8 @@ public boolean place(ActionContext context, PositionTarget position, boolean dec } private ItemResult place(ItemUsageContext context, ItemStackExchanger stackExchanger) { - if (!(context.getWorld() instanceof ServerWorld world)) { - return ItemResult.SUCCEED; - } - ActionContext actionContext = new ItemPlacementContext(context) - .itematic$actionContext(world, stackExchanger); + .itematic$actionContext(stackExchanger); if (this.place(actionContext, PositionTarget.INTERACTED_POSITION, true)) { return ItemResult.SUCCEED; } @@ -161,6 +156,7 @@ private ItemResult place(ItemUsageContext context, ItemStackExchanger stackExcha public enum Pass implements StringIdentifiable { BLOCK("block"), FLUID("fluid"); + public static final Set DEFAULT_PASSES = Set.of(BLOCK); public static final Codec CODEC = StringIdentifiable.createCodec(Pass::values); diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java index f1e541cb..e4a3c653 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/BucketItemComponent.java @@ -34,7 +34,6 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryEntryLookup; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvent; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; @@ -49,7 +48,6 @@ public record BucketItemComponent(WorldModification modification, Optional[] drainFluid(RegistryEntryLookup dispenseBehaviors) { return new ItemComponent[] { StackableItemComponent.of(16), @@ -106,16 +104,12 @@ public Codec codec() { @Override public ItemResult use(World world, PlayerEntity user, Hand hand, ItemStack stack, ItemStackExchanger stackExchanger) { - if (world.isClient()) { - return ItemResult.PASS; - } - BlockHitResult blockHitResult = ItemAccessor.raycast(world, user, this.modification().fluidHandling()); if (blockHitResult.getType() != HitResult.Type.BLOCK) { return ItemResult.PASS; } - ActionContext context = ActionContext.builder((ServerWorld) world) + ActionContext context = ActionContext.builder(world) .stackExchanger(stackExchanger) .addOptional(LootContextParameters.THIS_ENTITY, user) .addOptional(LootContextParameters.ORIGIN, user, Entity::getPos) diff --git a/src/main/java/net/errorcraft/itematic/item/component/components/ThrowableItemComponent.java b/src/main/java/net/errorcraft/itematic/item/component/components/ThrowableItemComponent.java index f55b8500..3dc28ab5 100644 --- a/src/main/java/net/errorcraft/itematic/item/component/components/ThrowableItemComponent.java +++ b/src/main/java/net/errorcraft/itematic/item/component/components/ThrowableItemComponent.java @@ -92,24 +92,25 @@ public boolean stopUsing(ItemStack stack, World world, LivingEntity user, int us private void createEntity(World world, LivingEntity user, ItemStack stack, ItemStackExchanger stackExchanger) { if (world instanceof ServerWorld serverWorld) { - ActionContext.Builder contextBuilder = ActionContext.builder(serverWorld) + ActionContext context = ActionContext.builder(serverWorld) .stackExchanger(stackExchanger) .add(LootContextParameters.TOOL, stack) .add(LootContextParameters.THIS_ENTITY, user) .add(LootContextParameters.ORIGIN, user.getPos()) - .add(ItematicContextParameters.INTERACTED_POSITION, user.getEyePos().add(0.0d, -0.1d, 0.0d)); - this.createEntity(contextBuilder, serverWorld, stack); + .add(ItematicContextParameters.INTERACTED_POSITION, user.getEyePos().add(0.0d, -0.1d, 0.0d)) + .build(); + this.createEntity(context, serverWorld, stack); } } - private void createEntity(ActionContext.Builder contextBuilder, ServerWorld world, ItemStack stack) { + private void createEntity(ActionContext context, ServerWorld world, ItemStack stack) { ProjectileItemComponent projectile = stack.itematic$getBehavior(ItemComponentTypes.PROJECTILE).orElse(null); if (projectile == null) { return; } Entity projectileEntity = projectile.createEntity( - contextBuilder.build(), + context, PositionTarget.INTERACTED_POSITION, this.angleOffset, this.speed, @@ -120,7 +121,8 @@ private void createEntity(ActionContext.Builder contextBuilder, ServerWorld worl } world.spawnEntity(projectileEntity); - ActionContext projectileContext = contextBuilder.add(ItematicContextParameters.TARGET_ENTITY, projectileEntity) + ActionContext projectileContext = context.extend() + .add(ItematicContextParameters.TARGET_ENTITY, projectileEntity) .build(); stack.itematic$invokeEvent(ItemEvents.THROW_PROJECTILE, projectileContext); } diff --git a/src/main/java/net/errorcraft/itematic/item/placement/EntityPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/EntityPlacer.java index b5648388..9aa338e0 100644 --- a/src/main/java/net/errorcraft/itematic/item/placement/EntityPlacer.java +++ b/src/main/java/net/errorcraft/itematic/item/placement/EntityPlacer.java @@ -20,6 +20,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; import java.util.Objects; @@ -69,7 +70,7 @@ private boolean modifySpawnerBlock(BlockPos pos, BlockState state) { return false; } - ServerWorld world = this.context.world(); + World world = this.context.world(); if (!state.isOf(Blocks.SPAWNER)) { return false; } @@ -84,7 +85,7 @@ private boolean modifySpawnerBlock(BlockPos pos, BlockState state) { return true; } - private void modifySpawnerBlock(ServerWorld world, MobSpawnerBlockEntity blockEntity, BlockPos pos, BlockState state) { + private void modifySpawnerBlock(World world, MobSpawnerBlockEntity blockEntity, BlockPos pos, BlockState state) { blockEntity.setEntityType(this.type, world.getRandom()); blockEntity.markDirty(); world.updateListeners(pos, state, state, Block.NOTIFY_ALL); @@ -96,12 +97,15 @@ private void modifySpawnerBlock(ServerWorld world, MobSpawnerBlockEntity blockEn } private T spawn(BlockPos pos, BlockState state) { - ServerWorld world = this.context.world(); + if (!(this.context.world() instanceof ServerWorld world)) { + return null; + } + Direction side = this.context.get(ItematicContextParameters.SIDE); BlockPos offset = state.getCollisionShape(world, pos).isEmpty() || side == null ? pos : pos.offset(side); - T entity = this.spawn(offset, !Objects.equals(pos, offset) && side == Direction.UP); + T entity = this.spawn(world, offset, !Objects.equals(pos, offset) && side == Direction.UP); if (entity == null) { return null; } @@ -119,7 +123,7 @@ private T spawn(BlockPos pos, BlockState state) { return entity; } - private T spawn(BlockPos pos, boolean invertY) { + private T spawn(ServerWorld world, BlockPos pos, boolean invertY) { T entity = this.type.itematic$create( this.context, this.spawnReason, @@ -132,7 +136,7 @@ private T spawn(BlockPos pos, boolean invertY) { return null; } - this.context.world().spawnEntityAndPassengers(entity); + world.spawnEntityAndPassengers(entity); return entity; } diff --git a/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java index 2eed452f..b3053674 100644 --- a/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java +++ b/src/main/java/net/errorcraft/itematic/item/placement/block/BlockPlacer.java @@ -20,11 +20,11 @@ import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; import org.jetbrains.annotations.Nullable; @@ -36,7 +36,7 @@ public class BlockPlacer { @Nullable private final RegistryEntry placeSound; - public BlockPlacer(ActionContext context, PositionTarget position, BlockPicker block, ItemPlacementContext placementContext, boolean operatorOnly, @Nullable RegistryEntry placeSound) { + private BlockPlacer(ActionContext context, BlockPicker block, ItemPlacementContext placementContext, boolean operatorOnly, @Nullable RegistryEntry placeSound) { this.context = context; this.block = block; this.placementContext = placementContext; @@ -47,7 +47,6 @@ public BlockPlacer(ActionContext context, PositionTarget position, BlockPicker block, boolean operatorOnly, RegistryEntry placeSound) { return new BlockPlacer( context, - position, block, context.blockPlaceContext(position, block), operatorOnly, @@ -76,7 +75,7 @@ public boolean place() { } private void placed(BlockState blockState, BlockPos pos, @Nullable LivingEntity placer) { - ServerWorld world = this.context.world(); + World world = this.context.world(); ItemStack stack = this.context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY); blockState = this.placeFromNbt(blockState, pos, stack); BlockEntity blockEntity = world.getBlockEntity(pos); @@ -120,7 +119,7 @@ private boolean canPlace(BlockState state, BlockPos pos, @Nullable LivingEntity } ShapeContext shapeContext = ShapeContexts.ofNullable(placer); - ServerWorld world = this.context.world(); + World world = this.context.world(); return state.canPlaceAt(world, pos) && world.canPlace(state, pos, shapeContext); } diff --git a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java index 62e844ed..a7adf468 100644 --- a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java +++ b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidDrainer.java @@ -13,9 +13,9 @@ import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; import net.minecraft.stat.Stats; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; import org.jetbrains.annotations.Nullable; @@ -35,7 +35,7 @@ public ItemStack drain() { return null; } - ServerWorld world = this.context.world(); + World world = this.context.world(); BlockState state = world.getBlockState(pos); if (!(state.getBlock() instanceof FluidDrainable fluidDrainable)) { return null; diff --git a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java index 13cc4ed3..27a09426 100644 --- a/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java +++ b/src/main/java/net/errorcraft/itematic/item/placement/fluid/FluidPlacer.java @@ -22,6 +22,7 @@ import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; public class FluidPlacer { @@ -66,7 +67,7 @@ private boolean shouldOffset(BlockPos pos) { return true; } - ServerWorld world = this.context.world(); + World world = this.context.world(); BlockState state = world.getBlockState(pos); if (!(state.getBlock() instanceof FluidFillable fluidFillable)) { return true; @@ -94,7 +95,10 @@ private boolean tryPlaceFluid(BlockPos pos) { } private boolean tryEvaporate(BlockPos pos) { - ServerWorld world = this.context.world(); + if (!(context.world() instanceof ServerWorld world)) { + return false; + } + if (!world.getDimension().ultrawarm()) { return false; } @@ -149,7 +153,7 @@ private boolean tryPlaceFluidBlock(BlockPos pos, BlockState state, Fluid fluid) return false; } - ServerWorld world = this.context.world(); + World world = this.context.world(); if (!state.isAir() && !state.isLiquid()) { world.breakBlock(pos, true); } @@ -167,7 +171,7 @@ private void playPlaceSound(BlockPos pos) { return; } - ServerWorld world = this.context.world(); + World world = this.context.world(); Entity possiblePlacer = this.context.get(LootContextParameters.THIS_ENTITY); world.playSound(possiblePlacer, pos, this.placeSound.value(), SoundCategory.BLOCKS, 1.0f, 1.0f); world.emitGameEvent(possiblePlacer, GameEvent.FLUID_PLACE, pos); diff --git a/src/main/java/net/errorcraft/itematic/mixin/entity/EntityTypeExtender.java b/src/main/java/net/errorcraft/itematic/mixin/entity/EntityTypeExtender.java index 45f15810..5eaf060b 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/entity/EntityTypeExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/entity/EntityTypeExtender.java @@ -445,9 +445,13 @@ private T useEntityInitializer(EntityType.EntityFactory instance, EntityType< @Override public T itematic$create(ActionContext context, SpawnReason reason, BlockPos pos, @Nullable EntitySpawnCallback callback, boolean allowItemData, boolean invertY) { + if (!(context.world() instanceof ServerWorld world)) { + return null; + } + this.actionContext = context; return this.create( - context.world(), + world, copier(context, callback, allowItemData), pos, reason, diff --git a/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java b/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java index e6f37fd2..ce01eda5 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/item/ItemPlacementContextExtender.java @@ -9,7 +9,6 @@ import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemUsageContext; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import org.spongepowered.asm.mixin.Mixin; @@ -28,8 +27,8 @@ public ItemPlacementContextExtender(PlayerEntity player, Hand hand, BlockHitResu } @Override - public ActionContext itematic$actionContext(ServerWorld world, ItemStackExchanger stackExchanger) { - return ActionContext.builder(world) + public ActionContext itematic$actionContext(ItemStackExchanger stackExchanger) { + return ActionContext.builder(this.getWorld()) .stackExchanger(stackExchanger) .addOptional(LootContextParameters.THIS_ENTITY, this.getPlayer()) .addOptional(LootContextParameters.ORIGIN, this.getPlayer(), Entity::getPos) diff --git a/src/main/java/net/errorcraft/itematic/mixin/item/ItemStackExtender.java b/src/main/java/net/errorcraft/itematic/mixin/item/ItemStackExtender.java index b298d4a6..c7fd525c 100644 --- a/src/main/java/net/errorcraft/itematic/mixin/item/ItemStackExtender.java +++ b/src/main/java/net/errorcraft/itematic/mixin/item/ItemStackExtender.java @@ -748,11 +748,15 @@ public boolean canBeEnchantedWith(RegistryEntry enchantment, Enchan @Override public void itematic$damage(int amount, ActionContext context) { + if (!(context.world() instanceof ServerWorld world)) { + return; + } + this.context = context; Entity entity = context.get(LootContextParameters.THIS_ENTITY); this.damage( amount, - context.world(), + world, entity instanceof ServerPlayerEntity player ? player : null, item -> this.onItemBroken(item, entity, context) ); diff --git a/src/main/java/net/errorcraft/itematic/world/action/ActionEntry.java b/src/main/java/net/errorcraft/itematic/world/action/ActionEntry.java index 7f87a97b..e0f9a2a7 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/ActionEntry.java +++ b/src/main/java/net/errorcraft/itematic/world/action/ActionEntry.java @@ -54,6 +54,10 @@ private boolean test(ActionContext context) { LootCondition requirements = this.requirements.get(); LootContext lootContext = context.lootContext(); + if (lootContext == null) { + return false; + } + lootContext.markActive(LootContext.predicate(requirements)); return requirements.test(lootContext); } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/AttachLeashedEntitiesOnBlockAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/AttachLeashedEntitiesOnBlockAction.java index 511fff23..4ebd6cc3 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/AttachLeashedEntitiesOnBlockAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/AttachLeashedEntitiesOnBlockAction.java @@ -11,8 +11,8 @@ import net.minecraft.item.LeadItem; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.tag.BlockTags; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public record AttachLeashedEntitiesOnBlockAction(PositionTarget position) implements Action { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -31,7 +31,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { BlockPos pos = context.getBlockPos(this.position.parameter()); - ServerWorld world = context.world(); + World world = context.world(); if (!world.getBlockState(pos).isIn(BlockTags.FENCES)) { return false; } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/ChargeRespawnAnchorAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/ChargeRespawnAnchorAction.java index 70f99f0a..efc33aa6 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/ChargeRespawnAnchorAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/ChargeRespawnAnchorAction.java @@ -11,8 +11,8 @@ import net.minecraft.block.Blocks; import net.minecraft.block.RespawnAnchorBlock; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public record ChargeRespawnAnchorAction(PositionTarget position) implements Action { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -30,7 +30,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.getBlockPos(this.position.parameter()); if (pos == null) { return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/DisplayParticleAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/DisplayParticleAction.java index 7308f539..a0f13708 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/DisplayParticleAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/DisplayParticleAction.java @@ -39,7 +39,10 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + if (!(context.world() instanceof ServerWorld world)) { + return false; + } + Random random = world.getRandom(); Vec3d pos = this.position(context, random); if (pos == null) { diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/FertilizeAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/FertilizeAction.java index 1152143b..9496a805 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/FertilizeAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/FertilizeAction.java @@ -9,10 +9,10 @@ import net.errorcraft.itematic.world.action.context.ActionContext; import net.errorcraft.itematic.world.action.context.PositionTarget; import net.minecraft.item.BoneMealItem; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import net.minecraft.world.WorldEvents; public record FertilizeAction(PositionTarget position) implements Action { @@ -37,7 +37,7 @@ public boolean execute(ActionContext context) { } BlockPos blockPos = BlockPos.ofFloored(pos); - ServerWorld world = context.world(); + World world = context.world(); if (BoneMealItem.useOnFertilizable(null, world, blockPos)) { fertilized(world, blockPos); return true; @@ -57,7 +57,7 @@ public boolean execute(ActionContext context) { return false; } - private static void fertilized(ServerWorld world, BlockPos pos) { + private static void fertilized(World world, BlockPos pos) { world.syncWorldEvent(WorldEvents.BONE_MEAL_USED, pos, 15); } } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/LightEndPortalAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/LightEndPortalAction.java index 72a08805..08b82d79 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/LightEndPortalAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/LightEndPortalAction.java @@ -11,8 +11,8 @@ import net.minecraft.block.Blocks; import net.minecraft.block.EndPortalFrameBlock; import net.minecraft.block.pattern.BlockPattern; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.WorldEvents; public record LightEndPortalAction(PositionTarget position) implements Action { @@ -32,7 +32,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.getBlockPos(this.position.parameter()); BlockPattern.Result result = EndPortalFrameBlock.getCompletedFramePattern() .searchAround(world, pos); diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/MarkBannerOnItemAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/MarkBannerOnItemAction.java index 6f989aca..cd5a4051 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/MarkBannerOnItemAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/MarkBannerOnItemAction.java @@ -13,8 +13,8 @@ import net.minecraft.item.map.MapState; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.tag.BlockTags; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public record MarkBannerOnItemAction(PositionTarget position) implements Action { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -37,7 +37,7 @@ public boolean execute(ActionContext context) { return false; } - ServerWorld world = context.world(); + World world = context.world(); if (!world.getBlockState(pos).isIn(BlockTags.BANNERS)) { return false; } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyBlockStateAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyBlockStateAction.java index 964e0cbf..ecb4aa22 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyBlockStateAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyBlockStateAction.java @@ -11,9 +11,9 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.component.type.BlockStateComponent; -import net.minecraft.server.world.ServerWorld; import net.minecraft.state.property.Property; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import java.util.HashMap; import java.util.Map; @@ -36,7 +36,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.getBlockPos(this.position.parameter()); if (pos == null) { return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyItemAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyItemAction.java index ee2cacc5..6bce9d7f 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyItemAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/ModifyItemAction.java @@ -48,6 +48,10 @@ public boolean execute(ActionContext context) { } LootContext lootContext = context.lootContext(); + if (lootContext == null) { + return false; + } + lootContext.markActive(LootContext.itemModifier(this.itemModifier)); ItemStack resultStack = this.itemModifier.apply(stack, lootContext); if (resultStack != stack) { diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceCarvedPumpkinAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceCarvedPumpkinAction.java index 640ad91e..93ea63bb 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceCarvedPumpkinAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaceCarvedPumpkinAction.java @@ -11,8 +11,8 @@ import net.minecraft.block.Blocks; import net.minecraft.block.CarvedPumpkinBlock; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; public record PlaceCarvedPumpkinAction(PositionTarget position) implements Action { @@ -36,7 +36,7 @@ public boolean execute(ActionContext context) { return false; } - ServerWorld world = context.world(); + World world = context.world(); if (!world.isAir(pos)) { return false; } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaySoundAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaySoundAction.java index eab58d0e..9f1f4529 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/PlaySoundAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/PlaySoundAction.java @@ -12,12 +12,12 @@ import net.minecraft.entity.Entity; import net.minecraft.loot.context.LootContextParameters; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; import java.util.Optional; @@ -70,7 +70,7 @@ public boolean execute(ActionContext context) { return false; } - ServerWorld world = context.world(); + World world = context.world(); Random random = world.getRandom(); float volume = this.volume.get(random); float pitch = this.pitch.get(random); diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/PrimeTntAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/PrimeTntAction.java index 2e828d5c..ff951f14 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/PrimeTntAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/PrimeTntAction.java @@ -31,12 +31,15 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { + if (!(context.world() instanceof ServerWorld world)) { + return false; + } + BlockPos pos = context.get(this.position.parameter(), BlockPos::ofFloored); if (pos == null) { return false; } - ServerWorld world = context.world(); PlayerEntity player = context.get(LootContextParameters.THIS_ENTITY, PlayerEntity.class); if (TntBlockAccessor.primeTnt(world, pos, player)) { world.removeBlock(pos, false); diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/RunFunctionAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/RunFunctionAction.java index 27c5c5d6..69e029e8 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/RunFunctionAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/RunFunctionAction.java @@ -9,6 +9,7 @@ import net.errorcraft.itematic.world.action.context.PositionTarget; import net.minecraft.command.ReturnValueConsumer; import net.minecraft.loot.context.LootContext; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.function.CommandFunction; import net.minecraft.server.function.CommandFunctionManager; @@ -31,7 +32,12 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - CommandFunctionManager functionManager = context.world().getServer().getCommandFunctionManager(); + MinecraftServer server = context.world().getServer(); + if (server == null) { + return false; + } + + CommandFunctionManager functionManager = server.getCommandFunctionManager(); Optional> function = functionManager.getFunction(this.function); if (function.isEmpty()) { return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/SetBlockStateAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/SetBlockStateAction.java index 857ae858..4b0953b6 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/SetBlockStateAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/SetBlockStateAction.java @@ -10,8 +10,8 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; public record SetBlockStateAction(PositionTarget position, BlockState state) implements Action { @@ -31,7 +31,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.getBlockPos(this.position.parameter()); if (pos == null) { return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/ShearAtPositionAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/ShearAtPositionAction.java index 1ed4a316..34db9c02 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/ShearAtPositionAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/ShearAtPositionAction.java @@ -29,12 +29,15 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { + if (!(context.world() instanceof ServerWorld world)) { + return false; + } + BlockPos pos = context.getBlockPos(this.position.parameter()); if (pos == null) { return false; } - ServerWorld world = context.world(); return ShearsDispenserBehaviorAccessor.tryShearBlock(world, pos) || ShearsDispenserBehaviorAccessor.tryShearEntity(world, pos, context.getOrDefault(LootContextParameters.TOOL, ItemStack.EMPTY)); } diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/TeleportAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/TeleportAction.java index 40ccbe3e..8e2a584e 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/TeleportAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/TeleportAction.java @@ -35,9 +35,13 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { + if (!(context.world() instanceof ServerWorld world)) { + return false; + } + Entity entity = context.get(this.entity.getParameter()); if (entity instanceof LivingEntity target) { - return this.teleport(target, context.world()); + return this.teleport(target, world); } return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/actions/WaxBlockAction.java b/src/main/java/net/errorcraft/itematic/world/action/actions/WaxBlockAction.java index a433f040..7e606ad1 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/actions/WaxBlockAction.java +++ b/src/main/java/net/errorcraft/itematic/world/action/actions/WaxBlockAction.java @@ -11,8 +11,8 @@ import net.minecraft.entity.Entity; import net.minecraft.item.HoneycombItem; import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.WorldEvents; import net.minecraft.world.event.GameEvent; @@ -32,7 +32,7 @@ public ActionType type() { @Override public boolean execute(ActionContext context) { - ServerWorld world = context.world(); + World world = context.world(); BlockPos pos = context.get(this.position.parameter(), BlockPos::ofFloored); if (pos == null) { return false; diff --git a/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java b/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java index 5f1a39a6..c3c32fcf 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java +++ b/src/main/java/net/errorcraft/itematic/world/action/context/ActionContext.java @@ -20,6 +20,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,17 +29,17 @@ import java.util.function.Function; public class ActionContext { - private final ServerWorld world; + private final World world; private final ContextParameterMap parameters; private final ItemStackExchanger stackExchanger; - private ActionContext(ServerWorld world, ContextParameterMap parameters, ItemStackExchanger stackExchanger) { + private ActionContext(World world, ContextParameterMap parameters, ItemStackExchanger stackExchanger) { this.world = world; this.parameters = parameters; this.stackExchanger = stackExchanger; } - public static Builder builder(ServerWorld world) { + public static Builder builder(World world) { return new Builder(world); } @@ -46,14 +47,10 @@ public Builder extend() { return new Builder(this); } - public ServerWorld world() { + public World world() { return this.world; } - public ItemStackExchanger stackExchanger() { - return this.stackExchanger; - } - public boolean has(ContextParameter parameter) { return this.parameters.contains(parameter); } @@ -100,9 +97,14 @@ public void exchangeStack(ItemStack stack) { this.stackExchanger.exchange(stack); } + @Nullable public LootContext lootContext() { + if (!(this.world instanceof ServerWorld serverWorld)) { + return null; + } + LootWorldContext context = new LootWorldContext( - this.world, + serverWorld, this.parameters, Map.of(), 0.0f @@ -168,11 +170,11 @@ private ItemPlacementContext blockPlaceContext(Vec3d pos, Direction side) { } public static class Builder { - private final ServerWorld world; + private final World world; private ItemStackExchanger stackExchanger = ItemStackExchanger.EMPTY; private final ContextParameterMap.Builder parameters = new ContextParameterMap.Builder(); - private Builder(ServerWorld world) { + private Builder(World world) { this.world = world; } @@ -228,8 +230,7 @@ public Builder addOptional(ContextParameter parameter, @Nullable U val return this; } - this.addOptional(parameter, mapper.apply(value)); - return this; + return this.addOptional(parameter, mapper.apply(value)); } } } diff --git a/src/main/java/net/errorcraft/itematic/world/action/context/ItemStackExchanger.java b/src/main/java/net/errorcraft/itematic/world/action/context/ItemStackExchanger.java index 2a0e77af..683e96a5 100644 --- a/src/main/java/net/errorcraft/itematic/world/action/context/ItemStackExchanger.java +++ b/src/main/java/net/errorcraft/itematic/world/action/context/ItemStackExchanger.java @@ -3,9 +3,9 @@ import net.minecraft.block.dispenser.ItemDispenserBehavior; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import java.util.Objects; import java.util.function.Consumer; @@ -36,7 +36,7 @@ public static ItemStackExchanger forEntity(LivingEntity entity, ItemStack initia ); } - public static ItemStackExchanger forDispenser(ServerWorld world, Direction side, Vec3d pos, ItemStack initialStack) { + public static ItemStackExchanger forDispenser(World world, Direction side, Vec3d pos, ItemStack initialStack) { return new ItemStackExchanger( stack -> true, stack -> ItemDispenserBehavior.spawnItem(world, stack, 6, side, pos), @@ -54,10 +54,14 @@ public void exchange(ItemStack stack) { return; } - if (!this.currentStack.isEmpty() && this.shouldDrop.test(this.currentStack)) { - this.dropper.accept(this.currentStack); + if (!this.shouldDrop.test(stack)) { + return; } - this.currentStack = stack; + if (this.currentStack.isEmpty()) { + this.currentStack = stack; + } else { + this.dropper.accept(stack); + } } }