mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-30 21:23:00 +00:00 
			
		
		
		
	Rethink PlatformHelper.useOn
useOn is now only responsible for firing the actual mod loader events, and just returns the result of firing that event. The actual calling of Block.use/Item.useOn now live in TurtlePlaceCommand. This isn't especially useful for 1.20.1, but is more relevant on 1.21.1 when we look at #2011, as the shared code is much larger.
This commit is contained in:
		| @@ -39,6 +39,7 @@ import net.minecraft.world.item.CreativeModeTab; | ||||
| import net.minecraft.world.item.DyeColor; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.context.UseOnContext; | ||||
| import net.minecraft.world.item.crafting.Recipe; | ||||
| import net.minecraft.world.level.Level; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| @@ -53,7 +54,6 @@ import java.util.List; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Function; | ||||
| import java.util.function.Predicate; | ||||
| 
 | ||||
| /** | ||||
|  * This extends {@linkplain dan200.computercraft.impl.PlatformHelper the API's loader abstraction layer}, adding | ||||
| @@ -375,20 +375,40 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper | ||||
|     boolean interactWithEntity(ServerPlayer player, Entity entity, Vec3 hitPos); | ||||
| 
 | ||||
|     /** | ||||
|      * Place an item against a block. | ||||
|      * <p> | ||||
|      * Implementations should largely mirror {@link ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult)} | ||||
|      * (including any loader-specific modifications), except the call to {@link BlockState#use(Level, Player, InteractionHand, BlockHitResult)} | ||||
|      * should only be evaluated when {@code canUseBlock} evaluates to true. | ||||
|      * | ||||
|      * @param player      The player which is placing this item. | ||||
|      * @param stack       The item to place. | ||||
|      * @param hit         The collision with the block we're placing against. | ||||
|      * @param canUseBlock Test whether the block should be interacted with first. | ||||
|      * @return Whether any interaction occurred. | ||||
|      * @see ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult) | ||||
|      * The result of attempting to use an item on a block. | ||||
|      */ | ||||
|     InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit, Predicate<BlockState> canUseBlock); | ||||
|     sealed interface UseOnResult { | ||||
|         /** | ||||
|          * This interaction was intercepted by an event, and handled. | ||||
|          * | ||||
|          * @param result The result of using an item on a block. | ||||
|          */ | ||||
|         record Handled(InteractionResult result) implements UseOnResult { | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * This result was not handled, and should be handled by the caller. | ||||
|          * | ||||
|          * @param block Whether the block may be used ({@link BlockState#use(Level, Player, InteractionHand, BlockHitResult)}). | ||||
|          * @param item  Whether the item may be used on the block ({@link ItemStack#useOn(UseOnContext)}). | ||||
|          * @see ServerPlayerGameMode#useItemOn(ServerPlayer, Level, ItemStack, InteractionHand, BlockHitResult) | ||||
|          */ | ||||
|         record Continue(boolean block, boolean item) implements UseOnResult { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Run mod-loader specific code before placing an item against a block. | ||||
|      * <p> | ||||
|      * This should dispatch any mod-loader specific events that are fired when clicking a block. It does necessarily | ||||
|      * handle the actual clicking of the block — see {@link UseOnResult.Handled} and {@link UseOnResult.Continue}. | ||||
|      * | ||||
|      * @param player The player which is placing this item. | ||||
|      * @param stack  The item to place. | ||||
|      * @param hit    The collision with the block we're placing against. | ||||
|      * @return Whether any interaction occurred. | ||||
|      */ | ||||
|     UseOnResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit); | ||||
| 
 | ||||
|     /** | ||||
|      * Whether {@link net.minecraft.network.chat.ClickEvent.Action#RUN_COMMAND} can be used to run client commands. | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import net.minecraft.world.phys.Vec3; | ||||
| /** | ||||
|  * An object that holds a pocket computer item. | ||||
|  */ | ||||
| public sealed interface PocketHolder permits PocketHolder.EntityHolder { | ||||
| public sealed interface PocketHolder { | ||||
|     /** | ||||
|      * The level this holder is in. | ||||
|      * | ||||
| @@ -54,7 +54,7 @@ public sealed interface PocketHolder permits PocketHolder.EntityHolder { | ||||
|     /** | ||||
|      * An {@link Entity} holding a pocket computer. | ||||
|      */ | ||||
|     sealed interface EntityHolder extends PocketHolder permits PocketHolder.PlayerHolder, PocketHolder.ItemEntityHolder { | ||||
|     sealed interface EntityHolder extends PocketHolder { | ||||
|         /** | ||||
|          * Get the entity holding this pocket computer. | ||||
|          * | ||||
|   | ||||
| @@ -202,11 +202,22 @@ public class TurtlePlaceCommand implements TurtleCommand { | ||||
|      * @return If this item was deployed. | ||||
|      */ | ||||
|     private static InteractionResult doDeployOnBlock(ItemStack stack, TurtlePlayer turtlePlayer, BlockHitResult hit, boolean adjacent) { | ||||
|         var result = PlatformHelper.get().useOn( | ||||
|             turtlePlayer.player(), stack, hit, | ||||
|             adjacent ? x -> x.is(ComputerCraftTags.Blocks.TURTLE_CAN_USE) : x -> false | ||||
|         ); | ||||
|         if (result != InteractionResult.PASS) return result; | ||||
|         var result = PlatformHelper.get().useOn(turtlePlayer.player(), stack, hit); | ||||
|         if (result instanceof PlatformHelper.UseOnResult.Handled handled) { | ||||
|             if (handled.result() != InteractionResult.PASS) return handled.result(); | ||||
|         } else { | ||||
|             var canUse = (PlatformHelper.UseOnResult.Continue) result; | ||||
| 
 | ||||
|             var player = turtlePlayer.player(); | ||||
|             var block = player.level().getBlockState(hit.getBlockPos()); | ||||
|             if (adjacent && canUse.block() && block.is(ComputerCraftTags.Blocks.TURTLE_CAN_USE)) { | ||||
|                 var useResult = block.use(player.level(), player, InteractionHand.MAIN_HAND, hit); | ||||
|                 if (useResult.consumesAction()) return useResult; | ||||
|             } | ||||
| 
 | ||||
|             var useOnResult = stack.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, hit)); | ||||
|             if (useOnResult != InteractionResult.PASS) return useOnResult; | ||||
|         } | ||||
| 
 | ||||
|         var level = turtlePlayer.player().level(); | ||||
| 
 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ import net.minecraft.world.entity.decoration.ArmorStand; | ||||
| import net.minecraft.world.entity.player.Player; | ||||
| import net.minecraft.world.item.Item; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.item.context.UseOnContext; | ||||
| import net.minecraft.world.item.enchantment.EnchantmentHelper; | ||||
| import net.minecraft.world.level.BlockGetter; | ||||
| import net.minecraft.world.level.Level; | ||||
| @@ -343,8 +344,12 @@ public class TurtleTool extends AbstractTurtleUpgrade { | ||||
|         } | ||||
| 
 | ||||
|         var hit = TurtlePlaceCommand.getHitResult(position, direction.getOpposite()); | ||||
|         var result = PlatformHelper.get().useOn(turtlePlayer.player(), stack, hit, x -> false); | ||||
|         return result.consumesAction(); | ||||
|         var result = PlatformHelper.get().useOn(turtlePlayer.player(), stack, hit); | ||||
|         if (result instanceof PlatformHelper.UseOnResult.Handled handled) { | ||||
|             return handled.result().consumesAction(); | ||||
|         } else { | ||||
|             return ((PlatformHelper.UseOnResult.Continue) result).item() && item.useOn(new UseOnContext(turtlePlayer.player(), InteractionHand.MAIN_HAND, hit)).consumesAction(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static boolean isTriviallyBreakable(BlockGetter reader, BlockPos pos, BlockState state) { | ||||
|   | ||||
| @@ -59,7 +59,6 @@ import java.util.List; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Function; | ||||
| import java.util.function.Predicate; | ||||
| 
 | ||||
| @AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class }) | ||||
| public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper { | ||||
| @@ -223,7 +222,7 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public InteractionResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit, Predicate<BlockState> canUseBlock) { | ||||
|     public UseOnResult useOn(ServerPlayer player, ItemStack stack, BlockHitResult hit) { | ||||
|         throw new UnsupportedOperationException("Cannot interact with the world inside tests"); | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -142,6 +142,22 @@ class Turtle_Test { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks that turtles cannot place items into non-adjacent blocks. | ||||
|      * | ||||
|      * See [ComputerCraftTags.Blocks.TURTLE_CAN_USE]. | ||||
|      */ | ||||
|     @GameTest | ||||
|     fun Place_into_composter_non_adjacent(helper: GameTestHelper) = helper.sequence { | ||||
|         thenOnComputer { | ||||
|             turtle.place(ObjectArguments()).await() | ||||
|                 .assertArrayEquals(false, "Cannot place item here", message = "Failed to place item") | ||||
|         } | ||||
|         thenExecute { | ||||
|             helper.assertBlockIs(BlockPos(2, 2, 3)) { it.block == Blocks.COMPOSTER && it.getValue(ComposterBlock.LEVEL) == 0 } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks that turtles can place bottles into beehives. | ||||
|      * | ||||
|   | ||||
| @@ -0,0 +1,138 @@ | ||||
| { | ||||
|     DataVersion: 3465, | ||||
|     size: [5, 5, 5], | ||||
|     data: [ | ||||
|         {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, | ||||
|         {pos: [0, 1, 0], state: "minecraft:air"}, | ||||
|         {pos: [0, 1, 1], state: "minecraft:air"}, | ||||
|         {pos: [0, 1, 2], state: "minecraft:air"}, | ||||
|         {pos: [0, 1, 3], state: "minecraft:air"}, | ||||
|         {pos: [0, 1, 4], state: "minecraft:air"}, | ||||
|         {pos: [1, 1, 0], state: "minecraft:air"}, | ||||
|         {pos: [1, 1, 1], state: "minecraft:air"}, | ||||
|         {pos: [1, 1, 2], state: "minecraft:air"}, | ||||
|         {pos: [1, 1, 3], state: "minecraft:air"}, | ||||
|         {pos: [1, 1, 4], state: "minecraft:air"}, | ||||
|         {pos: [2, 1, 0], state: "minecraft:air"}, | ||||
|         {pos: [2, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:pumpkin_pie"}], Label: "turtle_test.place_into_composter_non_adjacent", On: 1b, Owner: {LowerId: -7298459922670553123L, Name: "Player572", UpperId: -8225029765375707172L}, Slot: 0, id: "computercraft:turtle_normal"}}, | ||||
|         {pos: [2, 1, 2], state: "minecraft:air"}, | ||||
|         {pos: [2, 1, 3], state: "minecraft:composter{level:0}"}, | ||||
|         {pos: [2, 1, 4], state: "minecraft:air"}, | ||||
|         {pos: [3, 1, 0], state: "minecraft:air"}, | ||||
|         {pos: [3, 1, 1], state: "minecraft:air"}, | ||||
|         {pos: [3, 1, 2], state: "minecraft:air"}, | ||||
|         {pos: [3, 1, 3], state: "minecraft:air"}, | ||||
|         {pos: [3, 1, 4], state: "minecraft:air"}, | ||||
|         {pos: [4, 1, 0], state: "minecraft:air"}, | ||||
|         {pos: [4, 1, 1], state: "minecraft:air"}, | ||||
|         {pos: [4, 1, 2], state: "minecraft:air"}, | ||||
|         {pos: [4, 1, 3], state: "minecraft:air"}, | ||||
|         {pos: [4, 1, 4], state: "minecraft:air"}, | ||||
|         {pos: [0, 2, 0], state: "minecraft:air"}, | ||||
|         {pos: [0, 2, 1], state: "minecraft:air"}, | ||||
|         {pos: [0, 2, 2], state: "minecraft:air"}, | ||||
|         {pos: [0, 2, 3], state: "minecraft:air"}, | ||||
|         {pos: [0, 2, 4], state: "minecraft:air"}, | ||||
|         {pos: [1, 2, 0], state: "minecraft:air"}, | ||||
|         {pos: [1, 2, 1], state: "minecraft:air"}, | ||||
|         {pos: [1, 2, 2], state: "minecraft:air"}, | ||||
|         {pos: [1, 2, 3], state: "minecraft:air"}, | ||||
|         {pos: [1, 2, 4], state: "minecraft:air"}, | ||||
|         {pos: [2, 2, 0], state: "minecraft:air"}, | ||||
|         {pos: [2, 2, 1], state: "minecraft:air"}, | ||||
|         {pos: [2, 2, 2], state: "minecraft:air"}, | ||||
|         {pos: [2, 2, 3], state: "minecraft:air"}, | ||||
|         {pos: [2, 2, 4], state: "minecraft:air"}, | ||||
|         {pos: [3, 2, 0], state: "minecraft:air"}, | ||||
|         {pos: [3, 2, 1], state: "minecraft:air"}, | ||||
|         {pos: [3, 2, 2], state: "minecraft:air"}, | ||||
|         {pos: [3, 2, 3], state: "minecraft:air"}, | ||||
|         {pos: [3, 2, 4], state: "minecraft:air"}, | ||||
|         {pos: [4, 2, 0], state: "minecraft:air"}, | ||||
|         {pos: [4, 2, 1], state: "minecraft:air"}, | ||||
|         {pos: [4, 2, 2], state: "minecraft:air"}, | ||||
|         {pos: [4, 2, 3], state: "minecraft:air"}, | ||||
|         {pos: [4, 2, 4], state: "minecraft:air"}, | ||||
|         {pos: [0, 3, 0], state: "minecraft:air"}, | ||||
|         {pos: [0, 3, 1], state: "minecraft:air"}, | ||||
|         {pos: [0, 3, 2], state: "minecraft:air"}, | ||||
|         {pos: [0, 3, 3], state: "minecraft:air"}, | ||||
|         {pos: [0, 3, 4], state: "minecraft:air"}, | ||||
|         {pos: [1, 3, 0], state: "minecraft:air"}, | ||||
|         {pos: [1, 3, 1], state: "minecraft:air"}, | ||||
|         {pos: [1, 3, 2], state: "minecraft:air"}, | ||||
|         {pos: [1, 3, 3], state: "minecraft:air"}, | ||||
|         {pos: [1, 3, 4], state: "minecraft:air"}, | ||||
|         {pos: [2, 3, 0], state: "minecraft:air"}, | ||||
|         {pos: [2, 3, 1], state: "minecraft:air"}, | ||||
|         {pos: [2, 3, 2], state: "minecraft:air"}, | ||||
|         {pos: [2, 3, 3], state: "minecraft:air"}, | ||||
|         {pos: [2, 3, 4], state: "minecraft:air"}, | ||||
|         {pos: [3, 3, 0], state: "minecraft:air"}, | ||||
|         {pos: [3, 3, 1], state: "minecraft:air"}, | ||||
|         {pos: [3, 3, 2], state: "minecraft:air"}, | ||||
|         {pos: [3, 3, 3], state: "minecraft:air"}, | ||||
|         {pos: [3, 3, 4], state: "minecraft:air"}, | ||||
|         {pos: [4, 3, 0], state: "minecraft:air"}, | ||||
|         {pos: [4, 3, 1], state: "minecraft:air"}, | ||||
|         {pos: [4, 3, 2], state: "minecraft:air"}, | ||||
|         {pos: [4, 3, 3], state: "minecraft:air"}, | ||||
|         {pos: [4, 3, 4], state: "minecraft:air"}, | ||||
|         {pos: [0, 4, 0], state: "minecraft:air"}, | ||||
|         {pos: [0, 4, 1], state: "minecraft:air"}, | ||||
|         {pos: [0, 4, 2], state: "minecraft:air"}, | ||||
|         {pos: [0, 4, 3], state: "minecraft:air"}, | ||||
|         {pos: [0, 4, 4], state: "minecraft:air"}, | ||||
|         {pos: [1, 4, 0], state: "minecraft:air"}, | ||||
|         {pos: [1, 4, 1], state: "minecraft:air"}, | ||||
|         {pos: [1, 4, 2], state: "minecraft:air"}, | ||||
|         {pos: [1, 4, 3], state: "minecraft:air"}, | ||||
|         {pos: [1, 4, 4], state: "minecraft:air"}, | ||||
|         {pos: [2, 4, 0], state: "minecraft:air"}, | ||||
|         {pos: [2, 4, 1], state: "minecraft:air"}, | ||||
|         {pos: [2, 4, 2], state: "minecraft:air"}, | ||||
|         {pos: [2, 4, 3], state: "minecraft:air"}, | ||||
|         {pos: [2, 4, 4], state: "minecraft:air"}, | ||||
|         {pos: [3, 4, 0], state: "minecraft:air"}, | ||||
|         {pos: [3, 4, 1], state: "minecraft:air"}, | ||||
|         {pos: [3, 4, 2], state: "minecraft:air"}, | ||||
|         {pos: [3, 4, 3], state: "minecraft:air"}, | ||||
|         {pos: [3, 4, 4], state: "minecraft:air"}, | ||||
|         {pos: [4, 4, 0], state: "minecraft:air"}, | ||||
|         {pos: [4, 4, 1], state: "minecraft:air"}, | ||||
|         {pos: [4, 4, 2], state: "minecraft:air"}, | ||||
|         {pos: [4, 4, 3], state: "minecraft:air"}, | ||||
|         {pos: [4, 4, 4], state: "minecraft:air"} | ||||
|     ], | ||||
|     entities: [], | ||||
|     palette: [ | ||||
|         "minecraft:polished_andesite", | ||||
|         "minecraft:air", | ||||
|         "minecraft:composter{level:0}", | ||||
|         "computercraft:turtle_normal{facing:south,waterlogged:false}" | ||||
|     ] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates