Interface ITurtleUpgrade

All Superinterfaces:
UpgradeBase
All Known Implementing Classes:
AbstractTurtleUpgrade

public interface ITurtleUpgrade extends UpgradeBase
The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new peripheral.

Turtle upgrades are defined in two stages. First, one creates a ITurtleUpgrade subclass and corresponding UpgradeType instance, which are then registered in a Minecraft registry.

You then write a JSON file in your mod's data/ folder. This is then parsed when the world is loaded, and the upgrade automatically registered.

Example

Registering the upgrade type

First, let's create a new class that implements ITurtleUpgrade. It is recommended to subclass AbstractTurtleUpgrade, as that provides a default implementation of most methods.
public class ExampleTurtleUpgrade extends AbstractTurtleUpgrade {
    public ExampleTurtleUpgrade(ItemStack stack) {
        super(TurtleUpgradeType.PERIPHERAL, "example", stack);
    }

    @Override
    public UpgradeType<ExampleTurtleUpgrade> getType() {
        return ExampleMod.EXAMPLE_TURTLE_UPGRADE;
    }
}
Now we must construct a new upgrade type. In most cases, you can use one of the helper methods (e.g. UpgradeType.simpleWithCustomItem(Function)), rather than defining your own implementation.
public static final UpgradeType<ExampleTurtleUpgrade> EXAMPLE_TURTLE_UPGRADE = UpgradeType.simpleWithCustomItem(
    ExampleTurtleUpgrade::new
);
We now must register this upgrade type. This is done the same way as you'd register blocks, items, or other Minecraft objects. The approach to do this will depend on mod-loader.

Fabric

@SuppressWarnings("unchecked")
var turtleUpgradeSerialisers = (Registry<UpgradeType<? extends ITurtleUpgrade>>) BuiltInRegistries.REGISTRY.get(ITurtleUpgrade.typeRegistry().location());
Registry.register(turtleUpgradeSerialisers, ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "example_turtle_upgrade"), ExampleMod.EXAMPLE_TURTLE_UPGRADE);

Forge

modBus.addListener((RegisterEvent event) -> {
    event.register(
        ITurtleUpgrade.typeRegistry(),
        ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "example_turtle_upgrade"),
        () -> ExampleMod.EXAMPLE_TURTLE_UPGRADE
    );
});

Rendering the upgrade

Next, we need to register a model for our upgrade. This is done by registering a TurtleUpgradeModeller for your upgrade type.

Fabric

FabricComputerCraftAPIClient.registerTurtleUpgradeModeller(ExampleMod.EXAMPLE_TURTLE_UPGRADE, TurtleUpgradeModeller.flatItem());

Forge

FabricComputerCraftAPIClient.registerTurtleUpgradeModeller(ExampleMod.EXAMPLE_TURTLE_UPGRADE, TurtleUpgradeModeller.flatItem());

Registering the upgrade itself

Upgrades themselves are loaded from datapacks when a level is loaded. In order to register our new upgrade, we must create a new JSON file at data/<my_mod>/computercraft/turtle_upgrade/<my_upgrade_id>.json.
{
  "type": "examplemod:example_turtle_upgrade",
  "item": "minecraft:compass"
}
The "type" field points to the ID of the upgrade type we've just registered, while the other fields are read by the type itself. As our upgrade was defined with UpgradeType.simpleWithCustomItem(Function), the "item" field will construct our upgrade with Items.COMPASS.

Rather than manually creating the file, it is recommended to use data-generators to generate this file. First, we register our new upgrades into a patched registry.

public class TurtleUpgradeProvider {
    // Register our turtle upgrades.
    public static void addUpgrades(BootstrapContext<ITurtleUpgrade> upgrades) {
        upgrades.register(
            ITurtleUpgrade.createKey(ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "example_turtle_upgrade")),
            new ExampleTurtleUpgrade(new ItemStack(Items.COMPASS))
        );
    }

    // Set up the dynamic registries to contain our turtle upgrades.
    public static CompletableFuture<RegistrySetBuilder.PatchedRegistries> makeUpgradeRegistry(CompletableFuture<HolderLookup.Provider> registries) {
        return RegistryPatchGenerator.createLookup(registries, Util.make(new RegistrySetBuilder(), builder -> {
            builder.add(ITurtleUpgrade.REGISTRY, TurtleUpgradeProvider::addUpgrades);
        }));
    }
}
Next, we must write these upgrades to disk. Vanilla does not have complete support for this yet, so this must be done with mod-loader-specific APIs.

Fabric

private static void addTurtleUpgrades(FabricDataGenerator.Pack pack, CompletableFuture<HolderLookup.Provider> registries) {
    var fullRegistryPatch = TurtleUpgradeProvider.makeUpgradeRegistry(registries);
    pack.addProvider((FabricDataOutput output) -> new AutomaticDynamicRegistryProvider(output, fullRegistryPatch));
}

