mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-11-10 20:09:58 +00:00
Rewrite upgrades to use dynamic registries
Ever since 1.17, turtle and pocket upgrades have been loaded from datpacks, rather than being hard-coded in Java. However, upgrades have always been stored in our own registry-like structure, rather than using vanilla's registries. This has become a bit of a problem with the introduction of components. The upgrade components now hold the upgrade object (rather than just its id), which means we need the upgrades to be available much earlier (e.g. when reading recipes). The easiest fix here is to store upgrades in proper registries instead. This means that upgrades can no longer be reloaded (it requires a world restart), but otherwise is much nicer: - UpgradeData now stores a Holder<T> rather than a T. - UpgradeSerialiser has been renamed to UpgradeType. This now just provides a Codec<T>, rather than JSON and network reading/writing functions. - Upgrade classes no longer implement getUpgradeID(), but instead have a getType() function, which returns the associated UpgradeType. - Upgrades are now stored in turtle_upgrade (or pocket_upgrade) rather than turtle_upgrades (or pocket_upgrades). This will break existing datapacks, sorry!
This commit is contained in:
parent
cd9840d1c1
commit
bf203bb1f3
@ -6,7 +6,7 @@ Upstream-Contact: Jonathan Coates <git@squiddev.cc>
|
|||||||
Files:
|
Files:
|
||||||
projects/common/src/main/resources/assets/computercraft/sounds.json
|
projects/common/src/main/resources/assets/computercraft/sounds.json
|
||||||
projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg
|
projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg
|
||||||
projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/*
|
projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrade/*
|
||||||
projects/common/src/testMod/resources/data/cctest/structures/*
|
projects/common/src/testMod/resources/data/cctest/structures/*
|
||||||
projects/*/src/generated/*
|
projects/*/src/generated/*
|
||||||
projects/web/src/htmlTransform/export/index.json
|
projects/web/src/htmlTransform/export/index.json
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
package dan200.computercraft.api.client.turtle;
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A functional interface to register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
|
* A functional interface to register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
|
||||||
@ -18,9 +18,9 @@ public interface RegisterTurtleUpgradeModeller {
|
|||||||
/**
|
/**
|
||||||
* Register a {@link TurtleUpgradeModeller}.
|
* Register a {@link TurtleUpgradeModeller}.
|
||||||
*
|
*
|
||||||
* @param serialiser The turtle upgrade serialiser.
|
* @param type The turtle upgrade type.
|
||||||
* @param modeller The upgrade modeller.
|
* @param modeller The upgrade modeller.
|
||||||
* @param <T> The type of the turtle upgrade.
|
* @param <T> The type of the turtle upgrade.
|
||||||
*/
|
*/
|
||||||
<T extends ITurtleUpgrade> void register(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller);
|
<T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller);
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.pocket;
|
package dan200.computercraft.api.pocket;
|
||||||
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
@ -15,25 +13,14 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
* One does not have to use this, but it does provide a convenient template.
|
* One does not have to use this, but it does provide a convenient template.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractPocketUpgrade implements IPocketUpgrade {
|
public abstract class AbstractPocketUpgrade implements IPocketUpgrade {
|
||||||
private final ResourceLocation id;
|
|
||||||
private final String adjective;
|
private final String adjective;
|
||||||
private final ItemStack stack;
|
private final ItemStack stack;
|
||||||
|
|
||||||
protected AbstractPocketUpgrade(ResourceLocation id, String adjective, ItemStack stack) {
|
protected AbstractPocketUpgrade(String adjective, ItemStack stack) {
|
||||||
this.id = id;
|
|
||||||
this.adjective = adjective;
|
this.adjective = adjective;
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractPocketUpgrade(ResourceLocation id, ItemStack stack) {
|
|
||||||
this(id, UpgradeBase.getDefaultAdjective(id), stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final ResourceLocation getUpgradeID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String getUnlocalisedAdjective() {
|
public final String getUnlocalisedAdjective() {
|
||||||
return adjective;
|
return adjective;
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.api.pocket;
|
|||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@ -18,7 +18,7 @@ import javax.annotation.Nullable;
|
|||||||
* A peripheral which can be equipped to the back side of a pocket computer.
|
* A peripheral which can be equipped to the back side of a pocket computer.
|
||||||
* <p>
|
* <p>
|
||||||
* Pocket upgrades are defined in two stages. First, one creates a {@link IPocketUpgrade} subclass and corresponding
|
* Pocket upgrades are defined in two stages. First, one creates a {@link IPocketUpgrade} subclass and corresponding
|
||||||
* {@link UpgradeSerialiser} instance, which are then registered in a registry.
|
* {@link UpgradeType} instance, which are then registered in a registry.
|
||||||
* <p>
|
* <p>
|
||||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||||
* the upgrade automatically registered. It is recommended this is done via {@linkplain PocketUpgradeDataProvider data
|
* the upgrade automatically registered. It is recommended this is done via {@linkplain PocketUpgradeDataProvider data
|
||||||
@ -26,15 +26,15 @@ import javax.annotation.Nullable;
|
|||||||
*
|
*
|
||||||
* <h2>Example</h2>
|
* <h2>Example</h2>
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* // We use Forge's DeferredRegister to register our serialiser. Fabric mods may register their serialiser directly.
|
* // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly.
|
||||||
* static final DeferredRegister<UpgradeSerialiser<? extends IPocketUpgrade>> SERIALISERS = DeferredRegister.create(IPocketUpgrade.serialiserRegistryKey(), "my_mod");
|
* static final DeferredRegister<UpgradeType<? extends IPocketUpgrade>> POCKET_UPGRADES = DeferredRegister.create(IPocketUpgrade.typeRegistry(), "my_mod");
|
||||||
*
|
*
|
||||||
* // Register a new upgrade serialiser called "my_upgrade".
|
* // Register a new upgrade upgrade type called "my_upgrade".
|
||||||
* public static final RegistryObject<UpgradeSerialiser<MyUpgrade>> MY_UPGRADE =
|
* public static final RegistryObject<UpgradeType<MyUpgrade>> MY_UPGRADE =
|
||||||
* SERIALISERS.register("my_upgrade", () -> UpgradeSerialiser.simple(MyUpgrade::new));
|
* POCKET_UPGRADES.register("my_upgrade", () -> UpgradeType.simple(new MyUpgrade()));
|
||||||
*
|
*
|
||||||
* // Then in your constructor
|
* // Then in your constructor
|
||||||
* SERIALISERS.register(bus);
|
* POCKET_UPGRADES.register(bus);
|
||||||
* }</pre>
|
* }</pre>
|
||||||
* <p>
|
* <p>
|
||||||
* We can then define a new upgrade using JSON by placing the following in
|
* We can then define a new upgrade using JSON by placing the following in
|
||||||
@ -49,14 +49,22 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public interface IPocketUpgrade extends UpgradeBase {
|
public interface IPocketUpgrade extends UpgradeBase {
|
||||||
/**
|
/**
|
||||||
* The registry key for upgrade serialisers.
|
* The registry key for pocket upgrade types.
|
||||||
*
|
*
|
||||||
* @return The registry key.
|
* @return The registry key.
|
||||||
*/
|
*/
|
||||||
static ResourceKey<Registry<UpgradeSerialiser<? extends IPocketUpgrade>>> serialiserRegistryKey() {
|
static ResourceKey<Registry<UpgradeType<? extends IPocketUpgrade>>> typeRegistry() {
|
||||||
return ComputerCraftAPIService.get().pocketUpgradeRegistryId();
|
return ComputerCraftAPIService.get().pocketUpgradeRegistryId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of this upgrade.
|
||||||
|
*
|
||||||
|
* @return The type of this upgrade.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
UpgradeType<? extends IPocketUpgrade> getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a peripheral for the pocket computer.
|
* Creates a peripheral for the pocket computer.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
package dan200.computercraft.api.pocket;
|
package dan200.computercraft.api.pocket;
|
||||||
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeDataProvider;
|
import dan200.computercraft.api.upgrades.UpgradeDataProvider;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
|
import dan200.computercraft.impl.RegistryHelper;
|
||||||
import net.minecraft.data.DataGenerator;
|
import net.minecraft.data.DataGenerator;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
|
|
||||||
@ -19,10 +21,10 @@ import java.util.function.Consumer;
|
|||||||
* generate them.
|
* generate them.
|
||||||
*
|
*
|
||||||
* @see IPocketUpgrade
|
* @see IPocketUpgrade
|
||||||
* @see UpgradeSerialiser
|
* @see UpgradeType
|
||||||
*/
|
*/
|
||||||
public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade> {
|
public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade> {
|
||||||
public PocketUpgradeDataProvider(PackOutput output) {
|
public PocketUpgradeDataProvider(PackOutput output) {
|
||||||
super(output, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", IPocketUpgrade.serialiserRegistryKey());
|
super(output, "Pocket Computer Upgrades", RegistryHelper.POCKET_UPGRADE, ComputerCraftAPIService.get().pocketUpgradeCodec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.turtle;
|
package dan200.computercraft.api.turtle;
|
||||||
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
@ -15,34 +13,23 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
* One does not have to use this, but it does provide a convenient template.
|
* One does not have to use this, but it does provide a convenient template.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade {
|
public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade {
|
||||||
private final ResourceLocation id;
|
|
||||||
private final TurtleUpgradeType type;
|
private final TurtleUpgradeType type;
|
||||||
private final String adjective;
|
private final String adjective;
|
||||||
private final ItemStack stack;
|
private final ItemStack stack;
|
||||||
|
|
||||||
protected AbstractTurtleUpgrade(ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack) {
|
protected AbstractTurtleUpgrade(TurtleUpgradeType type, String adjective, ItemStack stack) {
|
||||||
this.id = id;
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.adjective = adjective;
|
this.adjective = adjective;
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractTurtleUpgrade(ResourceLocation id, TurtleUpgradeType type, ItemStack stack) {
|
|
||||||
this(id, type, UpgradeBase.getDefaultAdjective(id), stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final ResourceLocation getUpgradeID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String getUnlocalisedAdjective() {
|
public final String getUnlocalisedAdjective() {
|
||||||
return adjective;
|
return adjective;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TurtleUpgradeType getType() {
|
public final TurtleUpgradeType getUpgradeType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.api.turtle;
|
|||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
@ -20,7 +20,7 @@ import javax.annotation.Nullable;
|
|||||||
* peripheral.
|
* peripheral.
|
||||||
* <p>
|
* <p>
|
||||||
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
|
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
|
||||||
* {@link UpgradeSerialiser} instance, which are then registered in a registry.
|
* {@link UpgradeType} instance, which are then registered in a registry.
|
||||||
* <p>
|
* <p>
|
||||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||||
* the upgrade automatically registered. It is recommended this is done via {@linkplain TurtleUpgradeDataProvider data
|
* the upgrade automatically registered. It is recommended this is done via {@linkplain TurtleUpgradeDataProvider data
|
||||||
@ -28,15 +28,15 @@ import javax.annotation.Nullable;
|
|||||||
*
|
*
|
||||||
* <h2>Example</h2>
|
* <h2>Example</h2>
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* // We use Forge's DeferredRegister to register our serialiser. Fabric mods may register their serialiser directly.
|
* // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly.
|
||||||
* static final DeferredRegister<UpgradeSerialiser<? extends ITurtleUpgrade>> SERIALISERS = DeferredRegister.create(ITurtleUpgrade.serialiserRegistryKey(), "my_mod");
|
* static final DeferredRegister<UpgradeType<? extends ITurtleUpgrade>> TURTLE_UPGRADES = DeferredRegister.create(ITurtleUpgrade.typeRegistry(), "my_mod");
|
||||||
*
|
*
|
||||||
* // Register a new upgrade serialiser called "my_upgrade".
|
* // Register a new upgrade type called "my_upgrade".
|
||||||
* public static final RegistryObject<UpgradeSerialiser<MyUpgrade>> MY_UPGRADE =
|
* public static final RegistryObject<UpgradeType<MyUpgrade>> MY_UPGRADE =
|
||||||
* SERIALISERS.register( "my_upgrade", () -> TurtleUpgradeSerialiser.simple( MyUpgrade::new ) );
|
* TURTLE_UPGRADES.register("my_upgrade", () -> UpgradeType.simple(MyUpgrade::new));
|
||||||
*
|
*
|
||||||
* // Then in your constructor
|
* // Then in your constructor
|
||||||
* SERIALISERS.register( bus );
|
* TURTLE_UPGRADES.register(bus);
|
||||||
* }</pre>
|
* }</pre>
|
||||||
* <p>
|
* <p>
|
||||||
* We can then define a new upgrade using JSON by placing the following in
|
* We can then define a new upgrade using JSON by placing the following in
|
||||||
@ -44,7 +44,7 @@ import javax.annotation.Nullable;
|
|||||||
*
|
*
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* {
|
* {
|
||||||
* "type": my_mod:my_upgrade",
|
* "type": "my_mod:my_upgrade"
|
||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
* <p>
|
* <p>
|
||||||
@ -60,21 +60,29 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public interface ITurtleUpgrade extends UpgradeBase {
|
public interface ITurtleUpgrade extends UpgradeBase {
|
||||||
/**
|
/**
|
||||||
* The registry key for upgrade serialisers.
|
* The registry key for turtle upgrade types.
|
||||||
*
|
*
|
||||||
* @return The registry key.
|
* @return The registry key.
|
||||||
*/
|
*/
|
||||||
static ResourceKey<Registry<UpgradeSerialiser<? extends ITurtleUpgrade>>> serialiserRegistryKey() {
|
static ResourceKey<Registry<UpgradeType<? extends ITurtleUpgrade>>> typeRegistry() {
|
||||||
return ComputerCraftAPIService.get().turtleUpgradeRegistryId();
|
return ComputerCraftAPIService.get().turtleUpgradeRegistryId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of this upgrade.
|
||||||
|
*
|
||||||
|
* @return The type of this upgrade.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
UpgradeType<? extends ITurtleUpgrade> getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether this turtle adds a tool or a peripheral to the turtle.
|
* Return whether this turtle adds a tool or a peripheral to the turtle.
|
||||||
*
|
*
|
||||||
* @return The type of upgrade this is.
|
* @return The type of upgrade this is.
|
||||||
* @see TurtleUpgradeType for the differences between them.
|
* @see TurtleUpgradeType for the differences between them.
|
||||||
*/
|
*/
|
||||||
TurtleUpgradeType getType();
|
TurtleUpgradeType getUpgradeType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade.
|
* Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade.
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.turtle;
|
package dan200.computercraft.api.turtle;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
|
||||||
import dan200.computercraft.api.ComputerCraftTags;
|
import dan200.computercraft.api.ComputerCraftTags;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeDataProvider;
|
import dan200.computercraft.api.upgrades.UpgradeDataProvider;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
import dan200.computercraft.impl.RegistryHelper;
|
import dan200.computercraft.impl.RegistryHelper;
|
||||||
|
import dan200.computercraft.impl.upgrades.TurtleToolSpec;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.data.DataGenerator;
|
import net.minecraft.data.DataGenerator;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@ -21,6 +21,7 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,10 +34,8 @@ import java.util.function.Consumer;
|
|||||||
* @see ITurtleUpgrade
|
* @see ITurtleUpgrade
|
||||||
*/
|
*/
|
||||||
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade> {
|
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade> {
|
||||||
private static final ResourceLocation TOOL_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "tool");
|
|
||||||
|
|
||||||
public TurtleUpgradeDataProvider(PackOutput output) {
|
public TurtleUpgradeDataProvider(PackOutput output) {
|
||||||
super(output, "Turtle Upgrades", "computercraft/turtle_upgrades", ITurtleUpgrade.serialiserRegistryKey());
|
super(output, "Turtle Upgrades", RegistryHelper.TURTLE_UPGRADE, ComputerCraftAPIService.get().turtleUpgradeCodec());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +47,7 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
* @return A tool builder,
|
* @return A tool builder,
|
||||||
*/
|
*/
|
||||||
public final ToolBuilder tool(ResourceLocation id, Item item) {
|
public final ToolBuilder tool(ResourceLocation id, Item item) {
|
||||||
return new ToolBuilder(id, existingSerialiser(TOOL_ID), item);
|
return new ToolBuilder(id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,20 +55,19 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
*
|
*
|
||||||
* @see #tool(ResourceLocation, Item)
|
* @see #tool(ResourceLocation, Item)
|
||||||
*/
|
*/
|
||||||
public static class ToolBuilder {
|
public final class ToolBuilder {
|
||||||
private final ResourceLocation id;
|
private final ResourceLocation id;
|
||||||
private final UpgradeSerialiser<? extends ITurtleUpgrade> serialiser;
|
|
||||||
private final Item toolItem;
|
private final Item toolItem;
|
||||||
private @Nullable String adjective;
|
private String adjective;
|
||||||
private @Nullable Item craftingItem;
|
private @Nullable Item craftingItem;
|
||||||
private @Nullable Float damageMultiplier = null;
|
private float damageMultiplier = TurtleToolSpec.DEFAULT_DAMAGE_MULTIPLIER;
|
||||||
private @Nullable TagKey<Block> breakable;
|
private @Nullable TagKey<Block> breakable;
|
||||||
private boolean allowEnchantments = false;
|
private boolean allowEnchantments = false;
|
||||||
private TurtleToolDurability consumeDurability = TurtleToolDurability.NEVER;
|
private TurtleToolDurability consumeDurability = TurtleToolDurability.NEVER;
|
||||||
|
|
||||||
ToolBuilder(ResourceLocation id, UpgradeSerialiser<? extends ITurtleUpgrade> serialiser, Item toolItem) {
|
ToolBuilder(ResourceLocation id, Item toolItem) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.serialiser = serialiser;
|
adjective = UpgradeBase.getDefaultAdjective(id);
|
||||||
this.toolItem = toolItem;
|
this.toolItem = toolItem;
|
||||||
craftingItem = null;
|
craftingItem = null;
|
||||||
}
|
}
|
||||||
@ -150,20 +148,16 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
*
|
*
|
||||||
* @param add The callback given to {@link #addUpgrades(Consumer)}.
|
* @param add The callback given to {@link #addUpgrades(Consumer)}.
|
||||||
*/
|
*/
|
||||||
public void add(Consumer<Upgrade<UpgradeSerialiser<? extends ITurtleUpgrade>>> add) {
|
public void add(Consumer<Upgrade<ITurtleUpgrade>> add) {
|
||||||
add.accept(new Upgrade<>(id, serialiser, s -> {
|
upgrade(id, ComputerCraftAPIService.get().createTurtleTool(new TurtleToolSpec(
|
||||||
s.addProperty("item", RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, toolItem).toString());
|
adjective,
|
||||||
if (adjective != null) s.addProperty("adjective", adjective);
|
Optional.ofNullable(craftingItem),
|
||||||
if (craftingItem != null) {
|
toolItem,
|
||||||
s.addProperty("craftItem", RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, craftingItem).toString());
|
damageMultiplier,
|
||||||
}
|
allowEnchantments,
|
||||||
if (damageMultiplier != null) s.addProperty("damageMultiplier", damageMultiplier);
|
consumeDurability,
|
||||||
if (breakable != null) s.addProperty("breakable", breakable.location().toString());
|
Optional.ofNullable(breakable)
|
||||||
if (allowEnchantments) s.addProperty("allowEnchantments", true);
|
))).add(add);
|
||||||
if (consumeDurability != TurtleToolDurability.NEVER) {
|
|
||||||
s.addProperty("consumeDurability", consumeDurability.getSerializedName());
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,11 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
*/
|
*/
|
||||||
public interface UpgradeBase {
|
public interface UpgradeBase {
|
||||||
/**
|
/**
|
||||||
* Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem"
|
* Get the type of this upgrade.
|
||||||
* or "my_mod:my_upgrade".
|
|
||||||
* <p>
|
|
||||||
* You should use a unique resource domain to ensure this upgrade is uniquely identified.
|
|
||||||
* The upgrade will fail registration if an already used ID is specified.
|
|
||||||
*
|
*
|
||||||
* @return The unique ID for this upgrade.
|
* @return The type of this upgrade.
|
||||||
*/
|
*/
|
||||||
ResourceLocation getUpgradeID();
|
UpgradeType<?> getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an unlocalised string to describe this type of computer in item names.
|
* Return an unlocalised string to describe this type of computer in item names.
|
||||||
|
@ -6,38 +6,53 @@ package dan200.computercraft.api.upgrades;
|
|||||||
|
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
|
* An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
|
||||||
*
|
*
|
||||||
* @param upgrade The current upgrade.
|
* @param holder The current upgrade holder.
|
||||||
* @param data The upgrade's data.
|
* @param data The upgrade's data.
|
||||||
* @param <T> The type of upgrade, either {@link ITurtleUpgrade} or {@link IPocketUpgrade}.
|
* @param <T> The type of upgrade, either {@link ITurtleUpgrade} or {@link IPocketUpgrade}.
|
||||||
*/
|
*/
|
||||||
public record UpgradeData<T extends UpgradeBase>(T upgrade, DataComponentPatch data) {
|
public record UpgradeData<T extends UpgradeBase>(Holder.Reference<T> holder, DataComponentPatch data) {
|
||||||
/**
|
/**
|
||||||
* A utility method to construct a new {@link UpgradeData} instance.
|
* A utility method to construct a new {@link UpgradeData} instance.
|
||||||
*
|
*
|
||||||
* @param upgrade An upgrade.
|
* @param holder An upgrade.
|
||||||
* @param data The upgrade's data.
|
* @param data The upgrade's data.
|
||||||
* @param <T> The type of upgrade.
|
* @param <T> The type of upgrade.
|
||||||
* @return The new {@link UpgradeData} instance.
|
* @return The new {@link UpgradeData} instance.
|
||||||
*/
|
*/
|
||||||
public static <T extends UpgradeBase> UpgradeData<T> of(T upgrade, DataComponentPatch data) {
|
public static <T extends UpgradeBase> UpgradeData<T> of(Holder.Reference<T> holder, DataComponentPatch data) {
|
||||||
return new UpgradeData<>(upgrade, data);
|
return new UpgradeData<>(holder, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an {@link UpgradeData} containing the default {@linkplain #data() data} for an upgrade.
|
* Create an {@link UpgradeData} containing the default {@linkplain #data() data} for an upgrade.
|
||||||
*
|
*
|
||||||
* @param upgrade The upgrade instance.
|
* @param holder The upgrade instance.
|
||||||
* @param <T> The type of upgrade.
|
* @param <T> The type of upgrade.
|
||||||
* @return The default upgrade data.
|
* @return The default upgrade data.
|
||||||
*/
|
*/
|
||||||
public static <T extends UpgradeBase> UpgradeData<T> ofDefault(T upgrade) {
|
public static <T extends UpgradeBase> UpgradeData<T> ofDefault(Holder.Reference<T> holder) {
|
||||||
return of(upgrade, upgrade.getUpgradeData(upgrade.getCraftingItem()));
|
var upgrade = holder.value();
|
||||||
|
return of(holder, upgrade.getUpgradeData(upgrade.getCraftingItem()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpgradeData {
|
||||||
|
if (!holder.isBound()) throw new IllegalArgumentException("Holder is not bound");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current upgrade.
|
||||||
|
*
|
||||||
|
* @return The current upgrade.
|
||||||
|
*/
|
||||||
|
public T upgrade() {
|
||||||
|
return holder().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,6 +64,6 @@ public record UpgradeData<T extends UpgradeBase>(T upgrade, DataComponentPatch d
|
|||||||
* @return This upgrade's item.
|
* @return This upgrade's item.
|
||||||
*/
|
*/
|
||||||
public ItemStack getUpgradeItem() {
|
public ItemStack getUpgradeItem() {
|
||||||
return upgrade.getUpgradeItem(data).copy();
|
return upgrade().getUpgradeItem(data).copy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,22 @@
|
|||||||
package dan200.computercraft.api.upgrades;
|
package dan200.computercraft.api.upgrades;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.JsonOps;
|
||||||
import dan200.computercraft.impl.PlatformHelper;
|
import dan200.computercraft.impl.PlatformHelper;
|
||||||
import dan200.computercraft.impl.RegistryHelper;
|
|
||||||
import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem;
|
|
||||||
import dan200.computercraft.impl.upgrades.SimpleSerialiser;
|
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.data.CachedOutput;
|
import net.minecraft.data.CachedOutput;
|
||||||
import net.minecraft.data.DataProvider;
|
import net.minecraft.data.DataProvider;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data generator/provider for turtle and pocket computer upgrades. This should not be extended directly, instead see
|
* A data generator/provider for turtle and pocket computer upgrades. This should not be extended directly, instead see
|
||||||
@ -36,92 +31,66 @@ import java.util.function.Function;
|
|||||||
public abstract class UpgradeDataProvider<T extends UpgradeBase> implements DataProvider {
|
public abstract class UpgradeDataProvider<T extends UpgradeBase> implements DataProvider {
|
||||||
private final PackOutput output;
|
private final PackOutput output;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String folder;
|
private final ResourceKey<Registry<T>> registryName;
|
||||||
private final Registry<UpgradeSerialiser<? extends T>> registry;
|
private final Codec<T> codec;
|
||||||
|
|
||||||
private @Nullable List<T> upgrades;
|
private @Nullable Map<ResourceKey<T>, T> upgrades;
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
protected UpgradeDataProvider(PackOutput output, String name, String folder, ResourceKey<Registry<UpgradeSerialiser<? extends T>>> registry) {
|
protected UpgradeDataProvider(PackOutput output, String name, ResourceKey<Registry<T>> registryName, Codec<T> codec) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.folder = folder;
|
this.registryName = registryName;
|
||||||
this.registry = RegistryHelper.getRegistry(registry);
|
this.codec = codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register an upgrade using a {@linkplain UpgradeSerialiser#simple(Function) "simple" serialiser}.
|
* Add a new upgrade.
|
||||||
*
|
*
|
||||||
* @param id The ID of the upgrade to create.
|
* @param id The ID of the upgrade to create.
|
||||||
* @param serialiser The simple serialiser.
|
* @param upgrade The upgrade to add.
|
||||||
* @return The constructed upgrade, ready to be passed off to {@link #addUpgrades(Consumer)}'s consumer.
|
* @return The constructed upgrade, ready to be passed off to {@link #addUpgrades(Consumer)}'s consumer.
|
||||||
*/
|
*/
|
||||||
public final Upgrade<UpgradeSerialiser<? extends T>> simple(ResourceLocation id, UpgradeSerialiser<? extends T> serialiser) {
|
protected final Upgrade<T> upgrade(ResourceLocation id, T upgrade) {
|
||||||
if (!(serialiser instanceof SimpleSerialiser)) {
|
return new Upgrade<>(id, upgrade, j -> {
|
||||||
throw new IllegalStateException(serialiser + " must be a simple() seriaiser.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Upgrade<>(id, serialiser, s -> {
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an upgrade using a {@linkplain UpgradeSerialiser#simple(Function) simple serialiser}.
|
|
||||||
*
|
|
||||||
* @param id The ID of the upgrade to create.
|
|
||||||
* @param serialiser The simple serialiser.
|
|
||||||
* @param item The crafting upgrade for this item.
|
|
||||||
* @return The constructed upgrade, ready to be passed off to {@link #addUpgrades(Consumer)}'s consumer.
|
|
||||||
*/
|
|
||||||
public final Upgrade<UpgradeSerialiser<? extends T>> simpleWithCustomItem(ResourceLocation id, UpgradeSerialiser<? extends T> serialiser, Item item) {
|
|
||||||
if (!(serialiser instanceof SerialiserWithCraftingItem)) {
|
|
||||||
throw new IllegalStateException(serialiser + " must be a simpleWithCustomItem() serialiser.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Upgrade<>(id, serialiser, s ->
|
|
||||||
s.addProperty("item", RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, item).toString())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all turtle or pocket computer upgrades.
|
* Add all turtle or pocket computer upgrades.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Example usage:</strong>
|
* <strong>Example usage:</strong>
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* protected void addUpgrades(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> addUpgrade) {
|
* protected void addUpgrades(Consumer<Upgrade<ITurtleUpgrade>> addUpgrade) {
|
||||||
* simple(new ResourceLocation("mymod", "speaker"), SPEAKER_SERIALISER.get()).add(addUpgrade);
|
* upgrade(new ResourceLocation("mymod", "speaker"), new TurtleSpeaker(new ItemStack(Items.NOTE_BLOCK))).add(addUpgrade);
|
||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
* @param addUpgrade A callback used to register an upgrade.
|
* @param addUpgrade A callback used to register an upgrade.
|
||||||
*/
|
*/
|
||||||
protected abstract void addUpgrades(Consumer<Upgrade<UpgradeSerialiser<? extends T>>> addUpgrade);
|
protected abstract void addUpgrades(Consumer<Upgrade<T>> addUpgrade);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> run(CachedOutput cache) {
|
public CompletableFuture<?> run(CachedOutput cache) {
|
||||||
var base = output.getOutputFolder().resolve("data");
|
var base = output.createPathProvider(PackOutput.Target.DATA_PACK, registryName.location().getNamespace() + "/" + registryName.location().getPath());
|
||||||
|
|
||||||
|
Map<ResourceKey<T>, T> upgrades = new LinkedHashMap<>();
|
||||||
|
|
||||||
Set<ResourceLocation> seen = new HashSet<>();
|
|
||||||
List<T> upgrades = new ArrayList<>();
|
|
||||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||||
addUpgrades(upgrade -> {
|
addUpgrades(upgrade -> {
|
||||||
if (!seen.add(upgrade.id())) throw new IllegalStateException("Duplicate upgrade " + upgrade.id());
|
var id = ResourceKey.create(registryName, upgrade.id);
|
||||||
|
if (upgrades.containsKey(id)) throw new IllegalStateException("Duplicate upgrade " + upgrade.id);
|
||||||
|
|
||||||
var json = new JsonObject();
|
var json = (JsonObject) codec.encodeStart(JsonOps.INSTANCE, upgrade.upgrade).getOrThrow();
|
||||||
json.addProperty("type", RegistryHelper.getKeyOrThrow(registry, upgrade.serialiser()).toString());
|
upgrade.serialise.accept(json);
|
||||||
upgrade.serialise().accept(json);
|
|
||||||
|
|
||||||
futures.add(DataProvider.saveStable(cache, json, base.resolve(upgrade.id().getNamespace() + "/" + folder + "/" + upgrade.id().getPath() + ".json")));
|
futures.add(DataProvider.saveStable(cache, json, base.json(upgrade.id)));
|
||||||
|
|
||||||
try {
|
upgrades.put(id, upgrade.upgrade);
|
||||||
var result = upgrade.serialiser().fromJson(upgrade.id(), json);
|
|
||||||
upgrades.add(result);
|
|
||||||
} catch (IllegalArgumentException | JsonParseException e) {
|
|
||||||
LOGGER.error("Failed to parse {} {}", name, upgrade.id(), e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.upgrades = Collections.unmodifiableList(upgrades);
|
this.upgrades = Collections.unmodifiableMap(upgrades);
|
||||||
|
|
||||||
return Util.sequenceFailFast(futures);
|
return Util.sequenceFailFast(futures);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,34 +99,39 @@ public abstract class UpgradeDataProvider<T extends UpgradeBase> implements Data
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final UpgradeSerialiser<? extends T> existingSerialiser(ResourceLocation id) {
|
/**
|
||||||
var result = registry.get(id);
|
* Get all registered upgrades.
|
||||||
if (result == null) throw new IllegalArgumentException("No such serialiser " + id);
|
*
|
||||||
return result;
|
* @return The map of registered upgrades.
|
||||||
}
|
*/
|
||||||
|
public Map<ResourceKey<T>, T> getGeneratedUpgrades() {
|
||||||
public List<T> getGeneratedUpgrades() {
|
var upgrades = this.upgrades;
|
||||||
if (upgrades == null) throw new IllegalStateException("Upgrades have not been generated yet");
|
if (upgrades == null) throw new IllegalStateException("Upgrades are not available yet");
|
||||||
return upgrades;
|
return upgrades;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructed upgrade instance, produced {@link #addUpgrades(Consumer)}.
|
* A constructed upgrade instance, produced {@link #addUpgrades(Consumer)}.
|
||||||
*
|
*
|
||||||
* @param id The ID for this upgrade.
|
* @param <T> The type of upgrade.
|
||||||
* @param serialiser The serialiser which reads and writes this upgrade.
|
|
||||||
* @param serialise Augment the generated JSON with additional fields.
|
|
||||||
* @param <R> The type of upgrade serialiser.
|
|
||||||
*/
|
*/
|
||||||
public record Upgrade<R extends UpgradeSerialiser<?>>(
|
public static final class Upgrade<T extends UpgradeBase> {
|
||||||
ResourceLocation id, R serialiser, Consumer<JsonObject> serialise
|
private final ResourceLocation id;
|
||||||
) {
|
private final T upgrade;
|
||||||
|
private final Consumer<JsonObject> serialise;
|
||||||
|
|
||||||
|
private Upgrade(ResourceLocation id, T upgrade, Consumer<JsonObject> serialise) {
|
||||||
|
this.id = id;
|
||||||
|
this.upgrade = upgrade;
|
||||||
|
this.serialise = serialise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for registering an upgrade.
|
* Convenience method for registering an upgrade.
|
||||||
*
|
*
|
||||||
* @param add The callback given to {@link #addUpgrades(Consumer)}
|
* @param add The callback given to {@link #addUpgrades(Consumer)}
|
||||||
*/
|
*/
|
||||||
public void add(Consumer<Upgrade<R>> add) {
|
public void add(Consumer<Upgrade<T>> add) {
|
||||||
add.accept(this);
|
add.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,8 +144,8 @@ public abstract class UpgradeDataProvider<T extends UpgradeBase> implements Data
|
|||||||
* @param modId The id of the mod.
|
* @param modId The id of the mod.
|
||||||
* @return A new upgrade instance.
|
* @return A new upgrade instance.
|
||||||
*/
|
*/
|
||||||
public Upgrade<R> requireMod(String modId) {
|
public Upgrade<T> requireMod(String modId) {
|
||||||
return new Upgrade<>(id, serialiser, json -> {
|
return new Upgrade<>(id, upgrade, json -> {
|
||||||
PlatformHelper.get().addRequiredModCondition(json, modId);
|
PlatformHelper.get().addRequiredModCondition(json, modId);
|
||||||
serialise.accept(json);
|
serialise.accept(json);
|
||||||
});
|
});
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.upgrades;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|
||||||
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
|
||||||
import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem;
|
|
||||||
import dan200.computercraft.impl.upgrades.SimpleSerialiser;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
|
||||||
import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
|
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A serialiser for {@link ITurtleUpgrade} or {@link IPocketUpgrade}s.
|
|
||||||
* <p>
|
|
||||||
* These should be registered in a {@link Registry} while the game is loading, much like {@link RecipeSerializer}s.
|
|
||||||
* <p>
|
|
||||||
* This interface is very similar to {@link RecipeSerializer}; each serialiser should correspond to a specific upgrade
|
|
||||||
* class. Upgrades are then read from JSON files in datapacks, allowing multiple instances of the upgrade to be
|
|
||||||
* registered.
|
|
||||||
* <p>
|
|
||||||
* If your upgrade doesn't have any associated configurable parameters (like most upgrades), you can use
|
|
||||||
* {@link #simple(Function)} or {@link #simpleWithCustomItem(BiFunction)} to create a basic upgrade serialiser.
|
|
||||||
* <p>
|
|
||||||
* Upgrades may be data generated via a {@link UpgradeDataProvider} (see {@link TurtleUpgradeDataProvider} and
|
|
||||||
* {@link PocketUpgradeDataProvider}).
|
|
||||||
*
|
|
||||||
* @param <T> The upgrade that this class can serialise and deserialise.
|
|
||||||
* @see ITurtleUpgrade
|
|
||||||
* @see IPocketUpgrade
|
|
||||||
*/
|
|
||||||
public interface UpgradeSerialiser<T extends UpgradeBase> {
|
|
||||||
/**
|
|
||||||
* Read this upgrade from a JSON file in a datapack.
|
|
||||||
*
|
|
||||||
* @param id The ID of this upgrade.
|
|
||||||
* @param object The JSON object to load this upgrade from.
|
|
||||||
* @return The constructed upgrade, with a {@link UpgradeBase#getUpgradeID()} equal to {@code id}.
|
|
||||||
* @see net.minecraft.util.GsonHelper For additional JSON helper methods.
|
|
||||||
*/
|
|
||||||
T fromJson(ResourceLocation id, JsonObject object);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read this upgrade from a network packet, sent from the server.
|
|
||||||
*
|
|
||||||
* @param id The ID of this upgrade.
|
|
||||||
* @param buffer The buffer object to read this upgrade from.
|
|
||||||
* @return The constructed upgrade, with a {@link UpgradeBase#getUpgradeID()} equal to {@code id}.
|
|
||||||
*/
|
|
||||||
T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write this upgrade to a network packet, to be sent to the client.
|
|
||||||
*
|
|
||||||
* @param buffer The buffer object to write this upgrade to
|
|
||||||
* @param upgrade The upgrade to write.
|
|
||||||
*/
|
|
||||||
void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer},
|
|
||||||
* but for upgrades.
|
|
||||||
* <p>
|
|
||||||
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
|
|
||||||
*
|
|
||||||
* @param factory Generate a new upgrade with a specific ID.
|
|
||||||
* @param <T> The type of the generated upgrade.
|
|
||||||
* @return The serialiser for this upgrade
|
|
||||||
*/
|
|
||||||
static <T extends UpgradeBase> UpgradeSerialiser<T> simple(Function<ResourceLocation, T> factory) {
|
|
||||||
return new SimpleSerialiser<>(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an upgrade serialiser for a simple upgrade whose crafting item can be specified.
|
|
||||||
*
|
|
||||||
* @param factory Generate a new upgrade with a specific ID and crafting item. The returned upgrade's
|
|
||||||
* {@link UpgradeBase#getCraftingItem()} <strong>MUST</strong> equal the provided item.
|
|
||||||
* @param <T> The type of the generated upgrade.
|
|
||||||
* @return The serialiser for this upgrade.
|
|
||||||
* @see #simple(Function) For upgrades whose crafting stack should not vary.
|
|
||||||
*/
|
|
||||||
static <T extends UpgradeBase> UpgradeSerialiser<T> simpleWithCustomItem(BiFunction<ResourceLocation, ItemStack, T> factory) {
|
|
||||||
return new SerialiserWithCraftingItem<>(factory);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,89 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.upgrades;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
||||||
|
import dan200.computercraft.impl.upgrades.UpgradeTypeImpl;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
|
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a {@linkplain ITurtleUpgrade turtle} or {@linkplain IPocketUpgrade pocket} upgrade.
|
||||||
|
* <p>
|
||||||
|
* Turtle and pocket computer upgrades are registered using Minecraft's dynamic registry system. As a result, they
|
||||||
|
* follow a similar design to other dynamic content, such as {@linkplain Recipe recipes} or {@link LootItemFunction
|
||||||
|
* loot functions}.
|
||||||
|
* <p>
|
||||||
|
* First, one adds a new class implementing {@link ITurtleUpgrade} or {@link IPocketUpgrade}). This is responsible for
|
||||||
|
* handling all the logic of your upgrade.
|
||||||
|
* <p>
|
||||||
|
* However, the upgrades are not registered directly. Instead, each upgrade class should have a corresponding
|
||||||
|
* {@link UpgradeType}, which is responsible for loading the upgrade from a datapack. The upgrade type should then be
|
||||||
|
* registered in its appropriate registry ({@link ITurtleUpgrade#typeRegistry()},
|
||||||
|
* {@link IPocketUpgrade#typeRegistry()}).
|
||||||
|
* <p>
|
||||||
|
* In order to register the actual upgrade, a JSON file referencing your upgrade type should be added to a datapack. It
|
||||||
|
* is recommended to do this via the data generators (see {@link TurtleUpgradeDataProvider} and
|
||||||
|
* {@link PocketUpgradeDataProvider}).
|
||||||
|
*
|
||||||
|
* @param <T> The upgrade subclass that this upgrade type represents.
|
||||||
|
* @see ITurtleUpgrade
|
||||||
|
* @see IPocketUpgrade
|
||||||
|
*/
|
||||||
|
public interface UpgradeType<T extends UpgradeBase> {
|
||||||
|
/**
|
||||||
|
* The codec to read and write this upgrade from a datapack.
|
||||||
|
*
|
||||||
|
* @return The codec for this upgrade.
|
||||||
|
*/
|
||||||
|
MapCodec<T> codec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new upgrade type.
|
||||||
|
*
|
||||||
|
* @param codec The codec
|
||||||
|
* @param <T> The type of the generated upgrade.
|
||||||
|
* @return The newly created upgrade type.
|
||||||
|
*/
|
||||||
|
static <T extends UpgradeBase> UpgradeType<T> create(MapCodec<T> codec) {
|
||||||
|
return new UpgradeTypeImpl<>(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an upgrade type for an upgrade that takes no arguments.
|
||||||
|
* <p>
|
||||||
|
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(Function)} instead.
|
||||||
|
*
|
||||||
|
* @param instance Generate a new upgrade with a specific ID.
|
||||||
|
* @param <T> The type of the generated upgrade.
|
||||||
|
* @return A new upgrade type.
|
||||||
|
*/
|
||||||
|
static <T extends UpgradeBase> UpgradeType<T> simple(T instance) {
|
||||||
|
return create(MapCodec.unit(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an upgrade type for a simple upgrade whose crafting item can be specified.
|
||||||
|
*
|
||||||
|
* @param factory Generate a new upgrade with a specific ID and crafting item. The returned upgrade's
|
||||||
|
* {@link UpgradeBase#getCraftingItem()} <strong>MUST</strong> equal the provided item.
|
||||||
|
* @param <T> The type of the generated upgrade.
|
||||||
|
* @return A new upgrade type.
|
||||||
|
* @see #simple(UpgradeBase) For upgrades whose crafting stack should not vary.
|
||||||
|
*/
|
||||||
|
static <T extends UpgradeBase> UpgradeType<T> simpleWithCustomItem(Function<ItemStack, T> factory) {
|
||||||
|
return create(BuiltInRegistries.ITEM.byNameCodec()
|
||||||
|
.xmap(x -> factory.apply(new ItemStack(x)), x -> x.getCraftingItem().getItem())
|
||||||
|
.fieldOf("item"));
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.detail.BlockReference;
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
import dan200.computercraft.api.detail.DetailRegistry;
|
import dan200.computercraft.api.detail.DetailRegistry;
|
||||||
@ -19,7 +20,8 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|||||||
import dan200.computercraft.api.redstone.BundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.BundledRedstoneProvider;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleRefuelHandler;
|
import dan200.computercraft.api.turtle.TurtleRefuelHandler;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.impl.upgrades.TurtleToolSpec;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
@ -68,9 +70,15 @@ public interface ComputerCraftAPIService {
|
|||||||
|
|
||||||
void registerRefuelHandler(TurtleRefuelHandler handler);
|
void registerRefuelHandler(TurtleRefuelHandler handler);
|
||||||
|
|
||||||
ResourceKey<Registry<UpgradeSerialiser<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId();
|
ResourceKey<Registry<UpgradeType<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId();
|
||||||
|
|
||||||
ResourceKey<Registry<UpgradeSerialiser<? extends IPocketUpgrade>>> pocketUpgradeRegistryId();
|
Codec<ITurtleUpgrade> turtleUpgradeCodec();
|
||||||
|
|
||||||
|
ResourceKey<Registry<UpgradeType<? extends IPocketUpgrade>>> pocketUpgradeRegistryId();
|
||||||
|
|
||||||
|
ITurtleUpgrade createTurtleTool(TurtleToolSpec spec);
|
||||||
|
|
||||||
|
Codec<IPocketUpgrade> pocketUpgradeCodec();
|
||||||
|
|
||||||
DetailRegistry<ItemStack> getItemStackDetailRegistry();
|
DetailRegistry<ItemStack> getItemStackDetailRegistry();
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@ -15,6 +18,9 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public final class RegistryHelper {
|
public final class RegistryHelper {
|
||||||
|
public static final ResourceKey<Registry<ITurtleUpgrade>> TURTLE_UPGRADE = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade"));
|
||||||
|
public static final ResourceKey<Registry<IPocketUpgrade>> POCKET_UPGRADE = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade"));
|
||||||
|
|
||||||
private RegistryHelper() {
|
private RegistryHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.impl.upgrades;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.util.GsonHelper;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple serialiser which returns a constant upgrade with a custom crafting item.
|
|
||||||
* <p>
|
|
||||||
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
|
|
||||||
*
|
|
||||||
* @param <T> The upgrade that this class can serialise and deserialise.
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public final class SerialiserWithCraftingItem<T extends UpgradeBase> implements UpgradeSerialiser<T> {
|
|
||||||
private final BiFunction<ResourceLocation, ItemStack, T> factory;
|
|
||||||
|
|
||||||
public SerialiserWithCraftingItem(BiFunction<ResourceLocation, ItemStack, T> factory) {
|
|
||||||
this.factory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T fromJson(ResourceLocation id, JsonObject object) {
|
|
||||||
var item = GsonHelper.getAsItem(object, "item");
|
|
||||||
return factory.apply(id, new ItemStack(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) {
|
|
||||||
var item = ItemStack.STREAM_CODEC.decode(buffer);
|
|
||||||
return factory.apply(id, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade) {
|
|
||||||
ItemStack.STREAM_CODEC.encode(buffer, upgrade.getCraftingItem());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.impl.upgrades;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple serialiser which returns a constant upgrade.
|
|
||||||
* <p>
|
|
||||||
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
|
|
||||||
*
|
|
||||||
* @param <T> The upgrade that this class can serialise and deserialise.
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public final class SimpleSerialiser<T extends UpgradeBase> implements UpgradeSerialiser<T> {
|
|
||||||
private final Function<ResourceLocation, T> constructor;
|
|
||||||
|
|
||||||
public SimpleSerialiser(Function<ResourceLocation, T> constructor) {
|
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T fromJson(ResourceLocation id, JsonObject object) {
|
|
||||||
return constructor.apply(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) {
|
|
||||||
return constructor.apply(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toNetwork(RegistryFriendlyByteBuf buffer, T upgrade) {
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.impl.upgrades;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleToolDurability;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template for a turtle tool.
|
||||||
|
*
|
||||||
|
* @param adjective The adjective for this tool.
|
||||||
|
* @param craftItem The item used to craft this tool.
|
||||||
|
* @param toolItem The actual tool used.
|
||||||
|
* @param damageMultiplier The damage multiplier for this tool.
|
||||||
|
* @param allowEnchantments Whether to allow enchantments.
|
||||||
|
* @param consumeDurability When to consume durability.
|
||||||
|
* @param breakable The items breakable by this tool.
|
||||||
|
*/
|
||||||
|
public record TurtleToolSpec(
|
||||||
|
String adjective,
|
||||||
|
Optional<Item> craftItem,
|
||||||
|
Item toolItem,
|
||||||
|
float damageMultiplier,
|
||||||
|
boolean allowEnchantments,
|
||||||
|
TurtleToolDurability consumeDurability,
|
||||||
|
Optional<TagKey<Block>> breakable
|
||||||
|
) {
|
||||||
|
public static final float DEFAULT_DAMAGE_MULTIPLIER = 3.0f;
|
||||||
|
|
||||||
|
public static final MapCodec<TurtleToolSpec> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||||
|
Codec.STRING.fieldOf("adjective").forGetter(TurtleToolSpec::adjective),
|
||||||
|
BuiltInRegistries.ITEM.byNameCodec().optionalFieldOf("craftingItem").forGetter(TurtleToolSpec::craftItem),
|
||||||
|
BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(TurtleToolSpec::toolItem),
|
||||||
|
Codec.FLOAT.optionalFieldOf("damageMultiplier", DEFAULT_DAMAGE_MULTIPLIER).forGetter(TurtleToolSpec::damageMultiplier),
|
||||||
|
Codec.BOOL.optionalFieldOf("allowEnchantments", false).forGetter(TurtleToolSpec::allowEnchantments),
|
||||||
|
TurtleToolDurability.CODEC.optionalFieldOf("consumeDurability", TurtleToolDurability.NEVER).forGetter(TurtleToolSpec::consumeDurability),
|
||||||
|
TagKey.codec(Registries.BLOCK).optionalFieldOf("breakable").forGetter(TurtleToolSpec::breakable)
|
||||||
|
).apply(instance, TurtleToolSpec::new));
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.impl.upgrades;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple implementation of {@link UpgradeType}.
|
||||||
|
*
|
||||||
|
* @param codec The codec to read/write upgrades with.
|
||||||
|
* @param <T> The upgrade subclass that this upgrade type represents.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public record UpgradeTypeImpl<T extends UpgradeBase>(MapCodec<T> codec) implements UpgradeType<T> {
|
||||||
|
}
|
@ -128,8 +128,8 @@ public final class ClientHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void addTurtleUpgrade(Consumer<String> out, TurtleBlockEntity turtle, TurtleSide side) {
|
private static void addTurtleUpgrade(Consumer<String> out, TurtleBlockEntity turtle, TurtleSide side) {
|
||||||
var upgrade = turtle.getUpgrade(side);
|
var upgrade = turtle.getAccess().getUpgradeWithData(side);
|
||||||
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.getUpgradeID()));
|
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,17 +117,17 @@ public final class ClientRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) {
|
public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) {
|
||||||
register.register(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
register.register(ModRegistry.TurtleUpgradeTypes.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
||||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
||||||
));
|
));
|
||||||
register.register(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
register.register(ModRegistry.TurtleUpgradeTypes.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
||||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
||||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
||||||
));
|
));
|
||||||
register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
||||||
register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
register.register(ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
||||||
register.register(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
register.register(ModRegistry.TurtleUpgradeTypes.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
|
@ -10,9 +10,8 @@ import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.impl.RegistryHelper;
|
import dan200.computercraft.impl.RegistryHelper;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
|
||||||
import dan200.computercraft.impl.UpgradeManager;
|
import dan200.computercraft.impl.UpgradeManager;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
@ -30,7 +29,7 @@ public final class TurtleUpgradeModellers {
|
|||||||
private static final TurtleUpgradeModeller<ITurtleUpgrade> NULL_TURTLE_MODELLER = (upgrade, turtle, side, data) ->
|
private static final TurtleUpgradeModeller<ITurtleUpgrade> NULL_TURTLE_MODELLER = (upgrade, turtle, side, data) ->
|
||||||
new TransformedModel(Minecraft.getInstance().getModelManager().getMissingModel(), Transformation.identity());
|
new TransformedModel(Minecraft.getInstance().getModelManager().getMissingModel(), Transformation.identity());
|
||||||
|
|
||||||
private static final Map<UpgradeSerialiser<? extends ITurtleUpgrade>, TurtleUpgradeModeller<?>> turtleModels = new ConcurrentHashMap<>();
|
private static final Map<UpgradeType<? extends ITurtleUpgrade>, TurtleUpgradeModeller<?>> turtleModels = new ConcurrentHashMap<>();
|
||||||
private static volatile boolean fetchedModels;
|
private static volatile boolean fetchedModels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,15 +43,15 @@ public final class TurtleUpgradeModellers {
|
|||||||
private TurtleUpgradeModellers() {
|
private TurtleUpgradeModellers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends ITurtleUpgrade> void register(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
public static <T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller) {
|
||||||
if (fetchedModels) {
|
if (fetchedModels) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(String.format(
|
||||||
"Turtle upgrade serialiser %s must be registered before models are baked.",
|
"Turtle upgrade type %s must be registered before models are baked.",
|
||||||
RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.serialiserRegistryKey()), serialiser)
|
RegistryHelper.getKeyOrThrow(RegistryHelper.getRegistry(ITurtleUpgrade.typeRegistry()), type)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (turtleModels.putIfAbsent(serialiser, modeller) != null) {
|
if (turtleModels.putIfAbsent(type, modeller) != null) {
|
||||||
throw new IllegalStateException("Modeller already registered for serialiser");
|
throw new IllegalStateException("Modeller already registered for serialiser");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,11 +68,8 @@ public final class TurtleUpgradeModellers {
|
|||||||
return modeller.getModel(upgrade, null, side, data);
|
return modeller.getModel(upgrade, null, side, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TurtleUpgradeModeller<?> getModeller(ITurtleUpgrade upgradeA) {
|
private static TurtleUpgradeModeller<?> getModeller(ITurtleUpgrade upgrade) {
|
||||||
var wrapper = TurtleUpgrades.instance().getWrapper(upgradeA);
|
var modeller = turtleModels.get(upgrade.getType());
|
||||||
if (wrapper == null) return NULL_TURTLE_MODELLER;
|
|
||||||
|
|
||||||
var modeller = turtleModels.get(wrapper.serialiser());
|
|
||||||
return modeller == null ? NULL_TURTLE_MODELLER : modeller;
|
return modeller == null ? NULL_TURTLE_MODELLER : modeller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_axe.adjective",
|
||||||
|
"damageMultiplier": 6.0,
|
||||||
|
"item": "minecraft:diamond_axe"
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_hoe.adjective",
|
||||||
|
"breakable": "computercraft:turtle_hoe_harvestable",
|
||||||
|
"item": "minecraft:diamond_hoe"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_pickaxe.adjective",
|
||||||
|
"item": "minecraft:diamond_pickaxe"
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "computercraft:tool",
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_shovel.adjective",
|
||||||
"breakable": "computercraft:turtle_shovel_harvestable",
|
"breakable": "computercraft:turtle_shovel_harvestable",
|
||||||
"item": "minecraft:diamond_shovel"
|
"item": "minecraft:diamond_shovel"
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "computercraft:tool",
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_sword.adjective",
|
||||||
"breakable": "computercraft:turtle_sword_harvestable",
|
"breakable": "computercraft:turtle_sword_harvestable",
|
||||||
"damageMultiplier": 9.0,
|
"damageMultiplier": 9.0,
|
||||||
"item": "minecraft:diamond_sword"
|
"item": "minecraft:diamond_sword"
|
@ -1 +0,0 @@
|
|||||||
{"type": "computercraft:tool", "damageMultiplier": 6.0, "item": "minecraft:diamond_axe"}
|
|
@ -1 +0,0 @@
|
|||||||
{"type": "computercraft:tool", "breakable": "computercraft:turtle_hoe_harvestable", "item": "minecraft:diamond_hoe"}
|
|
@ -1 +0,0 @@
|
|||||||
{"type": "computercraft:tool", "item": "minecraft:diamond_pickaxe"}
|
|
@ -5,17 +5,20 @@
|
|||||||
package dan200.computercraft.data;
|
package dan200.computercraft.data;
|
||||||
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.RegistrySetBuilder;
|
||||||
import net.minecraft.data.DataProvider;
|
import net.minecraft.data.DataProvider;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.data.registries.RegistryPatchGenerator;
|
||||||
import net.minecraft.data.tags.TagsProvider;
|
import net.minecraft.data.tags.TagsProvider;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.packs.PackType;
|
import net.minecraft.server.packs.PackType;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -31,7 +34,14 @@ public final class DataProviders {
|
|||||||
public static void add(GeneratorSink generator) {
|
public static void add(GeneratorSink generator) {
|
||||||
var turtleUpgrades = generator.add(TurtleUpgradeProvider::new);
|
var turtleUpgrades = generator.add(TurtleUpgradeProvider::new);
|
||||||
var pocketUpgrades = generator.add(PocketUpgradeProvider::new);
|
var pocketUpgrades = generator.add(PocketUpgradeProvider::new);
|
||||||
generator.add((out, registries) -> new RecipeProvider(out, registries, turtleUpgrades, pocketUpgrades));
|
|
||||||
|
generator.add((out, registries) -> {
|
||||||
|
var builder = new RegistrySetBuilder();
|
||||||
|
builder.add(ModRegistry.TURTLE_UPGRADE, bs -> turtleUpgrades.getGeneratedUpgrades().forEach(bs::register));
|
||||||
|
builder.add(ModRegistry.POCKET_UPGRADE, bs -> pocketUpgrades.getGeneratedUpgrades().forEach(bs::register));
|
||||||
|
|
||||||
|
return new RecipeProvider(out, generator.createPatchedRegistries(registries, builder).thenApply(RegistrySetBuilder.PatchedRegistries::full));
|
||||||
|
});
|
||||||
|
|
||||||
var blockTags = generator.blockTags(TagProvider::blockTags);
|
var blockTags = generator.blockTags(TagProvider::blockTags);
|
||||||
generator.itemTags(TagProvider::itemTags, blockTags);
|
generator.itemTags(TagProvider::itemTags, blockTags);
|
||||||
@ -62,5 +72,18 @@ public final class DataProviders {
|
|||||||
TagsProvider<Block> blockTags(Consumer<TagProvider.TagConsumer<Block>> tags);
|
TagsProvider<Block> blockTags(Consumer<TagProvider.TagConsumer<Block>> tags);
|
||||||
|
|
||||||
TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks);
|
TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend our registries with additional entries.
|
||||||
|
*
|
||||||
|
* @param registries The existing registries.
|
||||||
|
* @param patch The new registries to apply.
|
||||||
|
* @return The built registries.
|
||||||
|
*/
|
||||||
|
default CompletableFuture<RegistrySetBuilder.PatchedRegistries> createPatchedRegistries(
|
||||||
|
CompletableFuture<HolderLookup.Provider> registries, RegistrySetBuilder patch
|
||||||
|
) {
|
||||||
|
return RegistryPatchGenerator.createLookup(registries, patch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,8 +287,8 @@ public final class LanguageProvider implements DataProvider {
|
|||||||
BuiltInRegistries.ITEM.holders()
|
BuiltInRegistries.ITEM.holders()
|
||||||
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
||||||
.map(x -> x.value().getDescriptionId()),
|
.map(x -> x.value().getDescriptionId()),
|
||||||
turtleUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),
|
turtleUpgrades.getGeneratedUpgrades().values().stream().map(UpgradeBase::getUnlocalisedAdjective),
|
||||||
pocketUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),
|
pocketUpgrades.getGeneratedUpgrades().values().stream().map(UpgradeBase::getUnlocalisedAdjective),
|
||||||
Metric.metrics().values().stream().map(x -> AggregatedMetric.TRANSLATION_PREFIX + x.name() + ".name"),
|
Metric.metrics().values().stream().map(x -> AggregatedMetric.TRANSLATION_PREFIX + x.name() + ".name"),
|
||||||
ConfigSpec.serverSpec.entries().map(ConfigFile.Entry::translationKey),
|
ConfigSpec.serverSpec.entries().map(ConfigFile.Entry::translationKey),
|
||||||
ConfigSpec.clientSpec.entries().map(ConfigFile.Entry::translationKey),
|
ConfigSpec.clientSpec.entries().map(ConfigFile.Entry::translationKey),
|
||||||
|
@ -7,14 +7,15 @@ package dan200.computercraft.data;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
|
||||||
|
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.ModRegistry.Items;
|
import static dan200.computercraft.shared.ModRegistry.Items;
|
||||||
import static dan200.computercraft.shared.ModRegistry.PocketUpgradeSerialisers;
|
|
||||||
|
|
||||||
class PocketUpgradeProvider extends PocketUpgradeDataProvider {
|
class PocketUpgradeProvider extends PocketUpgradeDataProvider {
|
||||||
PocketUpgradeProvider(PackOutput output) {
|
PocketUpgradeProvider(PackOutput output) {
|
||||||
@ -22,10 +23,10 @@ class PocketUpgradeProvider extends PocketUpgradeDataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addUpgrades(Consumer<Upgrade<UpgradeSerialiser<? extends IPocketUpgrade>>> addUpgrade) {
|
protected void addUpgrades(Consumer<Upgrade<IPocketUpgrade>> addUpgrade) {
|
||||||
addUpgrade.accept(simpleWithCustomItem(id("speaker"), PocketUpgradeSerialisers.SPEAKER.get(), Items.SPEAKER.get()));
|
upgrade(id("speaker"), new PocketSpeaker(new ItemStack(Items.SPEAKER.get()))).add(addUpgrade);
|
||||||
simpleWithCustomItem(id("wireless_modem_normal"), PocketUpgradeSerialisers.WIRELESS_MODEM_NORMAL.get(), Items.WIRELESS_MODEM_NORMAL.get()).add(addUpgrade);
|
upgrade(id("wireless_modem_normal"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_NORMAL.get()), false)).add(addUpgrade);
|
||||||
simpleWithCustomItem(id("wireless_modem_advanced"), PocketUpgradeSerialisers.WIRELESS_MODEM_ADVANCED.get(), Items.WIRELESS_MODEM_ADVANCED.get()).add(addUpgrade);
|
upgrade(id("wireless_modem_advanced"), new PocketModem(new ItemStack(Items.WIRELESS_MODEM_ADVANCED.get()), true)).add(addUpgrade);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResourceLocation id(String id) {
|
private static ResourceLocation id(String id) {
|
||||||
|
@ -8,8 +8,6 @@ import com.google.gson.JsonObject;
|
|||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.serialization.JsonOps;
|
import com.mojang.serialization.JsonOps;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.data.recipe.ShapedSpecBuilder;
|
import dan200.computercraft.data.recipe.ShapedSpecBuilder;
|
||||||
@ -61,28 +59,43 @@ import net.minecraft.world.level.block.Blocks;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER;
|
import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER;
|
||||||
import static dan200.computercraft.api.ComputerCraftTags.Items.WIRED_MODEM;
|
import static dan200.computercraft.api.ComputerCraftTags.Items.WIRED_MODEM;
|
||||||
|
|
||||||
final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||||
private final RecipeIngredients ingredients = PlatformHelper.get().getRecipeIngredients();
|
private final RecipeIngredients ingredients = PlatformHelper.get().getRecipeIngredients();
|
||||||
private final TurtleUpgradeDataProvider turtleUpgrades;
|
|
||||||
private final PocketUpgradeDataProvider pocketUpgrades;
|
|
||||||
|
|
||||||
RecipeProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
|
private final CompletableFuture<HolderLookup.Provider> registries;
|
||||||
|
|
||||||
|
RecipeProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
|
||||||
super(output, registries);
|
super(output, registries);
|
||||||
this.turtleUpgrades = turtleUpgrades;
|
this.registries = registries;
|
||||||
this.pocketUpgrades = pocketUpgrades;
|
}
|
||||||
|
|
||||||
|
private HolderLookup.Provider registries() {
|
||||||
|
try {
|
||||||
|
return registries.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new RuntimeException("Interrupted");
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
var cause = e.getCause();
|
||||||
|
throw cause instanceof RuntimeException rt ? rt : new RuntimeException("Unexpected error", cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildRecipes(RecipeOutput add) {
|
public void buildRecipes(RecipeOutput add) {
|
||||||
|
var registries = registries();
|
||||||
|
|
||||||
basicRecipes(add);
|
basicRecipes(add);
|
||||||
diskColours(add);
|
diskColours(add);
|
||||||
pocketUpgrades(add);
|
pocketUpgrades(add, registries);
|
||||||
turtleUpgrades(add);
|
turtleUpgrades(add, registries);
|
||||||
turtleOverlays(add);
|
turtleOverlays(add);
|
||||||
|
|
||||||
addSpecial(add, new PrintoutRecipe(CraftingBookCategory.MISC));
|
addSpecial(add, new PrintoutRecipe(CraftingBookCategory.MISC));
|
||||||
@ -119,15 +132,17 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
/**
|
/**
|
||||||
* Register a crafting recipe for each turtle upgrade.
|
* Register a crafting recipe for each turtle upgrade.
|
||||||
*
|
*
|
||||||
* @param add The callback to add recipes.
|
* @param add The callback to add recipes.
|
||||||
|
* @param registries The currently available registries.
|
||||||
*/
|
*/
|
||||||
private void turtleUpgrades(RecipeOutput add) {
|
private void turtleUpgrades(RecipeOutput add, HolderLookup.Provider registries) {
|
||||||
for (var turtleItem : turtleItems()) {
|
for (var turtleItem : turtleItems()) {
|
||||||
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
||||||
|
|
||||||
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
|
registries.lookup(ModRegistry.TURTLE_UPGRADE).map(HolderLookup::listElements).orElse(Stream.empty()).forEach(upgradeHolder -> {
|
||||||
|
var upgrade = upgradeHolder.value();
|
||||||
ShapedSpecBuilder
|
ShapedSpecBuilder
|
||||||
.shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade)))
|
.shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder)))
|
||||||
.group(name.toString())
|
.group(name.toString())
|
||||||
.pattern("#T")
|
.pattern("#T")
|
||||||
.define('T', turtleItem)
|
.define('T', turtleItem)
|
||||||
@ -136,9 +151,9 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
.build(ImpostorShapedRecipe::new)
|
.build(ImpostorShapedRecipe::new)
|
||||||
.save(
|
.save(
|
||||||
add,
|
add,
|
||||||
name.withSuffix(String.format("/%s/%s", upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath()))
|
name.withSuffix(String.format("/%s/%s", upgradeHolder.key().location().getNamespace(), upgradeHolder.key().location().getPath()))
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,15 +164,17 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
/**
|
/**
|
||||||
* Register a crafting recipe for each pocket upgrade.
|
* Register a crafting recipe for each pocket upgrade.
|
||||||
*
|
*
|
||||||
* @param add The callback to add recipes.
|
* @param add The callback to add recipes.
|
||||||
|
* @param registries The currently available registries.
|
||||||
*/
|
*/
|
||||||
private void pocketUpgrades(RecipeOutput add) {
|
private void pocketUpgrades(RecipeOutput add, HolderLookup.Provider registries) {
|
||||||
for (var pocket : pocketComputerItems()) {
|
for (var pocket : pocketComputerItems()) {
|
||||||
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, pocket).withPath(x -> x.replace("pocket_computer_", "pocket_"));
|
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, pocket).withPath(x -> x.replace("pocket_computer_", "pocket_"));
|
||||||
|
|
||||||
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
|
registries.lookup(ModRegistry.POCKET_UPGRADE).map(HolderLookup::listElements).orElse(Stream.empty()).forEach(upgradeHolder -> {
|
||||||
|
var upgrade = upgradeHolder.value();
|
||||||
ShapedSpecBuilder
|
ShapedSpecBuilder
|
||||||
.shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade)))
|
.shaped(RecipeCategory.REDSTONE, DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgradeHolder)))
|
||||||
.group(name.toString())
|
.group(name.toString())
|
||||||
.pattern("#")
|
.pattern("#")
|
||||||
.pattern("P")
|
.pattern("P")
|
||||||
@ -167,9 +184,9 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
.build(ImpostorShapedRecipe::new)
|
.build(ImpostorShapedRecipe::new)
|
||||||
.save(
|
.save(
|
||||||
add,
|
add,
|
||||||
name.withSuffix(String.format("/%s/%s", upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath()))
|
name.withSuffix(String.format("/%s/%s", upgradeHolder.key().location().getNamespace(), upgradeHolder.key().location().getPath()))
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,32 +8,34 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
|||||||
import dan200.computercraft.api.ComputerCraftTags.Blocks;
|
import dan200.computercraft.api.ComputerCraftTags.Blocks;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleCraftingTable;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleSpeaker;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.ModRegistry.Items;
|
|
||||||
import static dan200.computercraft.shared.ModRegistry.TurtleSerialisers;
|
|
||||||
|
|
||||||
class TurtleUpgradeProvider extends TurtleUpgradeDataProvider {
|
class TurtleUpgradeProvider extends TurtleUpgradeDataProvider {
|
||||||
TurtleUpgradeProvider(PackOutput output) {
|
TurtleUpgradeProvider(PackOutput output) {
|
||||||
super(output);
|
super(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addUpgrades(Consumer<Upgrade<UpgradeSerialiser<? extends ITurtleUpgrade>>> addUpgrade) {
|
protected void addUpgrades(Consumer<Upgrade<ITurtleUpgrade>> addUpgrade) {
|
||||||
simpleWithCustomItem(id("speaker"), TurtleSerialisers.SPEAKER.get(), Items.SPEAKER.get()).add(addUpgrade);
|
upgrade(id("speaker"), new TurtleSpeaker(new ItemStack(ModRegistry.Items.SPEAKER.get()))).add(addUpgrade);
|
||||||
simpleWithCustomItem(vanilla("crafting_table"), TurtleSerialisers.WORKBENCH.get(), net.minecraft.world.item.Items.CRAFTING_TABLE).add(addUpgrade);
|
upgrade(vanilla("crafting_table"), new TurtleCraftingTable(new ItemStack(Items.CRAFTING_TABLE))).add(addUpgrade);
|
||||||
simpleWithCustomItem(id("wireless_modem_normal"), TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), Items.WIRELESS_MODEM_NORMAL.get()).add(addUpgrade);
|
upgrade(id("wireless_modem_normal"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_NORMAL.get()), false)).add(addUpgrade);
|
||||||
simpleWithCustomItem(id("wireless_modem_advanced"), TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), Items.WIRELESS_MODEM_ADVANCED.get()).add(addUpgrade);
|
upgrade(id("wireless_modem_advanced"), new TurtleModem(new ItemStack(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get()), true)).add(addUpgrade);
|
||||||
|
|
||||||
tool(vanilla("diamond_axe"), net.minecraft.world.item.Items.DIAMOND_AXE).damageMultiplier(6.0f).add(addUpgrade);
|
tool(vanilla("diamond_axe"), Items.DIAMOND_AXE).damageMultiplier(6.0f).add(addUpgrade);
|
||||||
tool(vanilla("diamond_pickaxe"), net.minecraft.world.item.Items.DIAMOND_PICKAXE).add(addUpgrade);
|
tool(vanilla("diamond_pickaxe"), Items.DIAMOND_PICKAXE).add(addUpgrade);
|
||||||
tool(vanilla("diamond_hoe"), net.minecraft.world.item.Items.DIAMOND_HOE).breakable(Blocks.TURTLE_HOE_BREAKABLE).add(addUpgrade);
|
tool(vanilla("diamond_hoe"), Items.DIAMOND_HOE).breakable(Blocks.TURTLE_HOE_BREAKABLE).add(addUpgrade);
|
||||||
tool(vanilla("diamond_shovel"), net.minecraft.world.item.Items.DIAMOND_SHOVEL).breakable(Blocks.TURTLE_SHOVEL_BREAKABLE).add(addUpgrade);
|
tool(vanilla("diamond_shovel"), Items.DIAMOND_SHOVEL).breakable(Blocks.TURTLE_SHOVEL_BREAKABLE).add(addUpgrade);
|
||||||
tool(vanilla("diamond_sword"), net.minecraft.world.item.Items.DIAMOND_SWORD).breakable(Blocks.TURTLE_SWORD_BREAKABLE).damageMultiplier(9.0f).add(addUpgrade);
|
tool(vanilla("diamond_sword"), Items.DIAMOND_SWORD).breakable(Blocks.TURTLE_SWORD_BREAKABLE).damageMultiplier(9.0f).add(addUpgrade);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResourceLocation id(String id) {
|
private static ResourceLocation id(String id) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.detail.BlockReference;
|
import dan200.computercraft.api.detail.BlockReference;
|
||||||
import dan200.computercraft.api.detail.DetailRegistry;
|
import dan200.computercraft.api.detail.DetailRegistry;
|
||||||
@ -19,14 +20,16 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|||||||
import dan200.computercraft.api.redstone.BundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.BundledRedstoneProvider;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleRefuelHandler;
|
import dan200.computercraft.api.turtle.TurtleRefuelHandler;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.core.filesystem.WritableFileMount;
|
import dan200.computercraft.core.filesystem.WritableFileMount;
|
||||||
import dan200.computercraft.impl.detail.DetailRegistryImpl;
|
import dan200.computercraft.impl.detail.DetailRegistryImpl;
|
||||||
import dan200.computercraft.impl.network.wired.WiredNodeImpl;
|
import dan200.computercraft.impl.network.wired.WiredNodeImpl;
|
||||||
|
import dan200.computercraft.impl.upgrades.TurtleToolSpec;
|
||||||
import dan200.computercraft.shared.computer.core.ResourceMount;
|
import dan200.computercraft.shared.computer.core.ResourceMount;
|
||||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||||
import dan200.computercraft.shared.details.BlockDetails;
|
import dan200.computercraft.shared.details.BlockDetails;
|
||||||
import dan200.computercraft.shared.details.ItemDetails;
|
import dan200.computercraft.shared.details.ItemDetails;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleTool;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
@ -45,8 +48,8 @@ public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIServic
|
|||||||
private final DetailRegistry<ItemStack> itemStackDetails = new DetailRegistryImpl<>(ItemDetails::fillBasic);
|
private final DetailRegistry<ItemStack> itemStackDetails = new DetailRegistryImpl<>(ItemDetails::fillBasic);
|
||||||
private final DetailRegistry<BlockReference> blockDetails = new DetailRegistryImpl<>(BlockDetails::fillBasic);
|
private final DetailRegistry<BlockReference> blockDetails = new DetailRegistryImpl<>(BlockDetails::fillBasic);
|
||||||
|
|
||||||
protected static final ResourceKey<Registry<UpgradeSerialiser<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade_serialiser"));
|
protected static final ResourceKey<Registry<UpgradeType<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade_type"));
|
||||||
protected static final ResourceKey<Registry<UpgradeSerialiser<? extends IPocketUpgrade>>> pocketUpgradeRegistryId = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade_serialiser"));
|
protected static final ResourceKey<Registry<UpgradeType<? extends IPocketUpgrade>>> pocketUpgradeRegistryId = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade_type"));
|
||||||
|
|
||||||
public static @Nullable InputStream getResourceFile(MinecraftServer server, String domain, String subPath) {
|
public static @Nullable InputStream getResourceFile(MinecraftServer server, String domain, String subPath) {
|
||||||
var manager = server.getResourceManager();
|
var manager = server.getResourceManager();
|
||||||
@ -117,15 +120,30 @@ public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ResourceKey<Registry<UpgradeSerialiser<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId() {
|
public final ResourceKey<Registry<UpgradeType<? extends ITurtleUpgrade>>> turtleUpgradeRegistryId() {
|
||||||
return turtleUpgradeRegistryId;
|
return turtleUpgradeRegistryId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ResourceKey<Registry<UpgradeSerialiser<? extends IPocketUpgrade>>> pocketUpgradeRegistryId() {
|
public Codec<ITurtleUpgrade> turtleUpgradeCodec() {
|
||||||
|
return TurtleUpgrades.instance().upgradeCodec();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITurtleUpgrade createTurtleTool(TurtleToolSpec spec) {
|
||||||
|
return new TurtleTool(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ResourceKey<Registry<UpgradeType<? extends IPocketUpgrade>>> pocketUpgradeRegistryId() {
|
||||||
return pocketUpgradeRegistryId;
|
return pocketUpgradeRegistryId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Codec<IPocketUpgrade> pocketUpgradeCodec() {
|
||||||
|
return PocketUpgrades.instance().upgradeCodec();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final DetailRegistry<ItemStack> getItemStackDetailRegistry() {
|
public final DetailRegistry<ItemStack> getItemStackDetailRegistry() {
|
||||||
return itemStackDetails;
|
return itemStackDetails;
|
||||||
|
@ -4,14 +4,12 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public final class PocketUpgrades {
|
public final class PocketUpgrades {
|
||||||
private static final UpgradeManager<IPocketUpgrade> registry = new UpgradeManager<>(
|
private static final UpgradeManager<IPocketUpgrade> registry = new UpgradeManager<>(
|
||||||
"pocket computer upgrade", "computercraft/pocket_upgrades", IPocketUpgrade.serialiserRegistryKey()
|
IPocketUpgrade.typeRegistry(), ModRegistry.POCKET_UPGRADE, IPocketUpgrade::getType
|
||||||
);
|
);
|
||||||
|
|
||||||
private PocketUpgrades() {
|
private PocketUpgrades() {
|
||||||
@ -20,10 +18,4 @@ public final class PocketUpgrades {
|
|||||||
public static UpgradeManager<IPocketUpgrade> instance() {
|
public static UpgradeManager<IPocketUpgrade> instance() {
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<IPocketUpgrade> getVanillaUpgrades() {
|
|
||||||
return instance().getUpgradeWrappers().values().stream()
|
|
||||||
.filter(x -> x.modId().equals(ComputerCraftAPI.MOD_ID))
|
|
||||||
.map(UpgradeManager.UpgradeWrapper::upgrade);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,12 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public final class TurtleUpgrades {
|
public final class TurtleUpgrades {
|
||||||
private static final UpgradeManager<ITurtleUpgrade> registry = new UpgradeManager<>(
|
private static final UpgradeManager<ITurtleUpgrade> registry = new UpgradeManager<>(
|
||||||
"turtle upgrade", "computercraft/turtle_upgrades", ITurtleUpgrade.serialiserRegistryKey()
|
ITurtleUpgrade.typeRegistry(), ModRegistry.TURTLE_UPGRADE, ITurtleUpgrade::getType
|
||||||
);
|
);
|
||||||
|
|
||||||
private TurtleUpgrades() {
|
private TurtleUpgrades() {
|
||||||
@ -20,10 +18,4 @@ public final class TurtleUpgrades {
|
|||||||
public static UpgradeManager<ITurtleUpgrade> instance() {
|
public static UpgradeManager<ITurtleUpgrade> instance() {
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<ITurtleUpgrade> getVanillaUpgrades() {
|
|
||||||
return instance().getUpgradeWrappers().values().stream()
|
|
||||||
.filter(x -> x.modId().equals(ComputerCraftAPI.MOD_ID))
|
|
||||||
.map(UpgradeManager.UpgradeWrapper::upgrade);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,36 +4,26 @@
|
|||||||
|
|
||||||
package dan200.computercraft.impl;
|
package dan200.computercraft.impl;
|
||||||
|
|
||||||
import com.google.gson.*;
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.DataResult;
|
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.util.SafeDispatchCodec;
|
||||||
import io.netty.buffer.ByteBuf;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.resources.RegistryFixedCodec;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
|
|
||||||
import net.minecraft.util.GsonHelper;
|
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collection;
|
import java.util.function.Function;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages turtle and pocket computer upgrades.
|
* Manages turtle and pocket computer upgrades.
|
||||||
@ -42,145 +32,81 @@ import java.util.stream.Collectors;
|
|||||||
* @see TurtleUpgrades
|
* @see TurtleUpgrades
|
||||||
* @see PocketUpgrades
|
* @see PocketUpgrades
|
||||||
*/
|
*/
|
||||||
public class UpgradeManager<T extends UpgradeBase> extends SimpleJsonResourceReloadListener {
|
public final class UpgradeManager<T extends UpgradeBase> {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(UpgradeManager.class);
|
private final ResourceKey<Registry<T>> registry;
|
||||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
private final Codec<T> upgradeCodec;
|
||||||
|
private final Codec<UpgradeData<T>> dataCodec;
|
||||||
|
private final StreamCodec<RegistryFriendlyByteBuf, UpgradeData<T>> dataStreamCodec;
|
||||||
|
|
||||||
public record UpgradeWrapper<T extends UpgradeBase>(
|
UpgradeManager(
|
||||||
ResourceLocation id, T upgrade, UpgradeSerialiser<? extends T> serialiser, String modId
|
ResourceKey<Registry<UpgradeType<? extends T>>> typeRegistry,
|
||||||
|
ResourceKey<Registry<T>> registry,
|
||||||
|
Function<T, UpgradeType<? extends T>> getType
|
||||||
) {
|
) {
|
||||||
}
|
|
||||||
|
|
||||||
private final String kind;
|
|
||||||
private final ResourceKey<Registry<UpgradeSerialiser<? extends T>>> registry;
|
|
||||||
|
|
||||||
private Map<ResourceLocation, UpgradeWrapper<T>> current = Map.of();
|
|
||||||
private Map<T, UpgradeWrapper<T>> currentWrappers = Map.of();
|
|
||||||
|
|
||||||
private final Codec<T> upgradeCodec = ResourceLocation.CODEC.flatXmap(
|
|
||||||
x -> {
|
|
||||||
var upgrade = get(x);
|
|
||||||
return upgrade == null ? DataResult.error(() -> "Unknown upgrade " + x) : DataResult.success(upgrade);
|
|
||||||
},
|
|
||||||
x -> DataResult.success(x.getUpgradeID())
|
|
||||||
);
|
|
||||||
|
|
||||||
private final Codec<UpgradeData<T>> fullCodec = RecordCodecBuilder.create(i -> i.group(
|
|
||||||
upgradeCodec.fieldOf("id").forGetter(UpgradeData::upgrade),
|
|
||||||
DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(UpgradeData::data)
|
|
||||||
).apply(i, UpgradeData::new));
|
|
||||||
|
|
||||||
private final Codec<UpgradeData<T>> codec = Codec.withAlternative(fullCodec, upgradeCodec, UpgradeData::ofDefault);
|
|
||||||
|
|
||||||
private final StreamCodec<ByteBuf, T> upgradeStreamCodec = ResourceLocation.STREAM_CODEC.map(
|
|
||||||
x -> {
|
|
||||||
var upgrade = get(x);
|
|
||||||
if (upgrade == null) throw new IllegalStateException("Unknown upgrade " + x);
|
|
||||||
return upgrade;
|
|
||||||
},
|
|
||||||
UpgradeBase::getUpgradeID
|
|
||||||
);
|
|
||||||
|
|
||||||
private final StreamCodec<RegistryFriendlyByteBuf, UpgradeData<T>> streamCodec = StreamCodec.composite(
|
|
||||||
upgradeStreamCodec, UpgradeData::upgrade,
|
|
||||||
DataComponentPatch.STREAM_CODEC, UpgradeData::data,
|
|
||||||
UpgradeData::new
|
|
||||||
);
|
|
||||||
|
|
||||||
public UpgradeManager(String kind, String path, ResourceKey<Registry<UpgradeSerialiser<? extends T>>> registry) {
|
|
||||||
super(GSON, path);
|
|
||||||
this.kind = kind;
|
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
|
|
||||||
|
upgradeCodec = SafeDispatchCodec.ofRegistry(typeRegistry, getType, UpgradeType::codec);
|
||||||
|
|
||||||
|
var holderCodec = RegistryFixedCodec.create(registry).xmap(x -> (Holder.Reference<T>) x, x -> x);
|
||||||
|
Codec<UpgradeData<T>> fullCodec = RecordCodecBuilder.create(i -> i.group(
|
||||||
|
holderCodec.fieldOf("id").forGetter(UpgradeData::holder),
|
||||||
|
DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(UpgradeData::data)
|
||||||
|
).apply(i, UpgradeData::new));
|
||||||
|
dataCodec = Codec.withAlternative(fullCodec, holderCodec, UpgradeData::ofDefault);
|
||||||
|
|
||||||
|
dataStreamCodec = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.holderRegistry(registry).map(x -> (Holder.Reference<T>) x, x -> x), UpgradeData::holder,
|
||||||
|
DataComponentPatch.STREAM_CODEC, UpgradeData::data,
|
||||||
|
UpgradeData::new
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The codec for an upgrade instance.
|
||||||
|
*
|
||||||
|
* @return The instance codec.
|
||||||
|
*/
|
||||||
|
public Codec<T> upgradeCodec() {
|
||||||
|
return upgradeCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The codec for an upgrade and its associated data.
|
||||||
|
*
|
||||||
|
* @return The upgrade data codec.
|
||||||
|
*/
|
||||||
|
public Codec<UpgradeData<T>> upgradeDataCodec() {
|
||||||
|
return dataCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream codec for an upgrade and its associated data.
|
||||||
|
*
|
||||||
|
* @return The upgrade data codec.
|
||||||
|
*/
|
||||||
|
public StreamCodec<RegistryFriendlyByteBuf, UpgradeData<T>> upgradeDataStreamCodec() {
|
||||||
|
return dataStreamCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOwner(Holder.Reference<T> upgrade) {
|
||||||
|
var ns = upgrade.key().location().getNamespace();
|
||||||
|
return ns.equals("minecraft") ? ComputerCraftAPI.MOD_ID : ns;
|
||||||
|
|
||||||
|
// TODO: Would be nice if we could use the registration info here.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public T get(ResourceLocation id) {
|
public UpgradeData<T> get(HolderLookup.Provider registries, ItemStack stack) {
|
||||||
var wrapper = current.get(id);
|
|
||||||
return wrapper == null ? null : wrapper.upgrade();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public UpgradeWrapper<T> getWrapper(T upgrade) {
|
|
||||||
return currentWrappers.get(upgrade);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getOwner(T upgrade) {
|
|
||||||
var wrapper = currentWrappers.get(upgrade);
|
|
||||||
return wrapper != null ? wrapper.modId() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public UpgradeData<T> get(ItemStack stack) {
|
|
||||||
if (stack.isEmpty()) return null;
|
if (stack.isEmpty()) return null;
|
||||||
|
|
||||||
for (var wrapper : current.values()) {
|
return registries.lookupOrThrow(registry).listElements()
|
||||||
var craftingStack = wrapper.upgrade().getCraftingItem();
|
.filter(holder -> {
|
||||||
if (!craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade().isItemSuitable(stack)) {
|
var upgrade = holder.value();
|
||||||
return UpgradeData.of(wrapper.upgrade, wrapper.upgrade.getUpgradeData(stack));
|
var craftingStack = upgrade.getCraftingItem();
|
||||||
}
|
return !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.isItemSuitable(stack);
|
||||||
}
|
})
|
||||||
|
.findAny()
|
||||||
return null;
|
.map(x -> UpgradeData.of(x, x.value().getUpgradeData(stack)))
|
||||||
}
|
.orElse(null);
|
||||||
|
|
||||||
public Collection<T> getUpgrades() {
|
|
||||||
return currentWrappers.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<ResourceLocation, UpgradeWrapper<T>> getUpgradeWrappers() {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Codec<UpgradeData<T>> codec() {
|
|
||||||
return codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StreamCodec<RegistryFriendlyByteBuf, UpgradeData<T>> streamCodec() {
|
|
||||||
return streamCodec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void apply(Map<ResourceLocation, JsonElement> upgrades, ResourceManager manager, ProfilerFiller profiler) {
|
|
||||||
var registry = RegistryHelper.getRegistry(this.registry);
|
|
||||||
Map<ResourceLocation, UpgradeWrapper<T>> newUpgrades = new HashMap<>();
|
|
||||||
for (var element : upgrades.entrySet()) {
|
|
||||||
try {
|
|
||||||
loadUpgrade(registry, newUpgrades, element.getKey(), element.getValue());
|
|
||||||
} catch (IllegalArgumentException | JsonParseException e) {
|
|
||||||
LOG.error("Error loading {} {} from JSON file", kind, element.getKey(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = Collections.unmodifiableMap(newUpgrades);
|
|
||||||
currentWrappers = newUpgrades.values().stream().collect(Collectors.toUnmodifiableMap(UpgradeWrapper::upgrade, x -> x));
|
|
||||||
LOG.info("Loaded {} {}s", current.size(), kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadUpgrade(Registry<UpgradeSerialiser<? extends T>> registry, Map<ResourceLocation, UpgradeWrapper<T>> current, ResourceLocation id, JsonElement json) {
|
|
||||||
var root = GsonHelper.convertToJsonObject(json, "top element");
|
|
||||||
if (!PlatformHelper.get().shouldLoadResource(root)) return;
|
|
||||||
|
|
||||||
var serialiserId = new ResourceLocation(GsonHelper.getAsString(root, "type"));
|
|
||||||
var serialiser = registry.get(serialiserId);
|
|
||||||
if (serialiser == null) throw new JsonSyntaxException("Unknown upgrade type '" + serialiserId + "'");
|
|
||||||
|
|
||||||
// TODO: Can we track which mod this resource came from and use that instead? It's theoretically possible,
|
|
||||||
// but maybe not ideal for datapacks.
|
|
||||||
var modId = id.getNamespace();
|
|
||||||
if (modId.equals("minecraft") || modId.isEmpty()) modId = ComputerCraftAPI.MOD_ID;
|
|
||||||
|
|
||||||
var upgrade = serialiser.fromJson(id, root);
|
|
||||||
if (!upgrade.getUpgradeID().equals(id)) {
|
|
||||||
throw new IllegalArgumentException("Upgrade " + id + " from " + serialiser + " was incorrectly given id " + upgrade.getUpgradeID());
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new UpgradeWrapper<T>(id, upgrade, serialiser, modId);
|
|
||||||
current.put(result.id(), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadFromNetwork(Map<ResourceLocation, UpgradeWrapper<T>> newUpgrades) {
|
|
||||||
current = Collections.unmodifiableMap(newUpgrades);
|
|
||||||
currentWrappers = newUpgrades.values().stream().collect(Collectors.toUnmodifiableMap(UpgradeWrapper::upgrade, x -> x));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ package dan200.computercraft.shared;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
|
||||||
import dan200.computercraft.shared.computer.core.ResourceMount;
|
import dan200.computercraft.shared.computer.core.ResourceMount;
|
||||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||||
import dan200.computercraft.shared.computer.metrics.ComputerMBean;
|
import dan200.computercraft.shared.computer.metrics.ComputerMBean;
|
||||||
@ -121,8 +119,6 @@ public final class CommonHooks {
|
|||||||
|
|
||||||
public static void onDatapackReload(BiConsumer<String, PreparableReloadListener> addReload) {
|
public static void onDatapackReload(BiConsumer<String, PreparableReloadListener> addReload) {
|
||||||
addReload.accept("mounts", ResourceMount.RELOAD_LISTENER);
|
addReload.accept("mounts", ResourceMount.RELOAD_LISTENER);
|
||||||
addReload.accept("turtle_upgrades", TurtleUpgrades.instance());
|
|
||||||
addReload.accept("pocket_upgrades", PocketUpgrades.instance());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean onEntitySpawn(Entity entity) {
|
public static boolean onEntitySpawn(Entity entity) {
|
||||||
|
@ -13,11 +13,12 @@ import dan200.computercraft.api.detail.VanillaDetailRegistries;
|
|||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.RegistryHelper;
|
||||||
import dan200.computercraft.shared.command.UserLevel;
|
import dan200.computercraft.shared.command.UserLevel;
|
||||||
import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
|
import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
|
||||||
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
|
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
|
||||||
@ -79,12 +80,18 @@ import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
|||||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
import dan200.computercraft.shared.turtle.upgrades.TurtleCraftingTable;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleSpeaker;
|
||||||
|
import dan200.computercraft.shared.turtle.upgrades.TurtleTool;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
import dan200.computercraft.shared.util.NonNegativeId;
|
import dan200.computercraft.shared.util.NonNegativeId;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
|
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.cauldron.CauldronInteraction;
|
import net.minecraft.core.cauldron.CauldronInteraction;
|
||||||
import net.minecraft.core.component.DataComponentType;
|
import net.minecraft.core.component.DataComponentType;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
@ -92,6 +99,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
|
|||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.flag.FeatureFlags;
|
import net.minecraft.world.flag.FeatureFlags;
|
||||||
import net.minecraft.world.inventory.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
@ -122,6 +130,9 @@ public final class ModRegistry {
|
|||||||
private ModRegistry() {
|
private ModRegistry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final ResourceKey<Registry<ITurtleUpgrade>> TURTLE_UPGRADE = RegistryHelper.TURTLE_UPGRADE;
|
||||||
|
public static final ResourceKey<Registry<IPocketUpgrade>> POCKET_UPGRADE = RegistryHelper.POCKET_UPGRADE;
|
||||||
|
|
||||||
public static final class Blocks {
|
public static final class Blocks {
|
||||||
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
|
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
|
||||||
|
|
||||||
@ -289,7 +300,7 @@ public final class ModRegistry {
|
|||||||
* @see TurtleItem
|
* @see TurtleItem
|
||||||
*/
|
*/
|
||||||
public static final RegistryEntry<DataComponentType<UpgradeData<ITurtleUpgrade>>> LEFT_TURTLE_UPGRADE = register("left_turtle_upgrade", b -> b
|
public static final RegistryEntry<DataComponentType<UpgradeData<ITurtleUpgrade>>> LEFT_TURTLE_UPGRADE = register("left_turtle_upgrade", b -> b
|
||||||
.persistent(TurtleUpgrades.instance().codec()).networkSynchronized(TurtleUpgrades.instance().streamCodec())
|
.persistent(dan200.computercraft.impl.TurtleUpgrades.instance().upgradeDataCodec()).networkSynchronized(dan200.computercraft.impl.TurtleUpgrades.instance().upgradeDataStreamCodec())
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,7 +309,7 @@ public final class ModRegistry {
|
|||||||
* @see TurtleItem
|
* @see TurtleItem
|
||||||
*/
|
*/
|
||||||
public static final RegistryEntry<DataComponentType<UpgradeData<ITurtleUpgrade>>> RIGHT_TURTLE_UPGRADE = register("right_turtle_upgrade", b -> b
|
public static final RegistryEntry<DataComponentType<UpgradeData<ITurtleUpgrade>>> RIGHT_TURTLE_UPGRADE = register("right_turtle_upgrade", b -> b
|
||||||
.persistent(TurtleUpgrades.instance().codec()).networkSynchronized(TurtleUpgrades.instance().streamCodec())
|
.persistent(dan200.computercraft.impl.TurtleUpgrades.instance().upgradeDataCodec()).networkSynchronized(dan200.computercraft.impl.TurtleUpgrades.instance().upgradeDataStreamCodec())
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,7 +332,7 @@ public final class ModRegistry {
|
|||||||
* @see PocketComputerItem
|
* @see PocketComputerItem
|
||||||
*/
|
*/
|
||||||
public static final RegistryEntry<DataComponentType<UpgradeData<IPocketUpgrade>>> POCKET_UPGRADE = register("pocket_upgrade", b -> b
|
public static final RegistryEntry<DataComponentType<UpgradeData<IPocketUpgrade>>> POCKET_UPGRADE = register("pocket_upgrade", b -> b
|
||||||
.persistent(PocketUpgrades.instance().codec()).networkSynchronized(PocketUpgrades.instance().streamCodec())
|
.persistent(PocketUpgrades.instance().upgradeDataCodec()).networkSynchronized(PocketUpgrades.instance().upgradeDataStreamCodec())
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,30 +385,30 @@ public final class ModRegistry {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TurtleSerialisers {
|
public static class TurtleUpgradeTypes {
|
||||||
static final RegistrationHelper<UpgradeSerialiser<? extends ITurtleUpgrade>> REGISTRY = PlatformHelper.get().createRegistrationHelper(ITurtleUpgrade.serialiserRegistryKey());
|
static final RegistrationHelper<UpgradeType<? extends ITurtleUpgrade>> REGISTRY = PlatformHelper.get().createRegistrationHelper(ITurtleUpgrade.typeRegistry());
|
||||||
|
|
||||||
public static final RegistryEntry<UpgradeSerialiser<TurtleSpeaker>> SPEAKER =
|
public static final RegistryEntry<UpgradeType<TurtleSpeaker>> SPEAKER =
|
||||||
REGISTRY.register("speaker", () -> UpgradeSerialiser.simpleWithCustomItem(TurtleSpeaker::new));
|
REGISTRY.register("speaker", () -> UpgradeType.simpleWithCustomItem(TurtleSpeaker::new));
|
||||||
public static final RegistryEntry<UpgradeSerialiser<TurtleCraftingTable>> WORKBENCH =
|
public static final RegistryEntry<UpgradeType<TurtleCraftingTable>> WORKBENCH =
|
||||||
REGISTRY.register("workbench", () -> UpgradeSerialiser.simpleWithCustomItem(TurtleCraftingTable::new));
|
REGISTRY.register("workbench", () -> UpgradeType.simpleWithCustomItem(TurtleCraftingTable::new));
|
||||||
public static final RegistryEntry<UpgradeSerialiser<TurtleModem>> WIRELESS_MODEM_NORMAL =
|
public static final RegistryEntry<UpgradeType<TurtleModem>> WIRELESS_MODEM_NORMAL =
|
||||||
REGISTRY.register("wireless_modem_normal", () -> UpgradeSerialiser.simpleWithCustomItem((id, item) -> new TurtleModem(id, item, false)));
|
REGISTRY.register("wireless_modem_normal", () -> UpgradeType.simpleWithCustomItem(item -> new TurtleModem(item, false)));
|
||||||
public static final RegistryEntry<UpgradeSerialiser<TurtleModem>> WIRELESS_MODEM_ADVANCED =
|
public static final RegistryEntry<UpgradeType<TurtleModem>> WIRELESS_MODEM_ADVANCED =
|
||||||
REGISTRY.register("wireless_modem_advanced", () -> UpgradeSerialiser.simpleWithCustomItem((id, item) -> new TurtleModem(id, item, true)));
|
REGISTRY.register("wireless_modem_advanced", () -> UpgradeType.simpleWithCustomItem(item -> new TurtleModem(item, true)));
|
||||||
|
|
||||||
public static final RegistryEntry<UpgradeSerialiser<TurtleTool>> TOOL = REGISTRY.register("tool", () -> TurtleToolSerialiser.INSTANCE);
|
public static final RegistryEntry<UpgradeType<TurtleTool>> TOOL = REGISTRY.register("tool", () -> UpgradeType.create(TurtleTool.CODEC));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PocketUpgradeSerialisers {
|
public static class PocketUpgradeTypes {
|
||||||
static final RegistrationHelper<UpgradeSerialiser<? extends IPocketUpgrade>> REGISTRY = PlatformHelper.get().createRegistrationHelper(IPocketUpgrade.serialiserRegistryKey());
|
static final RegistrationHelper<UpgradeType<? extends IPocketUpgrade>> REGISTRY = PlatformHelper.get().createRegistrationHelper(IPocketUpgrade.typeRegistry());
|
||||||
|
|
||||||
public static final RegistryEntry<UpgradeSerialiser<PocketSpeaker>> SPEAKER =
|
public static final RegistryEntry<UpgradeType<PocketSpeaker>> SPEAKER =
|
||||||
REGISTRY.register("speaker", () -> UpgradeSerialiser.simpleWithCustomItem(PocketSpeaker::new));
|
REGISTRY.register("speaker", () -> UpgradeType.simpleWithCustomItem(PocketSpeaker::new));
|
||||||
public static final RegistryEntry<UpgradeSerialiser<PocketModem>> WIRELESS_MODEM_NORMAL =
|
public static final RegistryEntry<UpgradeType<PocketModem>> WIRELESS_MODEM_NORMAL =
|
||||||
REGISTRY.register("wireless_modem_normal", () -> UpgradeSerialiser.simpleWithCustomItem((id, item) -> new PocketModem(id, item, false)));
|
REGISTRY.register("wireless_modem_normal", () -> UpgradeType.simpleWithCustomItem(item -> new PocketModem(item, false)));
|
||||||
public static final RegistryEntry<UpgradeSerialiser<PocketModem>> WIRELESS_MODEM_ADVANCED =
|
public static final RegistryEntry<UpgradeType<PocketModem>> WIRELESS_MODEM_ADVANCED =
|
||||||
REGISTRY.register("wireless_modem_advanced", () -> UpgradeSerialiser.simpleWithCustomItem((id, item) -> new PocketModem(id, item, true)));
|
REGISTRY.register("wireless_modem_advanced", () -> UpgradeType.simpleWithCustomItem(item -> new PocketModem(item, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Menus {
|
public static class Menus {
|
||||||
@ -525,10 +536,10 @@ public final class ModRegistry {
|
|||||||
out.accept(new ItemStack(Items.COMPUTER_NORMAL.get()));
|
out.accept(new ItemStack(Items.COMPUTER_NORMAL.get()));
|
||||||
out.accept(new ItemStack(Items.COMPUTER_ADVANCED.get()));
|
out.accept(new ItemStack(Items.COMPUTER_ADVANCED.get()));
|
||||||
if (context.hasPermissions()) out.accept(new ItemStack(Items.COMPUTER_COMMAND.get()));
|
if (context.hasPermissions()) out.accept(new ItemStack(Items.COMPUTER_COMMAND.get()));
|
||||||
addTurtle(out, Items.TURTLE_NORMAL.get());
|
addTurtle(out, Items.TURTLE_NORMAL.get(), context.holders());
|
||||||
addTurtle(out, Items.TURTLE_ADVANCED.get());
|
addTurtle(out, Items.TURTLE_ADVANCED.get(), context.holders());
|
||||||
addPocket(out, Items.POCKET_COMPUTER_NORMAL.get());
|
addPocket(out, Items.POCKET_COMPUTER_NORMAL.get(), context.holders());
|
||||||
addPocket(out, Items.POCKET_COMPUTER_ADVANCED.get());
|
addPocket(out, Items.POCKET_COMPUTER_ADVANCED.get(), context.holders());
|
||||||
|
|
||||||
out.accept(Items.WIRELESS_MODEM_NORMAL.get());
|
out.accept(Items.WIRELESS_MODEM_NORMAL.get());
|
||||||
out.accept(Items.WIRELESS_MODEM_ADVANCED.get());
|
out.accept(Items.WIRELESS_MODEM_ADVANCED.get());
|
||||||
@ -562,8 +573,8 @@ public final class ModRegistry {
|
|||||||
BlockEntities.REGISTRY.register();
|
BlockEntities.REGISTRY.register();
|
||||||
Items.REGISTRY.register();
|
Items.REGISTRY.register();
|
||||||
DataComponents.REGISTRY.register();
|
DataComponents.REGISTRY.register();
|
||||||
TurtleSerialisers.REGISTRY.register();
|
TurtleUpgradeTypes.REGISTRY.register();
|
||||||
PocketUpgradeSerialisers.REGISTRY.register();
|
PocketUpgradeTypes.REGISTRY.register();
|
||||||
Menus.REGISTRY.register();
|
Menus.REGISTRY.register();
|
||||||
ArgumentTypes.REGISTRY.register();
|
ArgumentTypes.REGISTRY.register();
|
||||||
LootItemConditionTypes.REGISTRY.register();
|
LootItemConditionTypes.REGISTRY.register();
|
||||||
@ -594,15 +605,23 @@ public final class ModRegistry {
|
|||||||
CauldronInteraction.WATER.map().put(Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
|
CauldronInteraction.WATER.map().put(Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
|
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle, HolderLookup.Provider registries) {
|
||||||
out.accept(new ItemStack(turtle));
|
out.accept(new ItemStack(turtle));
|
||||||
TurtleUpgrades.getVanillaUpgrades()
|
registries.lookupOrThrow(TURTLE_UPGRADE).listElements()
|
||||||
|
.filter(ModRegistry::isOurUpgrade)
|
||||||
.map(x -> DataComponentUtil.createStack(turtle, DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(x)))
|
.map(x -> DataComponentUtil.createStack(turtle, DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(x)))
|
||||||
.forEach(out::accept);
|
.forEach(out::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket) {
|
private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket, HolderLookup.Provider registries) {
|
||||||
out.accept(new ItemStack(pocket));
|
out.accept(new ItemStack(pocket));
|
||||||
PocketUpgrades.getVanillaUpgrades().map(x -> DataComponentUtil.createStack(pocket, DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(x))).forEach(out::accept);
|
registries.lookupOrThrow(POCKET_UPGRADE).listElements()
|
||||||
|
.filter(ModRegistry::isOurUpgrade)
|
||||||
|
.map(x -> DataComponentUtil.createStack(pocket, DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(x))).forEach(out::accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isOurUpgrade(Holder.Reference<? extends UpgradeBase> upgrade) {
|
||||||
|
var namespace = upgrade.key().location().getNamespace();
|
||||||
|
return namespace.equals("minecraft") || namespace.equals(ComputerCraftAPI.MOD_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,23 @@ package dan200.computercraft.shared.integration;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for recipe mod plugins (such as JEI).
|
* Utilities for recipe mod plugins (such as JEI).
|
||||||
@ -48,24 +53,41 @@ public final class RecipeModHelpers {
|
|||||||
* Get additional ComputerCraft-related items which may not be visible in a creative tab. This includes upgraded
|
* Get additional ComputerCraft-related items which may not be visible in a creative tab. This includes upgraded
|
||||||
* turtle and pocket computers for each upgrade.
|
* turtle and pocket computers for each upgrade.
|
||||||
*
|
*
|
||||||
|
* @param registries The currently available registries.
|
||||||
* @return The additional stacks to show.
|
* @return The additional stacks to show.
|
||||||
*/
|
*/
|
||||||
public static List<ItemStack> getExtraStacks() {
|
public static List<ItemStack> getExtraStacks(HolderLookup.Provider registries) {
|
||||||
List<ItemStack> upgradeItems = new ArrayList<>();
|
List<ItemStack> upgradeItems = new ArrayList<>();
|
||||||
for (var turtleSupplier : TURTLES) {
|
for (var turtleSupplier : TURTLES) {
|
||||||
var turtle = turtleSupplier.get();
|
var turtle = turtleSupplier.get();
|
||||||
for (var upgrade : TurtleUpgrades.instance().getUpgrades()) {
|
forEachRegistry(registries, ModRegistry.TURTLE_UPGRADE, upgrade ->
|
||||||
upgradeItems.add(DataComponentUtil.createStack(turtle, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade)));
|
upgradeItems.add(DataComponentUtil.createStack(turtle, ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get(), UpgradeData.ofDefault(upgrade)))
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var pocketSupplier : POCKET_COMPUTERS) {
|
for (var pocketSupplier : POCKET_COMPUTERS) {
|
||||||
var pocket = pocketSupplier.get();
|
var pocket = pocketSupplier.get();
|
||||||
for (var upgrade : PocketUpgrades.instance().getUpgrades()) {
|
forEachRegistry(registries, ModRegistry.POCKET_UPGRADE, upgrade ->
|
||||||
upgradeItems.add(DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade)));
|
upgradeItems.add(DataComponentUtil.createStack(pocket, ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade)))
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return upgradeItems;
|
return upgradeItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary function to denote places where we need a {@link HolderLookup.Provider} within our recipe mods, but
|
||||||
|
* don't have access to one.
|
||||||
|
*
|
||||||
|
* @return The empty recipe mod access.
|
||||||
|
* @deprecated We should get the registry access from a more sensible place.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static HolderLookup.Provider getEmptyRegistryAccess() {
|
||||||
|
return RegistryAccess.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void forEachRegistry(HolderLookup.Provider registries, ResourceKey<Registry<T>> registry, Consumer<Holder.Reference<T>> consumer) {
|
||||||
|
registries.lookup(registry).map(HolderLookup::listElements).orElse(Stream.empty()).forEach(consumer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@ -27,8 +27,7 @@ import javax.annotation.Nullable;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.integration.RecipeModHelpers.POCKET_COMPUTERS;
|
import static dan200.computercraft.shared.integration.RecipeModHelpers.*;
|
||||||
import static dan200.computercraft.shared.integration.RecipeModHelpers.TURTLES;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides dynamic recipe and usage information for upgraded turtle and pocket computers. This is intended to be
|
* Provides dynamic recipe and usage information for upgraded turtle and pocket computers. This is intended to be
|
||||||
@ -39,14 +38,16 @@ import static dan200.computercraft.shared.integration.RecipeModHelpers.TURTLES;
|
|||||||
*/
|
*/
|
||||||
public class UpgradeRecipeGenerator<T> {
|
public class UpgradeRecipeGenerator<T> {
|
||||||
private final Function<ShapedRecipe, T> wrap;
|
private final Function<ShapedRecipe, T> wrap;
|
||||||
|
private final HolderLookup.Provider registries;
|
||||||
|
|
||||||
private final Map<Item, List<UpgradeInfo>> upgradeItemLookup = new HashMap<>();
|
private final Map<Item, List<UpgradeInfo>> upgradeItemLookup = new HashMap<>();
|
||||||
private final List<UpgradeInfo> pocketUpgrades = new ArrayList<>();
|
private final List<UpgradeInfo> pocketUpgrades = new ArrayList<>();
|
||||||
private final List<UpgradeInfo> turtleUpgrades = new ArrayList<>();
|
private final List<UpgradeInfo> turtleUpgrades = new ArrayList<>();
|
||||||
private boolean initialised = false;
|
private boolean initialised = false;
|
||||||
|
|
||||||
public UpgradeRecipeGenerator(Function<ShapedRecipe, T> wrap) {
|
public UpgradeRecipeGenerator(Function<ShapedRecipe, T> wrap, HolderLookup.Provider registries) {
|
||||||
this.wrap = wrap;
|
this.wrap = wrap;
|
||||||
|
this.registries = registries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,23 +57,25 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
if (initialised) return;
|
if (initialised) return;
|
||||||
initialised = true;
|
initialised = true;
|
||||||
|
|
||||||
for (var upgrade : TurtleUpgrades.instance().getUpgrades()) {
|
forEachRegistry(registries, ModRegistry.TURTLE_UPGRADE, holder -> {
|
||||||
|
var upgrade = holder.value();
|
||||||
var stack = upgrade.getCraftingItem();
|
var stack = upgrade.getCraftingItem();
|
||||||
if (stack.isEmpty()) return;
|
if (stack.isEmpty()) return;
|
||||||
|
|
||||||
var info = new UpgradeInfo(stack, upgrade);
|
var info = new UpgradeInfo(stack, upgrade, holder, null);
|
||||||
upgradeItemLookup.computeIfAbsent(stack.getItem(), k -> new ArrayList<>(1)).add(info);
|
upgradeItemLookup.computeIfAbsent(stack.getItem(), k -> new ArrayList<>(1)).add(info);
|
||||||
turtleUpgrades.add(info);
|
turtleUpgrades.add(info);
|
||||||
}
|
});
|
||||||
|
|
||||||
for (var upgrade : PocketUpgrades.instance().getUpgrades()) {
|
forEachRegistry(registries, ModRegistry.POCKET_UPGRADE, holder -> {
|
||||||
|
var upgrade = holder.value();
|
||||||
var stack = upgrade.getCraftingItem();
|
var stack = upgrade.getCraftingItem();
|
||||||
if (stack.isEmpty()) return;
|
if (stack.isEmpty()) return;
|
||||||
|
|
||||||
var info = new UpgradeInfo(stack, upgrade);
|
var info = new UpgradeInfo(stack, upgrade, null, holder);
|
||||||
upgradeItemLookup.computeIfAbsent(stack.getItem(), k -> new ArrayList<>(1)).add(info);
|
upgradeItemLookup.computeIfAbsent(stack.getItem(), k -> new ArrayList<>(1)).add(info);
|
||||||
pocketUpgrades.add(info);
|
pocketUpgrades.add(info);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,23 +251,17 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
private class UpgradeInfo {
|
private class UpgradeInfo {
|
||||||
final ItemStack stack;
|
final ItemStack stack;
|
||||||
final Ingredient ingredient;
|
final Ingredient ingredient;
|
||||||
final @Nullable ITurtleUpgrade turtle;
|
final @Nullable Holder.Reference<ITurtleUpgrade> turtle;
|
||||||
final @Nullable IPocketUpgrade pocket;
|
final @Nullable Holder.Reference<IPocketUpgrade> pocket;
|
||||||
final UpgradeBase upgrade;
|
final UpgradeBase upgrade;
|
||||||
private @Nullable ArrayList<T> recipes;
|
private @Nullable ArrayList<T> recipes;
|
||||||
|
|
||||||
UpgradeInfo(ItemStack stack, ITurtleUpgrade turtle) {
|
UpgradeInfo(ItemStack stack, UpgradeBase upgrade, @Nullable Holder.Reference<ITurtleUpgrade> turtle, @Nullable Holder.Reference<IPocketUpgrade> pocket) {
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
ingredient = Ingredient.of(stack);
|
ingredient = Ingredient.of(stack);
|
||||||
upgrade = this.turtle = turtle;
|
this.turtle = turtle;
|
||||||
pocket = null;
|
this.pocket = pocket;
|
||||||
}
|
this.upgrade = upgrade;
|
||||||
|
|
||||||
UpgradeInfo(ItemStack stack, IPocketUpgrade pocket) {
|
|
||||||
this.stack = stack;
|
|
||||||
ingredient = Ingredient.of(stack);
|
|
||||||
turtle = null;
|
|
||||||
upgrade = this.pocket = pocket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> getRecipes() {
|
List<T> getRecipes() {
|
||||||
|
@ -52,7 +52,7 @@ public class JEIComputerCraft implements IModPlugin {
|
|||||||
var registry = runtime.getRecipeManager();
|
var registry = runtime.getRecipeManager();
|
||||||
|
|
||||||
// Register all turtles/pocket computers (not just vanilla upgrades) as upgrades on JEI.
|
// Register all turtles/pocket computers (not just vanilla upgrades) as upgrades on JEI.
|
||||||
var upgradeItems = RecipeModHelpers.getExtraStacks();
|
var upgradeItems = RecipeModHelpers.getExtraStacks(RecipeModHelpers.getEmptyRegistryAccess());
|
||||||
if (!upgradeItems.isEmpty()) {
|
if (!upgradeItems.isEmpty()) {
|
||||||
runtime.getIngredientManager().addIngredientsAtRuntime(VanillaTypes.ITEM_STACK, upgradeItems);
|
runtime.getIngredientManager().addIngredientsAtRuntime(VanillaTypes.ITEM_STACK, upgradeItems);
|
||||||
}
|
}
|
||||||
@ -73,11 +73,11 @@ public class JEIComputerCraft implements IModPlugin {
|
|||||||
var name = new StringBuilder("turtle:");
|
var name = new StringBuilder("turtle:");
|
||||||
|
|
||||||
// Add left and right upgrades to the identifier
|
// Add left and right upgrades to the identifier
|
||||||
var left = TurtleItem.getUpgrade(stack, TurtleSide.LEFT);
|
var left = TurtleItem.getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
var right = TurtleItem.getUpgrade(stack, TurtleSide.RIGHT);
|
var right = TurtleItem.getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
if (left != null) name.append(left.getUpgradeID());
|
if (left != null) name.append(left.holder().key().location());
|
||||||
if (left != null && right != null) name.append('|');
|
if (left != null && right != null) name.append('|');
|
||||||
if (right != null) name.append(right.getUpgradeID());
|
if (right != null) name.append(right.holder().key().location());
|
||||||
|
|
||||||
return name.toString();
|
return name.toString();
|
||||||
};
|
};
|
||||||
@ -89,8 +89,8 @@ public class JEIComputerCraft implements IModPlugin {
|
|||||||
var name = new StringBuilder("pocket:");
|
var name = new StringBuilder("pocket:");
|
||||||
|
|
||||||
// Add the upgrade to the identifier
|
// Add the upgrade to the identifier
|
||||||
var upgrade = PocketComputerItem.getUpgrade(stack);
|
var upgrade = PocketComputerItem.getUpgradeWithData(stack);
|
||||||
if (upgrade != null) name.append(upgrade.getUpgradeID());
|
if (upgrade != null) name.append(upgrade.holder().key().location());
|
||||||
|
|
||||||
return name.toString();
|
return name.toString();
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package dan200.computercraft.shared.integration.jei;
|
package dan200.computercraft.shared.integration.jei;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.shared.integration.RecipeModHelpers;
|
||||||
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
@ -22,7 +23,7 @@ import java.util.List;
|
|||||||
|
|
||||||
class RecipeResolver implements IRecipeManagerPlugin {
|
class RecipeResolver implements IRecipeManagerPlugin {
|
||||||
private static final ResourceLocation RECIPE_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "upgrade");
|
private static final ResourceLocation RECIPE_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "upgrade");
|
||||||
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver = new UpgradeRecipeGenerator<>(x -> new RecipeHolder<>(RECIPE_ID, x));
|
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver = new UpgradeRecipeGenerator<>(x -> new RecipeHolder<>(RECIPE_ID, x), RecipeModHelpers.getEmptyRegistryAccess());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> List<RecipeType<?>> getRecipeTypes(IFocus<V> focus) {
|
public <V> List<RecipeType<?>> getRecipeTypes(IFocus<V> focus) {
|
||||||
|
@ -42,7 +42,6 @@ public final class NetworkMessages {
|
|||||||
public static final CustomPacketPayload.Type<SpeakerPlayClientMessage> SPEAKER_PLAY = registerClientbound("speaker_play", SpeakerPlayClientMessage.STREAM_CODEC);
|
public static final CustomPacketPayload.Type<SpeakerPlayClientMessage> SPEAKER_PLAY = registerClientbound("speaker_play", SpeakerPlayClientMessage.STREAM_CODEC);
|
||||||
public static final CustomPacketPayload.Type<SpeakerStopClientMessage> SPEAKER_STOP = registerClientbound("speaker_stop", SpeakerStopClientMessage.STREAM_CODEC);
|
public static final CustomPacketPayload.Type<SpeakerStopClientMessage> SPEAKER_STOP = registerClientbound("speaker_stop", SpeakerStopClientMessage.STREAM_CODEC);
|
||||||
public static final CustomPacketPayload.Type<UploadResultMessage> UPLOAD_RESULT = registerClientbound("upload_result", UploadResultMessage.STREAM_CODEC);
|
public static final CustomPacketPayload.Type<UploadResultMessage> UPLOAD_RESULT = registerClientbound("upload_result", UploadResultMessage.STREAM_CODEC);
|
||||||
public static final CustomPacketPayload.Type<UpgradesLoadedMessage> UPGRADES_LOADED = registerClientbound("upgrades_loaded", UpgradesLoadedMessage.STREAM_CODEC);
|
|
||||||
|
|
||||||
private NetworkMessages() {
|
private NetworkMessages() {
|
||||||
}
|
}
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.shared.network.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
|
||||||
import dan200.computercraft.impl.RegistryHelper;
|
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
|
||||||
import dan200.computercraft.impl.UpgradeManager;
|
|
||||||
import dan200.computercraft.shared.network.NetworkMessage;
|
|
||||||
import dan200.computercraft.shared.network.NetworkMessages;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syncs turtle and pocket upgrades to the client.
|
|
||||||
*/
|
|
||||||
public final class UpgradesLoadedMessage implements NetworkMessage<ClientNetworkContext> {
|
|
||||||
public static final StreamCodec<RegistryFriendlyByteBuf, UpgradesLoadedMessage> STREAM_CODEC = StreamCodec.ofMember(UpgradesLoadedMessage::write, UpgradesLoadedMessage::new);
|
|
||||||
|
|
||||||
private final Map<ResourceLocation, UpgradeManager.UpgradeWrapper<ITurtleUpgrade>> turtleUpgrades;
|
|
||||||
private final Map<ResourceLocation, UpgradeManager.UpgradeWrapper<IPocketUpgrade>> pocketUpgrades;
|
|
||||||
|
|
||||||
public UpgradesLoadedMessage() {
|
|
||||||
turtleUpgrades = TurtleUpgrades.instance().getUpgradeWrappers();
|
|
||||||
pocketUpgrades = PocketUpgrades.instance().getUpgradeWrappers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private UpgradesLoadedMessage(RegistryFriendlyByteBuf buf) {
|
|
||||||
turtleUpgrades = fromBytes(buf, ITurtleUpgrade.serialiserRegistryKey());
|
|
||||||
pocketUpgrades = fromBytes(buf, IPocketUpgrade.serialiserRegistryKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends UpgradeBase> Map<ResourceLocation, UpgradeManager.UpgradeWrapper<T>> fromBytes(
|
|
||||||
RegistryFriendlyByteBuf buf, ResourceKey<Registry<UpgradeSerialiser<? extends T>>> registryKey
|
|
||||||
) {
|
|
||||||
var registry = RegistryHelper.getRegistry(registryKey);
|
|
||||||
|
|
||||||
var size = buf.readVarInt();
|
|
||||||
Map<ResourceLocation, UpgradeManager.UpgradeWrapper<T>> upgrades = new HashMap<>(size);
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
var id = buf.readResourceLocation();
|
|
||||||
|
|
||||||
var serialiserId = buf.readResourceLocation();
|
|
||||||
var serialiser = registry.get(serialiserId);
|
|
||||||
if (serialiser == null) throw new IllegalStateException("Unknown serialiser " + serialiserId);
|
|
||||||
|
|
||||||
var upgrade = serialiser.fromNetwork(id, buf);
|
|
||||||
var modId = buf.readUtf();
|
|
||||||
|
|
||||||
upgrades.put(id, new UpgradeManager.UpgradeWrapper<T>(id, upgrade, serialiser, modId));
|
|
||||||
}
|
|
||||||
|
|
||||||
return upgrades;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void write(RegistryFriendlyByteBuf buf) {
|
|
||||||
toBytes(buf, ITurtleUpgrade.serialiserRegistryKey(), turtleUpgrades);
|
|
||||||
toBytes(buf, IPocketUpgrade.serialiserRegistryKey(), pocketUpgrades);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends UpgradeBase> void toBytes(
|
|
||||||
RegistryFriendlyByteBuf buf, ResourceKey<Registry<UpgradeSerialiser<? extends T>>> registryKey, Map<ResourceLocation, UpgradeManager.UpgradeWrapper<T>> upgrades
|
|
||||||
) {
|
|
||||||
var registry = RegistryHelper.getRegistry(registryKey);
|
|
||||||
|
|
||||||
buf.writeVarInt(upgrades.size());
|
|
||||||
for (var entry : upgrades.entrySet()) {
|
|
||||||
buf.writeResourceLocation(entry.getKey());
|
|
||||||
|
|
||||||
var serialiser = entry.getValue().serialiser();
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
var unwrappedSerialiser = (UpgradeSerialiser<T>) serialiser;
|
|
||||||
|
|
||||||
buf.writeResourceLocation(RegistryHelper.getKeyOrThrow(registry, serialiser));
|
|
||||||
unwrappedSerialiser.toNetwork(buf, entry.getValue().upgrade());
|
|
||||||
|
|
||||||
buf.writeUtf(entry.getValue().modId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(ClientNetworkContext context) {
|
|
||||||
TurtleUpgrades.instance().loadFromNetwork(turtleUpgrades);
|
|
||||||
PocketUpgrades.instance().loadFromNetwork(pocketUpgrades);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CustomPacketPayload.Type<UpgradesLoadedMessage> type() {
|
|
||||||
return NetworkMessages.UPGRADES_LOADED;
|
|
||||||
}
|
|
||||||
}
|
|
@ -107,11 +107,11 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable UpgradeData<IPocketUpgrade> findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
private @Nullable UpgradeData<IPocketUpgrade> findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
||||||
for (var i = 0; i < inv.size(); i++) {
|
for (var i = 0; i < inv.size(); i++) {
|
||||||
var invStack = inv.get((i + start) % inv.size());
|
var invStack = inv.get((i + start) % inv.size());
|
||||||
if (!invStack.isEmpty()) {
|
if (!invStack.isEmpty()) {
|
||||||
var newUpgrade = PocketUpgrades.instance().get(invStack);
|
var newUpgrade = PocketUpgrades.instance().get(computer.getLevel().registryAccess(), invStack);
|
||||||
|
|
||||||
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
||||||
// Consume an item from this stack and exit the loop
|
// Consume an item from this stack and exit the loop
|
||||||
|
@ -100,10 +100,10 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUpgradeData(DataComponentPatch data) {
|
public void setUpgradeData(DataComponentPatch data) {
|
||||||
var upgrade = PocketComputerItem.getUpgrade(stack);
|
var upgrade = PocketComputerItem.getUpgradeWithData(stack);
|
||||||
if (upgrade == null) return;
|
if (upgrade == null) return;
|
||||||
|
|
||||||
PocketComputerItem.setUpgrade(stack, new UpgradeData<>(upgrade, data));
|
PocketComputerItem.setUpgrade(stack, new UpgradeData<>(upgrade.holder(), data));
|
||||||
setItemChanged();
|
setItemChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable UpgradeData<IPocketUpgrade> getUpgrade() {
|
public @Nullable UpgradeData<IPocketUpgrade> getUpgrade() {
|
||||||
return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeData());
|
return PocketComputerItem.getUpgradeWithData(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,15 +150,9 @@ public class PocketComputerItem extends Item implements IMedia {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@ForgeOverride
|
@ForgeOverride
|
||||||
public String getCreatorModId(ItemStack stack) {
|
public String getCreatorModId(ItemStack stack) {
|
||||||
var upgrade = getUpgrade(stack);
|
var upgrade = getUpgradeWithData(stack);
|
||||||
if (upgrade != null) {
|
return upgrade != null ? PocketUpgrades.instance().getOwner(upgrade.holder()) : ComputerCraftAPI.MOD_ID;
|
||||||
// If we're a non-vanilla, non-CC upgrade then return whichever mod this upgrade
|
|
||||||
// belongs to.
|
|
||||||
var mod = PocketUpgrades.instance().getOwner(upgrade);
|
|
||||||
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ComputerCraftAPI.MOD_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PocketServerComputer createServerComputer(ServerLevel level, Entity entity, @Nullable Container inventory, ItemStack stack) {
|
public PocketServerComputer createServerComputer(ServerLevel level, Entity entity, @Nullable Container inventory, ItemStack stack) {
|
||||||
|
@ -7,8 +7,9 @@ package dan200.computercraft.shared.pocket.peripherals;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.pocket.AbstractPocketUpgrade;
|
import dan200.computercraft.api.pocket.AbstractPocketUpgrade;
|
||||||
import dan200.computercraft.api.pocket.IPocketAccess;
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -16,8 +17,8 @@ import javax.annotation.Nullable;
|
|||||||
public class PocketModem extends AbstractPocketUpgrade {
|
public class PocketModem extends AbstractPocketUpgrade {
|
||||||
private final boolean advanced;
|
private final boolean advanced;
|
||||||
|
|
||||||
public PocketModem(ResourceLocation id, ItemStack stack, boolean advanced) {
|
public PocketModem(ItemStack stack, boolean advanced) {
|
||||||
super(id, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack);
|
super(advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack);
|
||||||
this.advanced = advanced;
|
this.advanced = advanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,4 +37,11 @@ public class PocketModem extends AbstractPocketUpgrade {
|
|||||||
var state = modem.getModemState();
|
var state = modem.getModemState();
|
||||||
if (state.pollChanged()) access.setLight(state.isOpen() ? 0xBA0000 : -1);
|
if (state.pollChanged()) access.setLight(state.isOpen() ? 0xBA0000 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<PocketModem> getType() {
|
||||||
|
return advanced
|
||||||
|
? ModRegistry.PocketUpgradeTypes.WIRELESS_MODEM_ADVANCED.get()
|
||||||
|
: ModRegistry.PocketUpgradeTypes.WIRELESS_MODEM_NORMAL.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,16 @@ package dan200.computercraft.shared.pocket.peripherals;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.pocket.AbstractPocketUpgrade;
|
import dan200.computercraft.api.pocket.AbstractPocketUpgrade;
|
||||||
import dan200.computercraft.api.pocket.IPocketAccess;
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PocketSpeaker extends AbstractPocketUpgrade {
|
public class PocketSpeaker extends AbstractPocketUpgrade {
|
||||||
public PocketSpeaker(ResourceLocation id, ItemStack item) {
|
public PocketSpeaker(ItemStack item) {
|
||||||
super(id, UpgradeSpeakerPeripheral.ADJECTIVE, item);
|
super(UpgradeSpeakerPeripheral.ADJECTIVE, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -29,4 +30,9 @@ public class PocketSpeaker extends AbstractPocketUpgrade {
|
|||||||
if (!(peripheral instanceof PocketSpeakerPeripheral)) return;
|
if (!(peripheral instanceof PocketSpeakerPeripheral)) return;
|
||||||
((PocketSpeakerPeripheral) peripheral).update();
|
((PocketSpeakerPeripheral) peripheral).update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<PocketSpeaker> getType() {
|
||||||
|
return ModRegistry.PocketUpgradeTypes.SPEAKER.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public final class PocketComputerUpgradeRecipe extends CustomRecipe {
|
|||||||
if (computer.isEmpty()) return ItemStack.EMPTY;
|
if (computer.isEmpty()) return ItemStack.EMPTY;
|
||||||
|
|
||||||
var itemComputer = (PocketComputerItem) computer.getItem();
|
var itemComputer = (PocketComputerItem) computer.getItem();
|
||||||
if (PocketComputerItem.getUpgrade(computer) != null) return ItemStack.EMPTY;
|
if (PocketComputerItem.getUpgradeWithData(computer) != null) return ItemStack.EMPTY;
|
||||||
|
|
||||||
// Check for upgrades around the item
|
// Check for upgrades around the item
|
||||||
UpgradeData<IPocketUpgrade> upgrade = null;
|
UpgradeData<IPocketUpgrade> upgrade = null;
|
||||||
@ -69,7 +69,7 @@ public final class PocketComputerUpgradeRecipe extends CustomRecipe {
|
|||||||
if (x == computerX && y == computerY) continue;
|
if (x == computerX && y == computerY) continue;
|
||||||
|
|
||||||
if (x == computerX && y == computerY - 1) {
|
if (x == computerX && y == computerY - 1) {
|
||||||
upgrade = PocketUpgrades.instance().get(item);
|
upgrade = PocketUpgrades.instance().get(registryAccess, item);
|
||||||
if (upgrade == null) return ItemStack.EMPTY;
|
if (upgrade == null) return ItemStack.EMPTY;
|
||||||
} else if (!item.isEmpty()) {
|
} else if (!item.isEmpty()) {
|
||||||
return ItemStack.EMPTY;
|
return ItemStack.EMPTY;
|
||||||
|
@ -7,9 +7,9 @@ package dan200.computercraft.shared.recipe.function;
|
|||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.impl.RegistryHelper;
|
|
||||||
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
||||||
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
||||||
|
import dan200.computercraft.shared.util.SafeDispatchCodec;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
@ -44,7 +44,7 @@ public interface RecipeFunction {
|
|||||||
/**
|
/**
|
||||||
* The codec to read and write {@link RecipeFunction}s with.
|
* The codec to read and write {@link RecipeFunction}s with.
|
||||||
*/
|
*/
|
||||||
Codec<RecipeFunction> CODEC = Codec.lazyInitialized(() -> RegistryHelper.getRegistry(REGISTRY).byNameCodec().dispatch(RecipeFunction::getType, Type::codec));
|
Codec<RecipeFunction> CODEC = SafeDispatchCodec.ofRegistry(REGISTRY, RecipeFunction::getType, Type::codec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A codec for a list of functions.
|
* A codec for a list of functions.
|
||||||
|
@ -180,7 +180,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable UpgradeData<ITurtleUpgrade> withPersistedData(@Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
private static @Nullable UpgradeData<ITurtleUpgrade> withPersistedData(@Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.upgrade().getPersistedData(upgrade.data()));
|
return upgrade == null ? null : UpgradeData.of(upgrade.holder(), upgrade.upgrade().getPersistedData(upgrade.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -313,7 +313,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return upgrade != null && upgrade.getType().isPeripheral();
|
return upgrade != null && upgrade.getUpgradeType().isPeripheral();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void transferStateFrom(TurtleBlockEntity copy) {
|
public void transferStateFrom(TurtleBlockEntity copy) {
|
||||||
|
@ -26,6 +26,7 @@ import dan200.computercraft.shared.util.Holiday;
|
|||||||
import dan200.computercraft.shared.util.NBTUtil;
|
import dan200.computercraft.shared.util.NBTUtil;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
@ -119,7 +120,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
// Advance upgrades
|
// Advance upgrades
|
||||||
for (var side : TurtleSide.values()) {
|
for (var side : TurtleSide.values()) {
|
||||||
var upgrade = upgrades[side.ordinal()].upgrade;
|
var upgrade = upgrades[side.ordinal()].upgrade;
|
||||||
if (upgrade != null) upgrade.update(this, side);
|
if (upgrade != null) upgrade.value().update(this, side);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +137,8 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
overlay = nbt.contains(NBT_OVERLAY) ? new ResourceLocation(nbt.getString(NBT_OVERLAY)) : null;
|
overlay = nbt.contains(NBT_OVERLAY) ? new ResourceLocation(nbt.getString(NBT_OVERLAY)) : null;
|
||||||
|
|
||||||
// Read upgrades
|
// Read upgrades
|
||||||
setUpgradeDirect(TurtleSide.LEFT, NBTUtil.decodeFrom(TurtleUpgrades.instance().codec(), registries, nbt, NBT_LEFT_UPGRADE));
|
setUpgradeDirect(TurtleSide.LEFT, NBTUtil.decodeFrom(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE));
|
||||||
setUpgradeDirect(TurtleSide.RIGHT, NBTUtil.decodeFrom(TurtleUpgrades.instance().codec(), registries, nbt, NBT_RIGHT_UPGRADE));
|
setUpgradeDirect(TurtleSide.RIGHT, NBTUtil.decodeFrom(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_RIGHT_UPGRADE));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
@ -146,8 +147,8 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
if (overlay != null) nbt.putString(NBT_OVERLAY, overlay.toString());
|
if (overlay != null) nbt.putString(NBT_OVERLAY, overlay.toString());
|
||||||
|
|
||||||
// Write upgrades
|
// Write upgrades
|
||||||
NBTUtil.encodeTo(TurtleUpgrades.instance().codec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
|
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
|
||||||
NBTUtil.encodeTo(TurtleUpgrades.instance().codec(), registries, nbt, NBT_RIGHT_UPGRADE, getUpgradeWithData(TurtleSide.RIGHT));
|
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_RIGHT_UPGRADE, getUpgradeWithData(TurtleSide.RIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFromNBT(CompoundTag nbt, HolderLookup.Provider registries) {
|
public void readFromNBT(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||||
@ -459,7 +460,8 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable ITurtleUpgrade getUpgrade(TurtleSide side) {
|
public @Nullable ITurtleUpgrade getUpgrade(TurtleSide side) {
|
||||||
return upgrades[side.ordinal()].upgrade;
|
var upgrade = upgrades[side.ordinal()].upgrade;
|
||||||
|
return upgrade == null ? null : upgrade.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -561,7 +563,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
for (var side : TurtleSide.values()) {
|
for (var side : TurtleSide.values()) {
|
||||||
var upgrade = getUpgrade(side);
|
var upgrade = getUpgrade(side);
|
||||||
IPeripheral peripheral = null;
|
IPeripheral peripheral = null;
|
||||||
if (upgrade != null && upgrade.getType().isPeripheral()) {
|
if (upgrade != null && upgrade.getUpgradeType().isPeripheral()) {
|
||||||
peripheral = upgrade.createPeripheral(this, side);
|
peripheral = upgrade.createPeripheral(this, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +749,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class UpgradeInstance {
|
private static final class UpgradeInstance {
|
||||||
private @Nullable ITurtleUpgrade upgrade;
|
private @Nullable Holder.Reference<ITurtleUpgrade> upgrade;
|
||||||
private DataComponentPatch data = DataComponentPatch.EMPTY;
|
private DataComponentPatch data = DataComponentPatch.EMPTY;
|
||||||
private @Nullable IPeripheral peripheral;
|
private @Nullable IPeripheral peripheral;
|
||||||
|
|
||||||
@ -759,7 +761,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
data = DataComponentPatch.EMPTY;
|
data = DataComponentPatch.EMPTY;
|
||||||
cachedUpgradeData = null;
|
cachedUpgradeData = null;
|
||||||
} else {
|
} else {
|
||||||
this.upgrade = upgrade.upgrade();
|
this.upgrade = upgrade.holder();
|
||||||
this.data = upgrade.data();
|
this.data = upgrade.data();
|
||||||
this.cachedUpgradeData = upgrade;
|
this.cachedUpgradeData = upgrade;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class TurtleEquipCommand implements TurtleCommand {
|
|||||||
UpgradeData<ITurtleUpgrade> newUpgrade;
|
UpgradeData<ITurtleUpgrade> newUpgrade;
|
||||||
var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot());
|
var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot());
|
||||||
if (!selectedStack.isEmpty()) {
|
if (!selectedStack.isEmpty()) {
|
||||||
newUpgrade = TurtleUpgrades.instance().get(selectedStack);
|
newUpgrade = TurtleUpgrades.instance().get(turtle.getLevel().registryAccess(), selectedStack);
|
||||||
if (newUpgrade == null) return TurtleCommandResult.failure("Not a valid upgrade");
|
if (newUpgrade == null) return TurtleCommandResult.failure("Not a valid upgrade");
|
||||||
} else {
|
} else {
|
||||||
newUpgrade = null;
|
newUpgrade = null;
|
||||||
|
@ -27,7 +27,7 @@ public class TurtleToolCommand implements TurtleCommand {
|
|||||||
if (this.side != null && this.side != side) continue;
|
if (this.side != null && this.side != side) continue;
|
||||||
|
|
||||||
var upgrade = turtle.getUpgrade(side);
|
var upgrade = turtle.getUpgrade(side);
|
||||||
if (upgrade == null || !upgrade.getType().isTool()) continue;
|
if (upgrade == null || !upgrade.getUpgradeType().isTool()) continue;
|
||||||
|
|
||||||
var result = upgrade.useTool(turtle, side, verb, direction.toWorldDir(turtle));
|
var result = upgrade.useTool(turtle, side, verb, direction.toWorldDir(turtle));
|
||||||
if (result.isSuccess()) {
|
if (result.isSuccess()) {
|
||||||
|
@ -62,8 +62,9 @@ public final class TurtleMenu extends AbstractComputerMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Turtle upgrades
|
// Turtle upgrades
|
||||||
addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.LEFT, 0, UPGRADE_START_X, PLAYER_START_Y + 1));
|
var registries = playerInventory.player.level().registryAccess();
|
||||||
addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.RIGHT, 1, UPGRADE_START_X, PLAYER_START_Y + 1 + 18));
|
addSlot(new UpgradeSlot(turtleUpgrades, registries, TurtleSide.LEFT, 0, UPGRADE_START_X, PLAYER_START_Y + 1));
|
||||||
|
addSlot(new UpgradeSlot(turtleUpgrades, registries, TurtleSide.RIGHT, 1, UPGRADE_START_X, PLAYER_START_Y + 1 + 18));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TurtleMenu ofBrain(int id, Inventory player, TurtleBrain turtle) {
|
public static TurtleMenu ofBrain(int id, Inventory player, TurtleBrain turtle) {
|
||||||
|
@ -66,7 +66,7 @@ class UpgradeContainer implements Container {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setItem(int slot, ItemStack itemStack) {
|
public void setItem(int slot, ItemStack itemStack) {
|
||||||
var upgrade = TurtleUpgrades.instance().get(itemStack);
|
var upgrade = TurtleUpgrades.instance().get(turtle.getLevel().registryAccess(), itemStack);
|
||||||
turtle.setUpgrade(getSide(slot), upgrade);
|
turtle.setUpgrade(getSide(slot), upgrade);
|
||||||
setUpgradeStack(slot, upgrade);
|
setUpgradeStack(slot, upgrade);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import com.mojang.datafixers.util.Pair;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.inventory.InventoryMenu;
|
import net.minecraft.world.inventory.InventoryMenu;
|
||||||
@ -25,16 +26,18 @@ public class UpgradeSlot extends Slot {
|
|||||||
public static final ResourceLocation LEFT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_left");
|
public static final ResourceLocation LEFT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_left");
|
||||||
public static final ResourceLocation RIGHT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_right");
|
public static final ResourceLocation RIGHT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_right");
|
||||||
|
|
||||||
|
private final HolderLookup.Provider registries;
|
||||||
private final TurtleSide side;
|
private final TurtleSide side;
|
||||||
|
|
||||||
public UpgradeSlot(Container container, TurtleSide side, int slot, int xPos, int yPos) {
|
public UpgradeSlot(Container container, HolderLookup.Provider registries, TurtleSide side, int slot, int xPos, int yPos) {
|
||||||
super(container, slot, xPos, yPos);
|
super(container, slot, xPos, yPos);
|
||||||
|
this.registries = registries;
|
||||||
this.side = side;
|
this.side = side;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mayPlace(ItemStack stack) {
|
public boolean mayPlace(ItemStack stack) {
|
||||||
return TurtleUpgrades.instance().get(stack) != null;
|
return TurtleUpgrades.instance().get(registries, stack) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,16 +57,16 @@ public class TurtleItem extends AbstractComputerItem {
|
|||||||
// Determine our "creator mod" from the upgrades. We attempt to find the first non-vanilla/non-CC
|
// Determine our "creator mod" from the upgrades. We attempt to find the first non-vanilla/non-CC
|
||||||
// upgrade (starting from the left).
|
// upgrade (starting from the left).
|
||||||
|
|
||||||
var left = getUpgrade(stack, TurtleSide.LEFT);
|
var left = getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
if (left != null) {
|
if (left != null) {
|
||||||
var mod = TurtleUpgrades.instance().getOwner(left);
|
var mod = TurtleUpgrades.instance().getOwner(left.holder());
|
||||||
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
|
if (!mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
var right = getUpgrade(stack, TurtleSide.RIGHT);
|
var right = getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
var mod = TurtleUpgrades.instance().getOwner(right);
|
var mod = TurtleUpgrades.instance().getOwner(right.holder());
|
||||||
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
|
if (!mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ComputerCraftAPI.MOD_ID;
|
return ComputerCraftAPI.MOD_ID;
|
||||||
|
@ -113,7 +113,7 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
|
|||||||
var items = new ItemStack[]{ rightItem, leftItem };
|
var items = new ItemStack[]{ rightItem, leftItem };
|
||||||
for (var i = 0; i < 2; i++) {
|
for (var i = 0; i < 2; i++) {
|
||||||
if (!items[i].isEmpty()) {
|
if (!items[i].isEmpty()) {
|
||||||
var itemUpgrade = TurtleUpgrades.instance().get(items[i]);
|
var itemUpgrade = TurtleUpgrades.instance().get(registryAccess, items[i]);
|
||||||
if (itemUpgrade == null || upgrades[i] != null) return ItemStack.EMPTY;
|
if (itemUpgrade == null || upgrades[i] != null) return ItemStack.EMPTY;
|
||||||
upgrades[i] = itemUpgrade;
|
upgrades[i] = itemUpgrade;
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,23 @@ import dan200.computercraft.api.turtle.AbstractTurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
public class TurtleCraftingTable extends AbstractTurtleUpgrade {
|
public class TurtleCraftingTable extends AbstractTurtleUpgrade {
|
||||||
public TurtleCraftingTable(ResourceLocation id, ItemStack stack) {
|
public TurtleCraftingTable(ItemStack stack) {
|
||||||
super(id, TurtleUpgradeType.PERIPHERAL, "upgrade.minecraft.crafting_table.adjective", stack);
|
super(TurtleUpgradeType.PERIPHERAL, "upgrade.minecraft.crafting_table.adjective", stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPeripheral createPeripheral(ITurtleAccess turtle, TurtleSide side) {
|
public IPeripheral createPeripheral(ITurtleAccess turtle, TurtleSide side) {
|
||||||
return new CraftingTablePeripheral(turtle);
|
return new CraftingTablePeripheral(turtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<TurtleCraftingTable> getType() {
|
||||||
|
return ModRegistry.TurtleUpgradeTypes.WORKBENCH.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ package dan200.computercraft.shared.turtle.upgrades;
|
|||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.turtle.*;
|
import dan200.computercraft.api.turtle.*;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@ -50,8 +50,8 @@ public class TurtleModem extends AbstractTurtleUpgrade {
|
|||||||
|
|
||||||
private final boolean advanced;
|
private final boolean advanced;
|
||||||
|
|
||||||
public TurtleModem(ResourceLocation id, ItemStack stack, boolean advanced) {
|
public TurtleModem(ItemStack stack, boolean advanced) {
|
||||||
super(id, TurtleUpgradeType.PERIPHERAL, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack);
|
super(TurtleUpgradeType.PERIPHERAL, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack);
|
||||||
this.advanced = advanced;
|
this.advanced = advanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,4 +83,11 @@ public class TurtleModem extends AbstractTurtleUpgrade {
|
|||||||
public DataComponentPatch getPersistedData(DataComponentPatch upgradeData) {
|
public DataComponentPatch getPersistedData(DataComponentPatch upgradeData) {
|
||||||
return DataComponentPatch.EMPTY;
|
return DataComponentPatch.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<TurtleModem> getType() {
|
||||||
|
return advanced
|
||||||
|
? ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM_ADVANCED.get()
|
||||||
|
: ModRegistry.TurtleUpgradeTypes.WIRELESS_MODEM_NORMAL.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,10 @@ import dan200.computercraft.api.turtle.AbstractTurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
@ -36,8 +37,8 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TurtleSpeaker(ResourceLocation id, ItemStack item) {
|
public TurtleSpeaker(ItemStack item) {
|
||||||
super(id, TurtleUpgradeType.PERIPHERAL, UpgradeSpeakerPeripheral.ADJECTIVE, item);
|
super(TurtleUpgradeType.PERIPHERAL, UpgradeSpeakerPeripheral.ADJECTIVE, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -50,4 +51,9 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade {
|
|||||||
var peripheral = turtle.getPeripheral(turtleSide);
|
var peripheral = turtle.getPeripheral(turtleSide);
|
||||||
if (peripheral instanceof Peripheral speaker) speaker.update();
|
if (peripheral instanceof Peripheral speaker) speaker.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<TurtleSpeaker> getType() {
|
||||||
|
return ModRegistry.TurtleUpgradeTypes.SPEAKER.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,12 @@
|
|||||||
|
|
||||||
package dan200.computercraft.shared.turtle.upgrades;
|
package dan200.computercraft.shared.turtle.upgrades;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.ComputerCraftTags;
|
import dan200.computercraft.api.ComputerCraftTags;
|
||||||
import dan200.computercraft.api.turtle.*;
|
import dan200.computercraft.api.turtle.*;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
|
import dan200.computercraft.impl.upgrades.TurtleToolSpec;
|
||||||
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.turtle.TurtleUtil;
|
import dan200.computercraft.shared.turtle.TurtleUtil;
|
||||||
import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand;
|
import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand;
|
||||||
@ -16,7 +20,6 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
@ -27,7 +30,6 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
@ -41,25 +43,26 @@ import javax.annotation.Nullable;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class TurtleTool extends AbstractTurtleUpgrade {
|
public class TurtleTool extends AbstractTurtleUpgrade {
|
||||||
|
public static final MapCodec<TurtleTool> CODEC = TurtleToolSpec.CODEC.xmap(TurtleTool::new, x -> x.spec);
|
||||||
|
|
||||||
private static final TurtleCommandResult UNBREAKABLE = TurtleCommandResult.failure("Cannot break unbreakable block");
|
private static final TurtleCommandResult UNBREAKABLE = TurtleCommandResult.failure("Cannot break unbreakable block");
|
||||||
private static final TurtleCommandResult INEFFECTIVE = TurtleCommandResult.failure("Cannot break block with this tool");
|
private static final TurtleCommandResult INEFFECTIVE = TurtleCommandResult.failure("Cannot break block with this tool");
|
||||||
|
|
||||||
|
final TurtleToolSpec spec;
|
||||||
final ItemStack item;
|
final ItemStack item;
|
||||||
final float damageMulitiplier;
|
final float damageMulitiplier;
|
||||||
final boolean allowEnchantments;
|
final boolean allowEnchantments;
|
||||||
final TurtleToolDurability consumeDurability;
|
final TurtleToolDurability consumeDurability;
|
||||||
final @Nullable TagKey<Block> breakable;
|
final @Nullable TagKey<Block> breakable;
|
||||||
|
|
||||||
public TurtleTool(
|
public TurtleTool(TurtleToolSpec spec) {
|
||||||
ResourceLocation id, String adjective, Item craftItem, ItemStack toolItem, float damageMulitiplier,
|
super(TurtleUpgradeType.TOOL, spec.adjective(), new ItemStack(spec.craftItem().orElse(spec.toolItem())));
|
||||||
boolean allowEnchantments, TurtleToolDurability consumeDurability, @Nullable TagKey<Block> breakable
|
this.spec = spec;
|
||||||
) {
|
item = new ItemStack(spec.toolItem());
|
||||||
super(id, TurtleUpgradeType.TOOL, adjective, new ItemStack(craftItem));
|
this.damageMulitiplier = spec.damageMultiplier();
|
||||||
item = toolItem;
|
this.allowEnchantments = spec.allowEnchantments();
|
||||||
this.damageMulitiplier = damageMulitiplier;
|
this.consumeDurability = spec.consumeDurability();
|
||||||
this.allowEnchantments = allowEnchantments;
|
this.breakable = spec.breakable().orElse(null);
|
||||||
this.consumeDurability = consumeDurability;
|
|
||||||
this.breakable = breakable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -328,4 +331,9 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
// Allow breaking any "instabreak" block.
|
// Allow breaking any "instabreak" block.
|
||||||
|| state.getDestroySpeed(reader, pos) == 0;
|
|| state.getDestroySpeed(reader, pos) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpgradeType<TurtleTool> getType() {
|
||||||
|
return ModRegistry.TurtleUpgradeTypes.TOOL.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.shared.turtle.upgrades;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleToolDurability;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.tags.TagKey;
|
|
||||||
import net.minecraft.util.GsonHelper;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
|
|
||||||
public final class TurtleToolSerialiser implements UpgradeSerialiser<TurtleTool> {
|
|
||||||
public static final TurtleToolSerialiser INSTANCE = new TurtleToolSerialiser();
|
|
||||||
|
|
||||||
private TurtleToolSerialiser() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TurtleTool fromJson(ResourceLocation id, JsonObject object) {
|
|
||||||
var adjective = GsonHelper.getAsString(object, "adjective", UpgradeBase.getDefaultAdjective(id));
|
|
||||||
var toolItem = GsonHelper.getAsItem(object, "item");
|
|
||||||
var craftingItem = GsonHelper.getAsItem(object, "craftingItem", toolItem).value();
|
|
||||||
var damageMultiplier = GsonHelper.getAsFloat(object, "damageMultiplier", 3.0f);
|
|
||||||
var allowEnchantments = GsonHelper.getAsBoolean(object, "allowEnchantments", false);
|
|
||||||
var consumeDurability = TurtleToolDurability.CODEC.byName(GsonHelper.getAsString(object, "consumeDurability", null), TurtleToolDurability.NEVER);
|
|
||||||
|
|
||||||
TagKey<Block> breakable = null;
|
|
||||||
if (object.has("breakable")) {
|
|
||||||
var tag = new ResourceLocation(GsonHelper.getAsString(object, "breakable"));
|
|
||||||
breakable = TagKey.create(Registries.BLOCK, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TurtleTool(id, adjective, craftingItem, new ItemStack(toolItem), damageMultiplier, allowEnchantments, consumeDurability, breakable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TurtleTool fromNetwork(ResourceLocation id, RegistryFriendlyByteBuf buffer) {
|
|
||||||
var adjective = buffer.readUtf();
|
|
||||||
var craftingItem = ByteBufCodecs.registry(Registries.ITEM).decode(buffer);
|
|
||||||
var toolItem = ItemStack.STREAM_CODEC.decode(buffer);
|
|
||||||
// damageMultiplier and breakable aren't used by the client, but we need to construct the upgrade exactly
|
|
||||||
// as otherwise syncing on an SP world will overwrite the (shared) upgrade registry with an invalid upgrade!
|
|
||||||
var damageMultiplier = buffer.readFloat();
|
|
||||||
var allowsEnchantments = buffer.readBoolean();
|
|
||||||
var consumesDurability = buffer.readEnum(TurtleToolDurability.class);
|
|
||||||
|
|
||||||
var breakable = buffer.readNullable(b -> TagKey.create(Registries.BLOCK, b.readResourceLocation()));
|
|
||||||
return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, allowsEnchantments, consumesDurability, breakable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toNetwork(RegistryFriendlyByteBuf buffer, TurtleTool upgrade) {
|
|
||||||
buffer.writeUtf(upgrade.getUnlocalisedAdjective());
|
|
||||||
ByteBufCodecs.registry(Registries.ITEM).encode(buffer, upgrade.getCraftingItem().getItem());
|
|
||||||
ItemStack.STREAM_CODEC.encode(buffer, upgrade.item);
|
|
||||||
buffer.writeFloat(upgrade.damageMulitiplier);
|
|
||||||
buffer.writeBoolean(upgrade.allowEnchantments);
|
|
||||||
buffer.writeEnum(upgrade.consumeDurability);
|
|
||||||
buffer.writeNullable(upgrade.breakable, (b, x) -> b.writeResourceLocation(x.location()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -187,10 +187,10 @@ public class ComponentizationFixers {
|
|||||||
/**
|
/**
|
||||||
* Add our custom data components to the datafixer system.
|
* Add our custom data components to the datafixer system.
|
||||||
*
|
*
|
||||||
* @param type The existing component type definition.
|
* @param type The existing component type definition.
|
||||||
* @param schema The current schema.
|
* @param schema The current schema.
|
||||||
* @return The new component type definition.
|
* @return The new component type definition.
|
||||||
* @see UpgradeManager#codec()
|
* @see UpgradeManager#upgradeDataCodec()
|
||||||
* @see ModRegistry.DataComponents#POCKET_UPGRADE
|
* @see ModRegistry.DataComponents#POCKET_UPGRADE
|
||||||
* @see ModRegistry.DataComponents#LEFT_TURTLE_UPGRADE
|
* @see ModRegistry.DataComponents#LEFT_TURTLE_UPGRADE
|
||||||
* @see ModRegistry.DataComponents#RIGHT_TURTLE_UPGRADE
|
* @see ModRegistry.DataComponents#RIGHT_TURTLE_UPGRADE
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
|
import com.mojang.serialization.*;
|
||||||
|
import com.mojang.serialization.codecs.KeyDispatchCodec;
|
||||||
|
import dan200.computercraft.impl.RegistryHelper;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link Codec#dispatch(Function, Function)}/{@link KeyDispatchCodec} that checks that the
|
||||||
|
* result of {@code instance.getType()} matches the supplied type.
|
||||||
|
*
|
||||||
|
* @param <K> The type of keys.
|
||||||
|
* @param <V> The type of values.
|
||||||
|
*/
|
||||||
|
public final class SafeDispatchCodec<K, V> extends MapCodec<V> {
|
||||||
|
private static final String TYPE_KEY = "type";
|
||||||
|
private static final String COMPRESSED_VALUE_KEY = "value";
|
||||||
|
|
||||||
|
private final Codec<K> typeCodec;
|
||||||
|
private final Function<V, K> type;
|
||||||
|
private final Function<K, MapCodec<? extends V>> instanceCodec;
|
||||||
|
|
||||||
|
private SafeDispatchCodec(Codec<K> typeCodec, Function<V, K> type, Function<K, MapCodec<? extends V>> instanceCodec) {
|
||||||
|
this.typeCodec = typeCodec;
|
||||||
|
this.type = type;
|
||||||
|
this.instanceCodec = instanceCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new safe dispatch codec.
|
||||||
|
* <p>
|
||||||
|
* This decodes the {@code "type"} field of a map (using {@code typeCodec}), and then uses {@code instanceCodec} to
|
||||||
|
* find the codec that should be used for that type.
|
||||||
|
*
|
||||||
|
* @param typeCodec The codec to decode the type.
|
||||||
|
* @param type The function to get the type of an instance.
|
||||||
|
* @param instanceCodec The codec to decode an instance.
|
||||||
|
* @param <K> The type of keys.
|
||||||
|
* @param <V> The type of values.
|
||||||
|
* @return The dispatch codec.
|
||||||
|
*/
|
||||||
|
public static <K, V> Codec<V> codec(Codec<K> typeCodec, Function<V, K> type, Function<K, MapCodec<? extends V>> instanceCodec) {
|
||||||
|
return new SafeDispatchCodec<>(typeCodec, type, instanceCodec).codec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new safe dispatch codec.
|
||||||
|
* <p>
|
||||||
|
* This decodes the {@code "type"} field of a map (using {@code typeCodec}), and then uses {@code instanceCodec} to
|
||||||
|
* find the codec that should be used for that type.
|
||||||
|
*
|
||||||
|
* @param typeRegistry The built-in registry of types.
|
||||||
|
* @param type The function to get the type of an instance.
|
||||||
|
* @param instanceCodec The codec to decode an instance.
|
||||||
|
* @param <K> The type of keys.
|
||||||
|
* @param <V> The type of values.
|
||||||
|
* @return The dispatch codec.
|
||||||
|
*/
|
||||||
|
public static <K, V> Codec<V> ofRegistry(ResourceKey<Registry<K>> typeRegistry, Function<V, K> type, Function<K, MapCodec<? extends V>> instanceCodec) {
|
||||||
|
return codec(Codec.lazyInitialized(() -> RegistryHelper.getRegistry(typeRegistry).byNameCodec()), type, instanceCodec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> DataResult<V> decode(final DynamicOps<T> ops, final MapLike<T> input) {
|
||||||
|
var elementName = input.get(TYPE_KEY);
|
||||||
|
if (elementName == null) {
|
||||||
|
return DataResult.error(() -> "Input does not contain a key [" + TYPE_KEY + "]: " + input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeCodec.decode(ops, elementName).flatMap(typeResult -> {
|
||||||
|
var type = typeResult.getFirst();
|
||||||
|
var decoder = instanceCodec.apply(type);
|
||||||
|
|
||||||
|
DataResult<? extends V> result;
|
||||||
|
if (ops.compressMaps()) {
|
||||||
|
var value = input.get(ops.createString(COMPRESSED_VALUE_KEY));
|
||||||
|
if (value == null) return DataResult.error(() -> "Input does not have a \"value\" entry: " + input);
|
||||||
|
result = decoder.decoder().parse(ops, value);
|
||||||
|
} else {
|
||||||
|
result = decoder.decode(ops, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.flatMap(x -> {
|
||||||
|
var actualType = this.type.apply(x);
|
||||||
|
if (actualType != type) {
|
||||||
|
return DataResult.error(() -> x + " has the incorrect type. Expected " + type + ", but was " + actualType + ".");
|
||||||
|
}
|
||||||
|
return DataResult.success(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> RecordBuilder<T> encode(final V input, final DynamicOps<T> ops, final RecordBuilder<T> builder) {
|
||||||
|
@SuppressWarnings("unchecked") var encoder = (MapCodec<V>) instanceCodec.apply(type.apply(input));
|
||||||
|
|
||||||
|
if (ops.compressMaps()) {
|
||||||
|
return builder
|
||||||
|
.add(TYPE_KEY, typeCodec.encodeStart(ops, type.apply(input)))
|
||||||
|
.add(COMPRESSED_VALUE_KEY, encoder.encoder().encodeStart(ops, input));
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.encode(input, ops, builder).add(TYPE_KEY, typeCodec.encodeStart(ops, type.apply(input)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Stream<T> keys(final DynamicOps<T> ops) {
|
||||||
|
return Stream.of(TYPE_KEY, COMPRESSED_VALUE_KEY).map(ops::createString);
|
||||||
|
}
|
||||||
|
}
|
@ -1,65 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.shared.turtle.upgrades;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleToolDurability;
|
|
||||||
import dan200.computercraft.test.core.StructuralEquality;
|
|
||||||
import dan200.computercraft.test.shared.MinecraftArbitraries;
|
|
||||||
import dan200.computercraft.test.shared.MinecraftEqualities;
|
|
||||||
import dan200.computercraft.test.shared.NetworkSupport;
|
|
||||||
import dan200.computercraft.test.shared.WithMinecraft;
|
|
||||||
import net.jqwik.api.*;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
@WithMinecraft
|
|
||||||
class TurtleToolSerialiserTest {
|
|
||||||
static {
|
|
||||||
WithMinecraft.Setup.bootstrap(); // @Property doesn't run test lifecycle methods.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends turtle tools on a roundtrip, ensuring that their contents are reassembled on the other end.
|
|
||||||
*
|
|
||||||
* @param tool The message to send.
|
|
||||||
*/
|
|
||||||
@Property
|
|
||||||
public void testRoundTrip(@ForAll("tool") TurtleTool tool) {
|
|
||||||
var converted = NetworkSupport.roundTripSerialiser(
|
|
||||||
tool.getUpgradeID(), tool, TurtleToolSerialiser.INSTANCE::toNetwork, TurtleToolSerialiser.INSTANCE::fromNetwork
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!equality.equals(tool, converted)) {
|
|
||||||
System.out.println("Break");
|
|
||||||
}
|
|
||||||
assertThat("Messages are equal", converted, equality.asMatcher(TurtleTool.class, tool));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provide
|
|
||||||
Arbitrary<TurtleTool> tool() {
|
|
||||||
return Combinators.combine(
|
|
||||||
MinecraftArbitraries.resourceLocation(),
|
|
||||||
Arbitraries.strings().ofMaxLength(100),
|
|
||||||
MinecraftArbitraries.item(),
|
|
||||||
MinecraftArbitraries.nonEmptyItemStack(),
|
|
||||||
Arbitraries.floats(),
|
|
||||||
Arbitraries.of(true, false),
|
|
||||||
Arbitraries.of(TurtleToolDurability.values()),
|
|
||||||
MinecraftArbitraries.tagKey(Registries.BLOCK)
|
|
||||||
).as(TurtleTool::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final StructuralEquality<TurtleTool> equality = StructuralEquality.all(
|
|
||||||
StructuralEquality.at("id", ITurtleUpgrade::getUpgradeID),
|
|
||||||
StructuralEquality.at("craftingItem", ITurtleUpgrade::getCraftingItem, MinecraftEqualities.itemStack),
|
|
||||||
StructuralEquality.at("tool", x -> x.item, MinecraftEqualities.itemStack),
|
|
||||||
StructuralEquality.at("damageMulitiplier", x -> x.damageMulitiplier),
|
|
||||||
StructuralEquality.at("allowEnchantments", x -> x.allowEnchantments),
|
|
||||||
StructuralEquality.at("consumeDurability", x -> x.consumeDurability),
|
|
||||||
StructuralEquality.at("breakable", x -> x.breakable)
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.test.shared;
|
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support methods for working with Minecraft's networking code.
|
|
||||||
*/
|
|
||||||
public final class NetworkSupport {
|
|
||||||
private NetworkSupport() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to serialise and then deserialise a value.
|
|
||||||
*
|
|
||||||
* @param value The value to serialise.
|
|
||||||
* @param write Serialise this value to a buffer.
|
|
||||||
* @param read Deserialise this value from a buffer.
|
|
||||||
* @param <T> The type of the value to round trip.
|
|
||||||
* @return The converted value, for checking equivalency.
|
|
||||||
*/
|
|
||||||
public static <T> T roundTrip(T value, BiConsumer<T, RegistryFriendlyByteBuf> write, Function<RegistryFriendlyByteBuf, T> read) {
|
|
||||||
var buffer = new RegistryFriendlyByteBuf(Unpooled.directBuffer(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY));
|
|
||||||
write.accept(value, buffer);
|
|
||||||
|
|
||||||
var converted = read.apply(buffer);
|
|
||||||
assertEquals(buffer.readableBytes(), 0, "Whole packet was read");
|
|
||||||
return converted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to serialise and then deserialise a value from a {@link RecipeSerializer}-like interface.
|
|
||||||
*
|
|
||||||
* @param id The id of this value.
|
|
||||||
* @param value The value to serialise.
|
|
||||||
* @param write Serialise this value to a buffer.
|
|
||||||
* @param read Deserialise this value from a buffer.
|
|
||||||
* @param <T> The type of the value to round trip.
|
|
||||||
* @return The converted value, for checking equivalency.
|
|
||||||
*/
|
|
||||||
public static <T> T roundTripSerialiser(ResourceLocation id, T value, BiConsumer<RegistryFriendlyByteBuf, T> write, BiFunction<ResourceLocation, RegistryFriendlyByteBuf, T> read) {
|
|
||||||
return roundTrip(value, (x, b) -> write.accept(b, x), b -> read.apply(id, b));
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,6 @@ import dan200.computercraft.api.upgrades.UpgradeData
|
|||||||
import dan200.computercraft.core.apis.PeripheralAPI
|
import dan200.computercraft.core.apis.PeripheralAPI
|
||||||
import dan200.computercraft.gametest.api.*
|
import dan200.computercraft.gametest.api.*
|
||||||
import dan200.computercraft.gametest.core.TestHooks
|
import dan200.computercraft.gametest.core.TestHooks
|
||||||
import dan200.computercraft.impl.TurtleUpgrades
|
|
||||||
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
||||||
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
||||||
import dan200.computercraft.shared.ModRegistry
|
import dan200.computercraft.shared.ModRegistry
|
||||||
@ -234,7 +233,7 @@ class Turtle_Test {
|
|||||||
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
||||||
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
TurtleUpgrades.instance()
|
helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE)
|
||||||
.get(ResourceLocation("cctest", "wooden_pickaxe")),
|
.get(ResourceLocation("cctest", "wooden_pickaxe")),
|
||||||
upgrade,
|
upgrade,
|
||||||
"Upgrade is a wooden pickaxe",
|
"Upgrade is a wooden pickaxe",
|
||||||
@ -262,7 +261,10 @@ class Turtle_Test {
|
|||||||
|
|
||||||
helper.assertUpgradeItem(
|
helper.assertUpgradeItem(
|
||||||
ItemStack(Items.WOODEN_PICKAXE),
|
ItemStack(Items.WOODEN_PICKAXE),
|
||||||
UpgradeData.ofDefault(TurtleUpgrades.instance().get(ResourceLocation("cctest", "wooden_pickaxe"))),
|
UpgradeData.ofDefault(
|
||||||
|
helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE)
|
||||||
|
.getHolder(ResourceLocation("cctest", "wooden_pickaxe")).orElseThrow(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +283,8 @@ class Turtle_Test {
|
|||||||
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
||||||
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
TurtleUpgrades.instance().get(ResourceLocation("cctest", "netherite_pickaxe")),
|
helper.level.registryAccess().registryOrThrow(ModRegistry.TURTLE_UPGRADE)
|
||||||
|
.get(ResourceLocation("cctest", "netherite_pickaxe")),
|
||||||
upgrade,
|
upgrade,
|
||||||
"Upgrade is a netherite pickaxe",
|
"Upgrade is a netherite pickaxe",
|
||||||
)
|
)
|
||||||
@ -299,8 +302,8 @@ class Turtle_Test {
|
|||||||
fail("Invalid upgrade item\n Expected => ${expected.componentsPatch}\n Actual => ${upgrade.upgradeItem.componentsPatch}")
|
fail("Invalid upgrade item\n Expected => ${expected.componentsPatch}\n Actual => ${upgrade.upgradeItem.componentsPatch}")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ItemStack.matches(ItemStack(expected.item), upgrade.upgrade.craftingItem)) {
|
if (!ItemStack.matches(ItemStack(expected.item), upgrade.upgrade().craftingItem)) {
|
||||||
fail("Original upgrade item has changed (is now ${upgrade.upgrade.craftingItem})")
|
fail("Original upgrade item has changed (is now ${upgrade.upgrade().craftingItem})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "computercraft:tool",
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_pickaxe.adjective",
|
||||||
"item": "minecraft:netherite_pickaxe",
|
"item": "minecraft:netherite_pickaxe",
|
||||||
"allowEnchantments": true,
|
"allowEnchantments": true,
|
||||||
"consumeDurability": "when_enchanted"
|
"consumeDurability": "when_enchanted"
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "computercraft:tool",
|
"type": "computercraft:tool",
|
||||||
|
"adjective": "upgrade.minecraft.diamond_pickaxe.adjective",
|
||||||
"item": "minecraft:wooden_pickaxe",
|
"item": "minecraft:wooden_pickaxe",
|
||||||
"consumeDurability": "always"
|
"consumeDurability": "always"
|
||||||
}
|
}
|
@ -9,8 +9,8 @@
|
|||||||
"name": "computercraft:treasure_disk",
|
"name": "computercraft:treasure_disk",
|
||||||
"functions": [
|
"functions": [
|
||||||
{
|
{
|
||||||
"function": "minecraft:set_nbt",
|
"function": "minecraft:set_components",
|
||||||
"tag": "{\"Title\": \"Demo disk\", \"SubPath\": \"demo\", \"Colour\": 15905331}"
|
"components": {"computercraft:treasure_disk": {"name": "Demo disk","title": "demo"}}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.api.client;
|
|||||||
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.impl.client.FabricComputerCraftAPIClientService;
|
import dan200.computercraft.impl.client.FabricComputerCraftAPIClientService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,12 +27,12 @@ public final class FabricComputerCraftAPIClient {
|
|||||||
* This method may be used as a {@link dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller}, for
|
* This method may be used as a {@link dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller}, for
|
||||||
* convenient use in multi-loader code.
|
* convenient use in multi-loader code.
|
||||||
*
|
*
|
||||||
* @param serialiser The turtle upgrade serialiser.
|
* @param type The turtle upgrade type.
|
||||||
* @param modeller The upgrade modeller.
|
* @param modeller The upgrade modeller.
|
||||||
* @param <T> The type of the turtle upgrade.
|
* @param <T> The type of the turtle upgrade.
|
||||||
*/
|
*/
|
||||||
public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller) {
|
||||||
getInstance().registerTurtleUpgradeModeller(serialiser, modeller);
|
getInstance().registerTurtleUpgradeModeller(type, modeller);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FabricComputerCraftAPIClientService getInstance() {
|
private static FabricComputerCraftAPIClientService getInstance() {
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.impl.client;
|
|||||||
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.impl.Services;
|
import dan200.computercraft.impl.Services;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ public interface FabricComputerCraftAPIClientService {
|
|||||||
return instance == null ? Services.raise(FabricComputerCraftAPIClientService.class, Instance.ERROR) : instance;
|
return instance == null ? Services.raise(FabricComputerCraftAPIClientService.class, Instance.ERROR) : instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
<T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller);
|
<T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller);
|
||||||
|
|
||||||
final class Instance {
|
final class Instance {
|
||||||
static final @Nullable FabricComputerCraftAPIClientService INSTANCE;
|
static final @Nullable FabricComputerCraftAPIClientService INSTANCE;
|
||||||
|
@ -12,7 +12,9 @@ import dan200.computercraft.shared.turtle.items.TurtleItem;
|
|||||||
import dev.architectury.event.EventResult;
|
import dev.architectury.event.EventResult;
|
||||||
import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
|
import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
|
||||||
import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
|
import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
|
||||||
|
import me.shedaniel.rei.api.client.registry.entry.EntryRegistry;
|
||||||
import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry;
|
import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry;
|
||||||
|
import me.shedaniel.rei.api.common.util.EntryStacks;
|
||||||
import me.shedaniel.rei.plugin.common.BuiltinPlugin;
|
import me.shedaniel.rei.plugin.common.BuiltinPlugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,20 +28,27 @@ public class REIComputerCraft implements REIClientPlugin {
|
|||||||
registry.register((context, stack) -> {
|
registry.register((context, stack) -> {
|
||||||
long hash = 1;
|
long hash = 1;
|
||||||
|
|
||||||
var left = TurtleItem.getUpgrade(stack, TurtleSide.LEFT);
|
var left = TurtleItem.getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
var right = TurtleItem.getUpgrade(stack, TurtleSide.RIGHT);
|
var right = TurtleItem.getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
if (left != null) hash = hash * 31 + left.getUpgradeID().hashCode();
|
if (left != null) hash = hash * 31 + left.holder().key().location().hashCode();
|
||||||
if (right != null) hash = hash * 31 + right.getUpgradeID().hashCode();
|
if (right != null) hash = hash * 31 + right.holder().key().location().hashCode();
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}, ModRegistry.Items.TURTLE_NORMAL.get(), ModRegistry.Items.TURTLE_ADVANCED.get());
|
}, ModRegistry.Items.TURTLE_NORMAL.get(), ModRegistry.Items.TURTLE_ADVANCED.get());
|
||||||
|
|
||||||
registry.register((context, stack) -> {
|
registry.register((context, stack) -> {
|
||||||
var upgrade = PocketComputerItem.getUpgrade(stack);
|
var upgrade = PocketComputerItem.getUpgradeWithData(stack);
|
||||||
return upgrade == null ? 1 : upgrade.getUpgradeID().hashCode();
|
return upgrade == null ? 1 : upgrade.holder().key().location().hashCode();
|
||||||
}, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
}, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerEntries(EntryRegistry registry) {
|
||||||
|
for (var stack : RecipeModHelpers.getExtraStacks(RecipeModHelpers.getEmptyRegistryAccess())) {
|
||||||
|
registry.addEntry(EntryStacks.of(stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerDisplays(DisplayRegistry registry) {
|
public void registerDisplays(DisplayRegistry registry) {
|
||||||
registry.registerDisplayGenerator(BuiltinPlugin.CRAFTING, new UpgradeDisplayGenerator());
|
registry.registerDisplayGenerator(BuiltinPlugin.CRAFTING, new UpgradeDisplayGenerator());
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.integration.rei;
|
package dan200.computercraft.client.integration.rei;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.integration.RecipeModHelpers;
|
||||||
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
||||||
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator;
|
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator;
|
||||||
import me.shedaniel.rei.api.common.display.basic.BasicDisplay;
|
import me.shedaniel.rei.api.common.display.basic.BasicDisplay;
|
||||||
@ -23,7 +24,7 @@ import java.util.Optional;
|
|||||||
* Provides custom recipe and usage hints for pocket/turtle upgrades.
|
* Provides custom recipe and usage hints for pocket/turtle upgrades.
|
||||||
*/
|
*/
|
||||||
class UpgradeDisplayGenerator implements DynamicDisplayGenerator<DefaultCraftingDisplay<?>> {
|
class UpgradeDisplayGenerator implements DynamicDisplayGenerator<DefaultCraftingDisplay<?>> {
|
||||||
private final UpgradeRecipeGenerator<DefaultCraftingDisplay<?>> resolver = new UpgradeRecipeGenerator<>(GeneratedShapedDisplay::new);
|
private final UpgradeRecipeGenerator<DefaultCraftingDisplay<?>> resolver = new UpgradeRecipeGenerator<>(GeneratedShapedDisplay::new, RecipeModHelpers.getEmptyRegistryAccess());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<List<DefaultCraftingDisplay<?>>> getRecipeFor(EntryStack<?> entry) {
|
public Optional<List<DefaultCraftingDisplay<?>>> getRecipeFor(EntryStack<?> entry) {
|
||||||
|
@ -7,13 +7,13 @@ package dan200.computercraft.impl.client;
|
|||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||||
|
|
||||||
@AutoService(FabricComputerCraftAPIClientService.class)
|
@AutoService(FabricComputerCraftAPIClientService.class)
|
||||||
public final class FabricComputerCraftAPIClientImpl implements FabricComputerCraftAPIClientService {
|
public final class FabricComputerCraftAPIClientImpl implements FabricComputerCraftAPIClientService {
|
||||||
@Override
|
@Override
|
||||||
public <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
public <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller) {
|
||||||
TurtleUpgradeModellers.register(serialiser, modeller);
|
TurtleUpgradeModellers.register(type, modeller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,26 +5,32 @@
|
|||||||
package dan200.computercraft.data;
|
package dan200.computercraft.data;
|
||||||
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
|
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.fabricmc.fabric.api.event.registry.DynamicRegistries;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.data.DataProvider;
|
import net.minecraft.data.DataProvider;
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.data.tags.TagsProvider;
|
import net.minecraft.data.tags.TagsProvider;
|
||||||
|
import net.minecraft.resources.RegistryDataLoader;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.packs.PackType;
|
import net.minecraft.server.packs.PackType;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class FabricDataGenerators implements DataGeneratorEntrypoint {
|
public class FabricDataGenerators implements DataGeneratorEntrypoint {
|
||||||
@Override
|
@Override
|
||||||
@ -103,5 +109,63 @@ public class FabricDataGenerators implements DataGeneratorEntrypoint {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<RegistrySetBuilder.PatchedRegistries> createPatchedRegistries(CompletableFuture<HolderLookup.Provider> registries, RegistrySetBuilder patch) {
|
||||||
|
return registries.thenApply(oldRegistries -> {
|
||||||
|
var factory = new Cloner.Factory();
|
||||||
|
DynamicRegistries.getDynamicRegistries().forEach(registryData -> registryData.runWithArguments(factory::addCodec));
|
||||||
|
return patch.buildPatch(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY), new DynamicRegistryLookup(oldRegistries), factory);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link HolderLookup.Provider} implementation that adds any Fabric dynamic registry, if missing.
|
||||||
|
*
|
||||||
|
* @param parent The parent registry.
|
||||||
|
*/
|
||||||
|
private record DynamicRegistryLookup(HolderLookup.Provider parent) implements HolderLookup.Provider {
|
||||||
|
@Override
|
||||||
|
public Stream<ResourceKey<? extends Registry<?>>> listRegistries() {
|
||||||
|
return Stream.concat(
|
||||||
|
parent.listRegistries(),
|
||||||
|
DynamicRegistries.getDynamicRegistries().stream().map(RegistryDataLoader.RegistryData::key)
|
||||||
|
).distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Optional<HolderLookup.RegistryLookup<T>> lookup(ResourceKey<? extends Registry<? extends T>> registryKey) {
|
||||||
|
return parent.lookup(registryKey).or(() -> Optional.of(new EmptyRegistry<>(registryKey)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record EmptyRegistry<T>(
|
||||||
|
ResourceKey<? extends Registry<? extends T>> key
|
||||||
|
) implements HolderLookup.RegistryLookup<T> {
|
||||||
|
@Override
|
||||||
|
public Lifecycle registryLifecycle() {
|
||||||
|
return Lifecycle.stable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<Holder.Reference<T>> listElements() {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<HolderSet.Named<T>> listTags() {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Holder.Reference<T>> get(ResourceKey<T> resourceKey) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<HolderSet.Named<T>> get(TagKey<T> tagKey) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public final class ComputerCraftAPIImpl extends AbstractComputerCraftAPI impleme
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
// This We create the registries here (rather than in the mod initialiser) to guarantee that they're available
|
// This We create the registries here (rather than in the mod initialiser) to guarantee that they're available
|
||||||
// when people come to register upgrade serialisers.
|
// when people come to register upgrade types.
|
||||||
// This is a little nasty (side effects in static constructors and all that!), but seems to be the easiest way.
|
// This is a little nasty (side effects in static constructors and all that!), but seems to be the easiest way.
|
||||||
FabricRegistryBuilder.createSimple(turtleUpgradeRegistryId).buildAndRegister();
|
FabricRegistryBuilder.createSimple(turtleUpgradeRegistryId).buildAndRegister();
|
||||||
FabricRegistryBuilder.createSimple(pocketUpgradeRegistryId).buildAndRegister();
|
FabricRegistryBuilder.createSimple(pocketUpgradeRegistryId).buildAndRegister();
|
||||||
|
@ -9,13 +9,13 @@ import dan200.computercraft.api.detail.FabricDetailRegistries;
|
|||||||
import dan200.computercraft.api.network.wired.WiredElementLookup;
|
import dan200.computercraft.api.network.wired.WiredElementLookup;
|
||||||
import dan200.computercraft.api.peripheral.PeripheralLookup;
|
import dan200.computercraft.api.peripheral.PeripheralLookup;
|
||||||
import dan200.computercraft.impl.Peripherals;
|
import dan200.computercraft.impl.Peripherals;
|
||||||
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
import dan200.computercraft.shared.config.ConfigSpec;
|
import dan200.computercraft.shared.config.ConfigSpec;
|
||||||
import dan200.computercraft.shared.details.FluidDetails;
|
import dan200.computercraft.shared.details.FluidDetails;
|
||||||
import dan200.computercraft.shared.network.NetworkMessages;
|
import dan200.computercraft.shared.network.NetworkMessages;
|
||||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
|
||||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
|
||||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||||
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||||
@ -29,6 +29,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
|||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.registry.DynamicRegistries;
|
||||||
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
|
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
|
||||||
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
|
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
|
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
|
||||||
@ -65,6 +66,9 @@ public class ComputerCraft {
|
|||||||
|
|
||||||
FabricRegistryBuilder.createSimple(RecipeFunction.REGISTRY).attribute(RegistryAttribute.SYNCED).buildAndRegister();
|
FabricRegistryBuilder.createSimple(RecipeFunction.REGISTRY).attribute(RegistryAttribute.SYNCED).buildAndRegister();
|
||||||
|
|
||||||
|
DynamicRegistries.registerSynced(ModRegistry.TURTLE_UPGRADE, TurtleUpgrades.instance().upgradeCodec());
|
||||||
|
DynamicRegistries.registerSynced(ModRegistry.POCKET_UPGRADE, PocketUpgrades.instance().upgradeCodec());
|
||||||
|
|
||||||
ModRegistry.register();
|
ModRegistry.register();
|
||||||
ModRegistry.registerMainThread();
|
ModRegistry.registerMainThread();
|
||||||
|
|
||||||
@ -106,7 +110,6 @@ public class ComputerCraft {
|
|||||||
((FabricConfigFile) ConfigSpec.serverSpec).unload();
|
((FabricConfigFile) ConfigSpec.serverSpec).unload();
|
||||||
});
|
});
|
||||||
ServerLifecycleEvents.SERVER_STARTED.register(CommonHooks::onServerStarted);
|
ServerLifecycleEvents.SERVER_STARTED.register(CommonHooks::onServerStarted);
|
||||||
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> ServerNetworking.sendToPlayer(new UpgradesLoadedMessage(), player));
|
|
||||||
|
|
||||||
ServerTickEvents.START_SERVER_TICK.register(CommonHooks::onServerTickStart);
|
ServerTickEvents.START_SERVER_TICK.register(CommonHooks::onServerTickStart);
|
||||||
ServerTickEvents.START_SERVER_TICK.register(s -> CommonHooks.onServerTickEnd());
|
ServerTickEvents.START_SERVER_TICK.register(s -> CommonHooks.onServerTickEnd());
|
||||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.api.client.turtle;
|
|||||||
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeType;
|
||||||
import net.neoforged.bus.api.Event;
|
import net.neoforged.bus.api.Event;
|
||||||
import net.neoforged.fml.event.IModBusEvent;
|
import net.neoforged.fml.event.IModBusEvent;
|
||||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
@ -33,7 +33,7 @@ public class RegisterTurtleModellersEvent extends Event implements IModBusEvent,
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T extends ITurtleUpgrade> void register(UpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
public <T extends ITurtleUpgrade> void register(UpgradeType<T> type, TurtleUpgradeModeller<T> modeller) {
|
||||||
dispatch.register(serialiser, modeller);
|
dispatch.register(type, modeller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ import dan200.computercraft.api.network.wired.WiredElementCapability;
|
|||||||
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.impl.Services;
|
import dan200.computercraft.impl.Services;
|
||||||
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.CommonHooks;
|
import dan200.computercraft.shared.CommonHooks;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
@ -48,6 +50,7 @@ import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
|||||||
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
||||||
|
import net.neoforged.neoforge.registries.DataPackRegistryEvent;
|
||||||
import net.neoforged.neoforge.registries.NewRegistryEvent;
|
import net.neoforged.neoforge.registries.NewRegistryEvent;
|
||||||
import net.neoforged.neoforge.registries.RegistryBuilder;
|
import net.neoforged.neoforge.registries.RegistryBuilder;
|
||||||
|
|
||||||
@ -80,11 +83,17 @@ public final class ComputerCraft {
|
|||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void registerRegistries(NewRegistryEvent event) {
|
public static void registerRegistries(NewRegistryEvent event) {
|
||||||
event.create(new RegistryBuilder<>(ITurtleUpgrade.serialiserRegistryKey()));
|
event.create(new RegistryBuilder<>(ITurtleUpgrade.typeRegistry()));
|
||||||
event.create(new RegistryBuilder<>(IPocketUpgrade.serialiserRegistryKey()));
|
event.create(new RegistryBuilder<>(IPocketUpgrade.typeRegistry()));
|
||||||
event.create(new RegistryBuilder<>(RecipeFunction.REGISTRY).sync(true));
|
event.create(new RegistryBuilder<>(RecipeFunction.REGISTRY).sync(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void registerDynamicRegistries(DataPackRegistryEvent.NewRegistry event) {
|
||||||
|
event.dataPackRegistry(ModRegistry.TURTLE_UPGRADE, TurtleUpgrades.instance().upgradeCodec(), TurtleUpgrades.instance().upgradeCodec());
|
||||||
|
event.dataPackRegistry(ModRegistry.POCKET_UPGRADE, PocketUpgrades.instance().upgradeCodec(), PocketUpgrades.instance().upgradeCodec());
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void init(FMLCommonSetupEvent event) {
|
public static void init(FMLCommonSetupEvent event) {
|
||||||
event.enqueueWork(ModRegistry::registerMainThread);
|
event.enqueueWork(ModRegistry::registerMainThread);
|
||||||
|
@ -6,8 +6,6 @@ package dan200.computercraft.shared;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
|
||||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -15,7 +13,10 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
import net.neoforged.bus.api.EventPriority;
|
import net.neoforged.bus.api.EventPriority;
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
import net.neoforged.fml.common.EventBusSubscriber;
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
import net.neoforged.neoforge.event.*;
|
import net.neoforged.neoforge.event.AddReloadListenerEvent;
|
||||||
|
import net.neoforged.neoforge.event.LootTableLoadEvent;
|
||||||
|
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||||
|
import net.neoforged.neoforge.event.TickEvent;
|
||||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingDropsEvent;
|
import net.neoforged.neoforge.event.entity.living.LivingDropsEvent;
|
||||||
import net.neoforged.neoforge.event.level.ChunkEvent;
|
import net.neoforged.neoforge.event.level.ChunkEvent;
|
||||||
@ -80,16 +81,6 @@ public class ForgeCommonHooks {
|
|||||||
CommonHooks.onDatapackReload((id, listener) -> event.addListener(listener));
|
CommonHooks.onDatapackReload((id, listener) -> event.addListener(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public static void onDatapackSync(OnDatapackSyncEvent event) {
|
|
||||||
var packet = new UpgradesLoadedMessage();
|
|
||||||
if (event.getPlayer() == null) {
|
|
||||||
ServerNetworking.sendToAllPlayers(packet, event.getPlayerList().getServer());
|
|
||||||
} else {
|
|
||||||
ServerNetworking.sendToPlayer(packet, event.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void lootLoad(LootTableLoadEvent event) {
|
public static void lootLoad(LootTableLoadEvent event) {
|
||||||
var pool = CommonHooks.getExtraLootPool(ResourceKey.create(Registries.LOOT_TABLE, event.getName()));
|
var pool = CommonHooks.getExtraLootPool(ResourceKey.create(Registries.LOOT_TABLE, event.getName()));
|
||||||
|
Loading…
Reference in New Issue
Block a user