diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e76ef7433..76e73fc5f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailProvider.java b/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailProvider.java index 879ed77eb..5923271ad 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailProvider.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailProvider.java @@ -14,6 +14,7 @@ import java.util.Map; * * @param The type of object that this provider can provide details for. * @see DetailRegistry + * @see dan200.computercraft.api.detail An overview of the detail system. */ @FunctionalInterface public interface DetailProvider { diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailRegistry.java b/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailRegistry.java index 4f21ff81f..342150515 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailRegistry.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/detail/DetailRegistry.java @@ -17,6 +17,7 @@ import java.util.Map; * also in this package. * * @param The type of object that this registry provides details for. + * @see dan200.computercraft.api.detail An overview of the detail system. */ @ApiStatus.NonExtendable public interface DetailRegistry { diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/detail/VanillaDetailRegistries.java b/projects/common-api/src/main/java/dan200/computercraft/api/detail/VanillaDetailRegistries.java index 409bca0f0..a7b462e1a 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/detail/VanillaDetailRegistries.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/detail/VanillaDetailRegistries.java @@ -17,6 +17,9 @@ public class VanillaDetailRegistries { *

* This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable) * and may be called from the computer thread. + *

+ * This does not have special handling for {@linkplain ItemStack#isEmpty() empty item stacks}, and so the returned + * details will be an empty stack of air. Callers should generally check for empty stacks before calling this. */ public static final DetailRegistry ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry(); diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/detail/package-info.java b/projects/common-api/src/main/java/dan200/computercraft/api/detail/package-info.java new file mode 100644 index 000000000..a562797dc --- /dev/null +++ b/projects/common-api/src/main/java/dan200/computercraft/api/detail/package-info.java @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +/** + * The detail system provides a standard way for mods to return descriptions of common game objects, such as blocks or + * items, as well as registering additional detail to be included in those descriptions. + *

+ * For instance, the built-in {@code turtle.getItemDetail()} method uses + * {@linkplain dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK in order to provide information about} + * the selected item: + * + *

{@code
+ * local item = turtle.getItemDetail(nil, true)
+ * --[[
+ * item = {
+ *   name = "minecraft:wheat",
+ *   displayName = "Wheat",
+ *   count = 1,
+ *   maxCount = 64,
+ *   tags = {},
+ * }
+ * ]]
+ * }
+ * + *

Built-in detail providers

+ * While you can define your own detail providers (perhaps for types from your own mod), CC comes with several built-in + * detail registries for vanilla and mod-loader objects: + * + *
    + *
  • {@link dan200.computercraft.api.detail.VanillaDetailRegistries}, for vanilla objects
  • + *
  • {@code dan200.computercraft.api.detail.ForgeDetailRegistries} for Forge-specific objects
  • + *
  • {@code dan200.computercraft.api.detail.FabricDetailRegistries} for Fabric-specific objects
  • + *
+ * + *

Example: Returning details from methods

+ * Here we define a {@code getHeldItem()} method for pocket computers which finds the currently held item of the player + * and returns it to the user using {@link dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK} and + * {@link dan200.computercraft.api.detail.DetailRegistry#getDetails(java.lang.Object)}. + * + * {@snippet class=com.example.examplemod.ExamplePocketPeripheral region=details} + * + *

Example: Registering custom detail registries

+ * Here we define a new detail provider for items that includes the nutrition and saturation values in the returned object. + * + * {@snippet class=com.example.examplemod.ExampleMod region=details} + */ +package dan200.computercraft.api.detail; diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java index a31b109a6..0b81bc291 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java +++ b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java @@ -22,6 +22,7 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.FastColor; import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; /** * A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern. diff --git a/projects/common/src/examples/java/com/example/examplemod/ExampleMod.java b/projects/common/src/examples/java/com/example/examplemod/ExampleMod.java index df15779a2..cdffd4b7c 100644 --- a/projects/common/src/examples/java/com/example/examplemod/ExampleMod.java +++ b/projects/common/src/examples/java/com/example/examplemod/ExampleMod.java @@ -3,6 +3,7 @@ package com.example.examplemod; import com.example.examplemod.data.TurtleDataProvider; import com.example.examplemod.peripheral.FurnacePeripheral; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.detail.VanillaDetailRegistries; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; /** @@ -34,6 +35,16 @@ public final class ExampleMod { ComputerCraftAPI.registerGenericSource(new FurnacePeripheral()); // @end region=generic_source + // @start region=details + VanillaDetailRegistries.ITEM_STACK.addProvider((out, stack) -> { + var food = stack.getItem().getFoodProperties(); + if (food == null) return; + + out.put("saturation", food.getSaturationModifier()); + out.put("nutrition", food.getNutrition()); + }); + // @end region=details + ExampleAPI.register(); } } diff --git a/projects/common/src/examples/java/com/example/examplemod/ExamplePocketPeripheral.java b/projects/common/src/examples/java/com/example/examplemod/ExamplePocketPeripheral.java new file mode 100644 index 000000000..bf9a19aa4 --- /dev/null +++ b/projects/common/src/examples/java/com/example/examplemod/ExamplePocketPeripheral.java @@ -0,0 +1,49 @@ +package com.example.examplemod; + +import dan200.computercraft.api.detail.DetailRegistry; +import dan200.computercraft.api.detail.VanillaDetailRegistries; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.pocket.IPocketAccess; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.LivingEntity; +import org.jspecify.annotations.Nullable; + +import java.util.Map; + +/** + * An example peripheral for pocket computers. This currently doesn't have an associated upgrade — it mostly exists to + * demonstrate other functionality. + */ +public class ExamplePocketPeripheral implements IPeripheral { + private final IPocketAccess pocket; + + public ExamplePocketPeripheral(IPocketAccess pocket) { + this.pocket = pocket; + } + + @Override + public String getType() { + return "example"; + } + + /** + * An example of using {@linkplain DetailRegistry detail registries} to get the current player's held item. + * + * @return The item details, or {@code null} if the player is not holding an item. + */ + // @start region=details + @LuaFunction(mainThread = true) + public final @Nullable Map getHeldItem() { + if (!(pocket.getEntity() instanceof LivingEntity entity)) return null; + + var heldItem = entity.getItemInHand(InteractionHand.MAIN_HAND); + return heldItem.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(heldItem); + } + // @end region=details + + @Override + public boolean equals(@Nullable IPeripheral other) { + return other instanceof ExamplePocketPeripheral o && pocket == o.pocket; + } +}