/**
 * A subclass of {@link FabricDynamicRegistryProvider} that writes all new entries.
 */
private static class AutomaticDynamicRegistryProvider extends FabricDynamicRegistryProvider {
    AutomaticDynamicRegistryProvider(FabricDataOutput output, CompletableFuture<RegistrySetBuilder.PatchedRegistries> registries) {
        super(output, registries.thenApply(RegistrySetBuilder.PatchedRegistries::patches));
    }

    @Override
    protected void configure(HolderLookup.Provider registries, Entries entries) {
        for (var r : DynamicRegistries.getDynamicRegistries()) entries.addAll(registries.lookupOrThrow(r.key()));
    }

    @Override
    public String getName() {
        return "Registries";
    }
}

Forge

private static void addTurtleUpgrades(DataGenerator.PackGenerator pack, CompletableFuture<HolderLookup.Provider> registries) {
    var fullRegistryPatch = TurtleUpgradeProvider.makeUpgradeRegistry(registries);
    pack.addProvider(o -> new DatapackBuiltinEntriesProvider(o, fullRegistryPatch, Set.of(ExampleMod.MOD_ID)));
}
  • Field Details

    • REGISTRY

      static final net.minecraft.resources.ResourceKey<net.minecraft.core.Registry<ITurtleUpgrade>> REGISTRY
      The registry in which turtle upgrades are stored.
  • Method Details

    • createKey

      static net.minecraft.resources.ResourceKey<ITurtleUpgrade> createKey(net.minecraft.resources.ResourceLocation id)
      Create a ResourceKey for a turtle upgrade given a ResourceLocation.

      This should only be called from within data generation code. Do not hard code references to your upgrades!

      Parameters:
      id - The id of the turtle upgrade.
      Returns:
      The upgrade registry key.
    • typeRegistry

      static net.minecraft.resources.ResourceKey<net.minecraft.core.Registry<UpgradeType<? extends ITurtleUpgrade>>> typeRegistry()
      The registry key for turtle upgrade types.
      Returns:
      The registry key.
    • getType

      UpgradeType<? extends ITurtleUpgrade> getType()
      Get the type of this upgrade.
      Specified by:
      getType in interface UpgradeBase
      Returns:
      The type of this upgrade.
    • getUpgradeType

      TurtleUpgradeType getUpgradeType()
      Return whether this turtle adds a tool or a peripheral to the turtle.
      Returns:
      The type of upgrade this is.
      See Also:
    • createPeripheral

      default @Nullable IPeripheral createPeripheral(ITurtleAccess turtle, TurtleSide side)
      Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade.

      The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to update(ITurtleAccess, TurtleSide). It will be attached, detached and have methods called in the same manner as a Computer peripheral.

      Parameters:
      turtle - Access to the turtle that the peripheral is being created for.
      side - Which side of the turtle (left or right) that the upgrade resides on.
      Returns:
      The newly created peripheral. You may return null if this upgrade is a Tool and this method is not expected to be called.
    • useTool

      default TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, net.minecraft.core.Direction direction)
      Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called by the turtle, and the tool is required to do some work.

      Conforming implementations should fire loader-specific events when using the tool, for instance Forge's AttackEntityEvent.

      Parameters:
      turtle - Access to the turtle that the tool resides on.
      side - Which side of the turtle (left or right) the tool resides on.
      verb - Which action (dig or attack) the turtle is being called on to perform.
      direction - Which world direction the action should be performed in, relative to the turtles position. This will either be up, down, or the direction the turtle is facing, depending on whether dig, digUp or digDown was called.
      Returns:
      Whether the turtle was able to perform the action, and hence whether the turtle.dig() or turtle.attack() lua method should return true. If true is returned, the tool will perform a swinging animation. You may return null if this turtle is a Peripheral and this method is not expected to be called.
    • update

      default void update(ITurtleAccess turtle, TurtleSide side)
      Called once per tick for each turtle which has the upgrade equipped.
      Parameters:
      turtle - Access to the turtle that the upgrade resides on.
      side - Which side of the turtle (left or right) the upgrade resides on.
    • getPersistedData

      default net.minecraft.core.component.DataComponentPatch getPersistedData(net.minecraft.core.component.DataComponentPatch upgradeData)
      Get upgrade data that should be persisted when the turtle was broken.

      This method should be overridden when you don't need to store all upgrade data by default. For instance, if you store peripheral state in the upgrade data, which should be lost when the turtle is broken.

      Parameters:
      upgradeData - Data that currently stored for this upgrade
      Returns:
      Filtered version of this data.