1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-25 22:53:22 +00:00

Update to Minecraft 1.19.3

Lots of minor changes, but nothing too nasty - just tedious.

Known bugs/issues:
 - REI and JEI haven't been updated at the time of writing, so our usage
   of their APIs may be incompatible.

 - Crash when opening the config UI in Fabric, as forgeconfigapi-port
   hasn't been updated yet.

Will hold off on doing a release until those mods have updated.
This commit is contained in:
Jonathan Coates 2022-12-08 19:45:02 +00:00
parent 3b42f22a4f
commit c3fe9f00d4
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
373 changed files with 886 additions and 728 deletions

View File

@ -9,4 +9,4 @@ isUnstable=true
modVersion=1.102.0-SNAPSHOT modVersion=1.102.0-SNAPSHOT
# Minecraft properties: We want to configure this here so we can read it in settings.gradle # Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.19.2 mcVersion=1.19.3

View File

@ -2,12 +2,12 @@
# Minecraft # Minecraft
# MC version is specified in gradle.properties, as we need that in settings.gradle. # MC version is specified in gradle.properties, as we need that in settings.gradle.
fabric-api = "0.67.0+1.19.2" fabric-api = "0.68.1+1.19.3"
fabric-loader = "0.14.10" fabric-loader = "0.14.11"
forge = "43.1.1" forge = "44.0.0"
forgeSpi = "6.0.0" forgeSpi = "6.0.0"
mixin = "0.8.5" mixin = "0.8.5"
parchment = "2022.10.16" parchment = "2022.11.27"
parchmentMc = "1.19.2" parchmentMc = "1.19.2"
# Normal dependencies # Normal dependencies
@ -28,16 +28,16 @@ slf4j = "1.7.36"
# Minecraft mods # Minecraft mods
forgeConfig = "4.2.7" forgeConfig = "4.2.7"
iris = "1.19.x-v1.4.0" iris = "1.19.3-v1.4.6"
jei = "11.3.0.262" jei = "11.3.0.262"
modmenu = "4.1.0" modmenu = "5.0.1"
oculus = "1.2.5" oculus = "1.2.5"
rei = "9.1.550" rei = "9.1.550"
rubidium = "0.6.1" rubidium = "0.6.1"
sodium = "mc1.19.2-0.4.4" sodium = "mc1.19.3-0.4.6"
# Testing # Testing
byteBuddy = "1.12.18" byteBuddy = "1.12.19"
hamcrest = "2.2" hamcrest = "2.2"
jqwik = "1.7.0" jqwik = "1.7.0"
junit = "5.9.1" junit = "5.9.1"
@ -100,6 +100,7 @@ sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
# Testing # Testing
byteBuddyAgent = { module ="net.bytebuddy:byte-buddy-agent", version.ref = "byteBuddy" } byteBuddyAgent = { module ="net.bytebuddy:byte-buddy-agent", version.ref = "byteBuddy" }
byteBuddy = { module ="net.bytebuddy:byte-buddy", version.ref = "byteBuddy" }
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" } jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" } jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
@ -143,10 +144,10 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
# Minecraft # Minecraft
externalMods-common = ["jei-api", "forgeConfig", "nightConfig-core", "nightConfig-toml"] externalMods-common = ["jei-api", "forgeConfig", "nightConfig-core", "nightConfig-toml"]
externalMods-forge-compile = ["oculus", "jei-api"] externalMods-forge-compile = ["oculus", "jei-api"]
externalMods-forge-runtime = ["jei-forge"] externalMods-forge-runtime = []
externalMods-fabric = ["fabric-loader", "fabric-api", "forgeConfig", "nightConfig-core", "nightConfig-toml"] externalMods-fabric = ["fabric-loader", "fabric-api", "forgeConfig", "nightConfig-core", "nightConfig-toml"]
externalMods-fabric-compile = ["iris", "jei-api", "rei-api", "rei-builtin"] externalMods-fabric-compile = ["iris", "jei-api", "rei-api", "rei-builtin"]
externalMods-fabric-runtime = ["jei-fabric", "modmenu"] externalMods-fabric-runtime = ["modmenu"]
# Testing # Testing
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"] test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]

View File

@ -5,13 +5,11 @@
*/ */
package dan200.computercraft.api.client.turtle; package dan200.computercraft.api.client.turtle;
import com.mojang.math.Matrix4f;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
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 org.joml.Matrix4f;
import java.nio.FloatBuffer;
class TurtleUpgradeModellers { class TurtleUpgradeModellers {
private static final Transformation leftTransform = getMatrixFor(-0.40625f); private static final Transformation leftTransform = getMatrixFor(-0.40625f);
@ -19,12 +17,12 @@ class TurtleUpgradeModellers {
private static Transformation getMatrixFor(float offset) { private static Transformation getMatrixFor(float offset) {
var matrix = new Matrix4f(); var matrix = new Matrix4f();
matrix.load(FloatBuffer.wrap(new float[]{ matrix.set(new float[]{
0.0f, 0.0f, -1.0f, 1.0f + offset, 0.0f, 0.0f, -1.0f, 1.0f + offset,
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
})); });
matrix.transpose(); matrix.transpose();
return new Transformation(matrix); return new Transformation(matrix);
} }

View File

@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.api; package dan200.computercraft.api;
import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
@ -22,7 +22,7 @@ public static class Items {
public static final TagKey<Item> MONITOR = make("monitor"); public static final TagKey<Item> MONITOR = make("monitor");
private static TagKey<Item> make(String name) { private static TagKey<Item> make(String name) {
return TagKey.create(Registry.ITEM_REGISTRY, new ResourceLocation(ComputerCraftAPI.MOD_ID, name)); return TagKey.create(Registries.ITEM, new ResourceLocation(ComputerCraftAPI.MOD_ID, name));
} }
} }
@ -53,7 +53,7 @@ public static class Blocks {
public static final TagKey<Block> TURTLE_HOE_BREAKABLE = make("turtle_hoe_harvestable"); public static final TagKey<Block> TURTLE_HOE_BREAKABLE = make("turtle_hoe_harvestable");
private static TagKey<Block> make(String name) { private static TagKey<Block> make(String name) {
return TagKey.create(Registry.BLOCK_REGISTRY, new ResourceLocation(ComputerCraftAPI.MOD_ID, name)); return TagKey.create(Registries.BLOCK, new ResourceLocation(ComputerCraftAPI.MOD_ID, name));
} }
} }
} }

View File

@ -7,19 +7,21 @@
import dan200.computercraft.api.upgrades.UpgradeDataProvider; import dan200.computercraft.api.upgrades.UpgradeDataProvider;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* A data provider to generate pocket computer upgrades. * A data provider to generate pocket computer upgrades.
* <p> * <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function, * This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the
* construct each upgrade, and pass them off to the provided consumer to generate them. * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
* generate them.
* *
* @see PocketUpgradeSerialiser * @see PocketUpgradeSerialiser
*/ */
public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade, PocketUpgradeSerialiser<?>> { public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade, PocketUpgradeSerialiser<?>> {
public PocketUpgradeDataProvider(DataGenerator generator) { public PocketUpgradeDataProvider(PackOutput output) {
super(generator, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", PocketUpgradeSerialiser.REGISTRY_ID); super(output, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", PocketUpgradeSerialiser.REGISTRY_ID);
} }
} }

View File

@ -14,7 +14,7 @@
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.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
@ -36,8 +36,8 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
ResourceKey<Registry<PocketUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade_serialiser")); ResourceKey<Registry<PocketUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade_serialiser"));
/** /**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for * Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer},
* upgrades. * but for upgrades.
* <p> * <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead. * If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
* *

View File

@ -9,8 +9,9 @@
import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.api.ComputerCraftTags;
import dan200.computercraft.api.upgrades.UpgradeDataProvider; import dan200.computercraft.api.upgrades.UpgradeDataProvider;
import dan200.computercraft.impl.PlatformHelper; import dan200.computercraft.impl.PlatformHelper;
import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.Attributes;
@ -23,16 +24,17 @@
/** /**
* A data provider to generate turtle upgrades. * A data provider to generate turtle upgrades.
* <p> * <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function, * This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the
* construct each upgrade, and pass them off to the provided consumer to generate them. * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
* generate them.
* *
* @see TurtleUpgradeSerialiser * @see TurtleUpgradeSerialiser
*/ */
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> { public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> {
private static final ResourceLocation TOOL_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "tool"); private static final ResourceLocation TOOL_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "tool");
public TurtleUpgradeDataProvider(DataGenerator generator) { public TurtleUpgradeDataProvider(PackOutput output) {
super(generator, "Turtle Upgrades", "computercraft/turtle_upgrades", TurtleUpgradeSerialiser.REGISTRY_ID); super(output, "Turtle Upgrades", "computercraft/turtle_upgrades", TurtleUpgradeSerialiser.REGISTRY_ID);
} }
/** /**
@ -124,10 +126,10 @@ public ToolBuilder breakable(TagKey<Block> breakable) {
*/ */
public void add(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> add) { public void add(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> add) {
add.accept(new Upgrade<>(id, serialiser, s -> { add.accept(new Upgrade<>(id, serialiser, s -> {
s.addProperty("item", PlatformHelper.get().getRegistryKey(Registry.ITEM_REGISTRY, toolItem).toString()); s.addProperty("item", PlatformHelper.get().getRegistryKey(Registries.ITEM, toolItem).toString());
if (adjective != null) s.addProperty("adjective", adjective); if (adjective != null) s.addProperty("adjective", adjective);
if (craftingItem != null) { if (craftingItem != null) {
s.addProperty("craftItem", PlatformHelper.get().getRegistryKey(Registry.ITEM_REGISTRY, craftingItem).toString()); s.addProperty("craftItem", PlatformHelper.get().getRegistryKey(Registries.ITEM, craftingItem).toString());
} }
if (damageMultiplier != null) s.addProperty("damageMultiplier", damageMultiplier); if (damageMultiplier != null) s.addProperty("damageMultiplier", damageMultiplier);
if (breakable != null) s.addProperty("breakable", breakable.location().toString()); if (breakable != null) s.addProperty("breakable", breakable.location().toString());

View File

@ -15,7 +15,7 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
@ -71,8 +71,8 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
ResourceKey<Registry<TurtleUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade_serialiser")); ResourceKey<Registry<TurtleUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade_serialiser"));
/** /**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for * Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer},
* upgrades. * but for upgrades.
* <p> * <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead. * If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
* *

View File

@ -11,10 +11,12 @@
import dan200.computercraft.impl.PlatformHelper; import dan200.computercraft.impl.PlatformHelper;
import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem;
import dan200.computercraft.impl.upgrades.SimpleSerialiser; import dan200.computercraft.impl.upgrades.SimpleSerialiser;
import net.minecraft.Util;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.CachedOutput; import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
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 net.minecraft.world.item.Item;
@ -22,11 +24,11 @@
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -40,15 +42,15 @@
public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider { public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider {
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
private final DataGenerator generator; private final PackOutput output;
private final String name; private final String name;
private final String folder; private final String folder;
private final ResourceKey<Registry<R>> registry; private final ResourceKey<Registry<R>> registry;
private @Nullable List<T> upgrades; private @Nullable List<T> upgrades;
protected UpgradeDataProvider(DataGenerator generator, String name, String folder, ResourceKey<Registry<R>> registry) { protected UpgradeDataProvider(PackOutput output, String name, String folder, ResourceKey<Registry<R>> registry) {
this.generator = generator; this.output = output;
this.name = name; this.name = name;
this.folder = folder; this.folder = folder;
this.registry = registry; this.registry = registry;
@ -84,7 +86,7 @@ public final Upgrade<R> simpleWithCustomItem(ResourceLocation id, R serialiser,
} }
return new Upgrade<>(id, serialiser, s -> return new Upgrade<>(id, serialiser, s ->
s.addProperty("item", PlatformHelper.get().getRegistryKey(Registry.ITEM_REGISTRY, item).toString()) s.addProperty("item", PlatformHelper.get().getRegistryKey(Registries.ITEM, item).toString())
); );
} }
@ -103,11 +105,12 @@ public final Upgrade<R> simpleWithCustomItem(ResourceLocation id, R serialiser,
protected abstract void addUpgrades(Consumer<Upgrade<R>> addUpgrade); protected abstract void addUpgrades(Consumer<Upgrade<R>> addUpgrade);
@Override @Override
public final void run(CachedOutput cache) throws IOException { public final CompletableFuture<?> run(CachedOutput cache) {
var base = generator.getOutputFolder().resolve("data"); var base = output.getOutputFolder().resolve("data");
Set<ResourceLocation> seen = new HashSet<>(); Set<ResourceLocation> seen = new HashSet<>();
List<T> upgrades = new ArrayList<>(); List<T> upgrades = new ArrayList<>();
List<CompletableFuture<?>> futures = new ArrayList<>();
addUpgrades(upgrade -> { addUpgrades(upgrade -> {
if (!seen.add(upgrade.id())) throw new IllegalStateException("Duplicate upgrade " + upgrade.id()); if (!seen.add(upgrade.id())) throw new IllegalStateException("Duplicate upgrade " + upgrade.id());
@ -115,11 +118,7 @@ public final void run(CachedOutput cache) throws IOException {
json.addProperty("type", PlatformHelper.get().getRegistryKey(registry, upgrade.serialiser()).toString()); json.addProperty("type", PlatformHelper.get().getRegistryKey(registry, upgrade.serialiser()).toString());
upgrade.serialise().accept(json); upgrade.serialise().accept(json);
try { futures.add(DataProvider.saveStable(cache, json, base.resolve(upgrade.id().getNamespace() + "/" + folder + "/" + upgrade.id().getPath() + ".json")));
DataProvider.saveStable(cache, json, base.resolve(upgrade.id().getNamespace() + "/" + folder + "/" + upgrade.id().getPath() + ".json"));
} catch (IOException e) {
LOGGER.error("Failed to save {} {}", name, upgrade.id(), e);
}
try { try {
var result = upgrade.serialiser().fromJson(upgrade.id(), json); var result = upgrade.serialiser().fromJson(upgrade.id(), json);
@ -130,6 +129,7 @@ public final void run(CachedOutput cache) throws IOException {
}); });
this.upgrades = upgrades; this.upgrades = upgrades;
return Util.sequenceFailFast(futures);
} }
@Override @Override

View File

@ -29,7 +29,7 @@
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceProvider;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -177,7 +177,7 @@ public interface BlockEntityRenderRegistry {
<T extends BlockEntity> void register(BlockEntityType<? extends T> type, BlockEntityRendererProvider<T> provider); <T extends BlockEntity> void register(BlockEntityType<? extends T> type, BlockEntityRendererProvider<T> provider);
} }
public static void registerShaders(ResourceManager resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException { public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
RenderTypes.registerShaders(resources, load); RenderTypes.registerShaders(resources, load);
} }

View File

@ -77,19 +77,12 @@ protected final TerminalWidget getTerminal() {
@Override @Override
protected void init() { protected void init() {
super.init(); super.init();
minecraft.keyboardHandler.setSendRepeatsToGui(true);
terminal = addRenderableWidget(createTerminal()); terminal = addRenderableWidget(createTerminal());
ComputerSidebar.addButtons(this, menu::isOn, input, this::addRenderableWidget, leftPos, topPos + sidebarYOffset); ComputerSidebar.addButtons(menu::isOn, input, this::addRenderableWidget, leftPos, topPos + sidebarYOffset);
setFocused(terminal); setFocused(terminal);
} }
@Override
public void removed() {
super.removed();
minecraft.keyboardHandler.setSendRepeatsToGui(false);
}
@Override @Override
public void containerTick() { public void containerTick() {
super.containerTick(); super.containerTick();

View File

@ -34,7 +34,7 @@ public void renderBg(PoseStack stack, float partialTicks, int mouseX, int mouseY
// Draw a border around the terminal // Draw a border around the terminal
var terminal = getTerminal(); var terminal = getTerminal();
ComputerBorderRenderer.render( ComputerBorderRenderer.render(
stack.last().pose(), ComputerBorderRenderer.getTexture(family), terminal.x, terminal.y, getBlitOffset(), stack.last().pose(), ComputerBorderRenderer.getTexture(family), terminal.getX(), terminal.getY(), getBlitOffset(),
FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
); );
ComputerSidebar.renderBackground(stack, leftPos, topPos + sidebarYOffset); ComputerSidebar.renderBackground(stack, leftPos, topPos + sidebarYOffset);

View File

@ -46,7 +46,6 @@ protected void init() {
KeyMapping.releaseAll(); KeyMapping.releaseAll();
super.init(); super.init();
minecraft.keyboardHandler.setSendRepeatsToGui(true);
terminal = addWidget(new TerminalWidget(terminalData, new ClientInputHandler(menu), 0, 0)); terminal = addWidget(new TerminalWidget(terminalData, new ClientInputHandler(menu), 0, 0));
terminal.visible = false; terminal.visible = false;
@ -54,12 +53,6 @@ protected void init() {
setFocused(terminal); setFocused(terminal);
} }
@Override
public final void removed() {
super.removed();
minecraft.keyboardHandler.setSendRepeatsToGui(false);
}
@Override @Override
public final void tick() { public final void tick() {
super.tick(); super.tick();

View File

@ -74,8 +74,7 @@ public void init() {
var x = (width - buttonWidth) / 2; var x = (width - buttonWidth) / 2;
for (var button : buttons) { for (var button : buttons) {
button.x = x; button.setPosition(x, y + textHeight);
button.y = y + textHeight;
addRenderableWidget(button); addRenderableWidget(button);
x += BUTTON_WIDTH + PADDING; x += BUTTON_WIDTH + PADDING;
@ -105,11 +104,7 @@ public void onClose() {
} }
public static AbstractWidget newButton(Component component, Button.OnPress clicked) { public static AbstractWidget newButton(Component component, Button.OnPress clicked) {
return new Button(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, component, clicked); return Button.builder(component, clicked).bounds(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT).build();
}
public void disable() {
for (var widget : buttons) widget.active = false;
} }
public Screen getOriginalScreen() { public Screen getOriginalScreen() {

View File

@ -7,17 +7,15 @@
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.gui.widgets.DynamicImageButton.HintedMessage;
import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.InputHandler; import dan200.computercraft.shared.computer.core.InputHandler;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu; import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -44,29 +42,29 @@ public final class ComputerSidebar {
private ComputerSidebar() { private ComputerSidebar() {
} }
public static void addButtons(Screen screen, BooleanSupplier isOn, InputHandler input, Consumer<AbstractWidget> add, int x, int y) { public static void addButtons(BooleanSupplier isOn, InputHandler input, Consumer<AbstractWidget> add, int x, int y) {
x += CORNERS_BORDER + 1; x += CORNERS_BORDER + 1;
y += CORNERS_BORDER + ICON_MARGIN; y += CORNERS_BORDER + ICON_MARGIN;
var turnOn = new HintedMessage(
Component.translatable("gui.computercraft.tooltip.turn_off"),
Component.translatable("gui.computercraft.tooltip.turn_off.key")
);
var turnOff = new HintedMessage(Component.translatable("gui.computercraft.tooltip.turn_on"), (Component) null);
add.accept(new DynamicImageButton( add.accept(new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> isOn.getAsBoolean() ? 15 : 1, 1, ICON_TEX_Y_DIFF, x, y, ICON_WIDTH, ICON_HEIGHT, () -> isOn.getAsBoolean() ? 15 : 1, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer(isOn, input), TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer(isOn, input),
() -> isOn.getAsBoolean() ? Arrays.asList( () -> isOn.getAsBoolean() ? turnOff : turnOn
Component.translatable("gui.computercraft.tooltip.turn_off"),
Component.translatable("gui.computercraft.tooltip.turn_off.key").withStyle(ChatFormatting.GRAY)
) : Collections.singletonList(
Component.translatable("gui.computercraft.tooltip.turn_on")
)
)); ));
y += ICON_HEIGHT + ICON_MARGIN * 2; y += ICON_HEIGHT + ICON_MARGIN * 2;
add.accept(new DynamicImageButton( add.accept(new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> input.queueEvent("terminate"), TEXTURE, TEX_SIZE, TEX_SIZE, b -> input.queueEvent("terminate"),
Arrays.asList( new HintedMessage(
Component.translatable("gui.computercraft.tooltip.terminate"), Component.translatable("gui.computercraft.tooltip.terminate"),
Component.translatable("gui.computercraft.tooltip.terminate.key").withStyle(ChatFormatting.GRAY) Component.translatable("gui.computercraft.tooltip.terminate.key")
) )
)); ));
} }

View File

@ -7,12 +7,13 @@
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import java.util.List; import javax.annotation.Nullable;
import java.util.function.IntSupplier; import java.util.function.IntSupplier;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -21,42 +22,39 @@
* dynamically. * dynamically.
*/ */
public class DynamicImageButton extends Button { public class DynamicImageButton extends Button {
private final Screen screen;
private final ResourceLocation texture; private final ResourceLocation texture;
private final IntSupplier xTexStart; private final IntSupplier xTexStart;
private final int yTexStart; private final int yTexStart;
private final int yDiffTex; private final int yDiffTex;
private final int textureWidth; private final int textureWidth;
private final int textureHeight; private final int textureHeight;
private final Supplier<List<Component>> tooltip; private final Supplier<HintedMessage> message;
public DynamicImageButton( public DynamicImageButton(
Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex,
ResourceLocation texture, int textureWidth, int textureHeight, ResourceLocation texture, int textureWidth, int textureHeight,
OnPress onPress, List<Component> tooltip OnPress onPress, HintedMessage message
) { ) {
this( this(
screen, x, y, width, height, () -> xTexStart, yTexStart, yDiffTex, x, y, width, height, () -> xTexStart, yTexStart, yDiffTex,
texture, textureWidth, textureHeight, texture, textureWidth, textureHeight,
onPress, () -> tooltip onPress, () -> message
); );
} }
public DynamicImageButton( public DynamicImageButton(
Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex,
ResourceLocation texture, int textureWidth, int textureHeight, ResourceLocation texture, int textureWidth, int textureHeight,
OnPress onPress, Supplier<List<Component>> tooltip OnPress onPress, Supplier<HintedMessage> message
) { ) {
super(x, y, width, height, Component.empty(), onPress); super(x, y, width, height, Component.empty(), onPress, DEFAULT_NARRATION);
this.screen = screen;
this.textureWidth = textureWidth; this.textureWidth = textureWidth;
this.textureHeight = textureHeight; this.textureHeight = textureHeight;
this.xTexStart = xTexStart; this.xTexStart = xTexStart;
this.yTexStart = yTexStart; this.yTexStart = yTexStart;
this.yDiffTex = yDiffTex; this.yDiffTex = yDiffTex;
this.texture = texture; this.texture = texture;
this.tooltip = tooltip; this.message = message;
} }
@Override @Override
@ -67,23 +65,29 @@ public void renderButton(PoseStack stack, int mouseX, int mouseY, float partialT
var yTex = yTexStart; var yTex = yTexStart;
if (isHoveredOrFocused()) yTex += yDiffTex; if (isHoveredOrFocused()) yTex += yDiffTex;
blit(stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight); blit(stack, getX(), getY(), xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight);
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
if (isHovered) renderToolTip(stack, mouseX, mouseY);
} }
@Override @Override
public Component getMessage() { public Component getMessage() {
var tooltip = this.tooltip.get(); return message.get().message;
return tooltip.isEmpty() ? Component.empty() : tooltip.get(0);
} }
@Override @Override
public void renderToolTip(PoseStack stack, int mouseX, int mouseY) { public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
var tooltip = this.tooltip.get(); setTooltip(message.get().tooltip());
if (!tooltip.isEmpty()) { super.render(stack, mouseX, mouseY, partialTicks);
screen.renderComponentTooltip(stack, tooltip, mouseX, mouseY); }
public record HintedMessage(Component message, Tooltip tooltip) {
public HintedMessage(Component message, @Nullable Component hint) {
this(
message,
hint == null
? Tooltip.create(message)
: Tooltip.create(Component.empty().append(message).append("\n").append(hint.copy().withStyle(ChatFormatting.GRAY)), hint)
);
} }
} }
} }

View File

@ -14,6 +14,7 @@
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@ -26,6 +27,8 @@
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
public class TerminalWidget extends AbstractWidget { public class TerminalWidget extends AbstractWidget {
private static final Component DESCRIPTION = Component.translatable("gui.computercraft.terminal");
private static final float TERMINATE_TIME = 0.5f; private static final float TERMINATE_TIME = 0.5f;
private final Terminal terminal; private final Terminal terminal;
@ -48,7 +51,7 @@ public class TerminalWidget extends AbstractWidget {
private final BitSet keysDown = new BitSet(256); private final BitSet keysDown = new BitSet(256);
public TerminalWidget(Terminal terminal, InputHandler computer, int x, int y) { public TerminalWidget(Terminal terminal, InputHandler computer, int x, int y) {
super(x, y, terminal.getWidth() * FONT_WIDTH + MARGIN * 2, terminal.getHeight() * FONT_HEIGHT + MARGIN * 2, Component.empty()); super(x, y, terminal.getWidth() * FONT_WIDTH + MARGIN * 2, terminal.getHeight() * FONT_HEIGHT + MARGIN * 2, DESCRIPTION);
this.terminal = terminal; this.terminal = terminal;
this.computer = computer; this.computer = computer;
@ -278,8 +281,8 @@ public void render(PoseStack transform, int mouseX, int mouseY, float partialTic
} }
@Override @Override
public void updateNarration(NarrationElementOutput output) { protected void updateWidgetNarration(NarrationElementOutput output) {
// I'm not sure what the right option is here. output.add(NarratedElementType.TITLE, getMessage());
} }
public static int getWidth(int termWidth) { public static int getWidth(int termWidth) {

View File

@ -7,12 +7,12 @@
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
public class ComputerBorderRenderer { public class ComputerBorderRenderer {
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_normal.png"); public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_normal.png");

View File

@ -6,7 +6,7 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f; import com.mojang.math.Axis;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
@ -66,7 +66,7 @@ private void renderItemFirstPersonSide(PoseStack transform, MultiBufferSource re
// If the player is not invisible then render a single arm // If the player is not invisible then render a single arm
if (!minecraft.player.isInvisible()) { if (!minecraft.player.isInvisible()) {
transform.pushPose(); transform.pushPose();
transform.mulPose(Vector3f.ZP.rotationDegrees(offset * 10f)); transform.mulPose(Axis.ZP.rotationDegrees(offset * 10f));
minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, render, combinedLight, equipProgress, swingProgress, side); minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, render, combinedLight, equipProgress, swingProgress, side);
transform.popPose(); transform.popPose();
} }
@ -81,8 +81,8 @@ private void renderItemFirstPersonSide(PoseStack transform, MultiBufferSource re
var f4 = 0.4f * Mth.sin(f1 * ((float) Math.PI * 2f)); var f4 = 0.4f * Mth.sin(f1 * ((float) Math.PI * 2f));
var f5 = -0.3f * Mth.sin(swingProgress * (float) Math.PI); var f5 = -0.3f * Mth.sin(swingProgress * (float) Math.PI);
transform.translate(offset * f3, f4 - 0.3f * f2, f5); transform.translate(offset * f3, f4 - 0.3f * f2, f5);
transform.mulPose(Vector3f.XP.rotationDegrees(f2 * -45f)); transform.mulPose(Axis.XP.rotationDegrees(f2 * -45f));
transform.mulPose(Vector3f.YP.rotationDegrees(offset * f2 * -30f)); transform.mulPose(Axis.YP.rotationDegrees(offset * f2 * -30f));
renderItem(transform, render, stack, combinedLight); renderItem(transform, render, stack, combinedLight);
@ -114,17 +114,17 @@ private void renderItemFirstPersonCenter(PoseStack transform, MultiBufferSource
var pitchAngle = renderer.calculateMapTilt(pitch); var pitchAngle = renderer.calculateMapTilt(pitch);
transform.translate(0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f); transform.translate(0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f);
transform.mulPose(Vector3f.XP.rotationDegrees(pitchAngle * -85.0f)); transform.mulPose(Axis.XP.rotationDegrees(pitchAngle * -85.0f));
if (!minecraft.player.isInvisible()) { if (!minecraft.player.isInvisible()) {
transform.pushPose(); transform.pushPose();
transform.mulPose(Vector3f.YP.rotationDegrees(90.0F)); transform.mulPose(Axis.YP.rotationDegrees(90.0F));
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.RIGHT); renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.RIGHT);
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.LEFT); renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.LEFT);
transform.popPose(); transform.popPose();
} }
var rX = Mth.sin(swingRt * (float) Math.PI); var rX = Mth.sin(swingRt * (float) Math.PI);
transform.mulPose(Vector3f.XP.rotationDegrees(rX * 20.0F)); transform.mulPose(Axis.XP.rotationDegrees(rX * 20.0F));
transform.scale(2.0F, 2.0F, 2.0F); transform.scale(2.0F, 2.0F, 2.0F);
renderItem(transform, render, stack, combinedLight); renderItem(transform, render, stack, combinedLight);

View File

@ -6,8 +6,7 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f; import com.mojang.math.Axis;
import com.mojang.math.Vector3f;
import dan200.computercraft.client.pocket.ClientPocketComputers; import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.util.Colour; import dan200.computercraft.core.util.Colour;
@ -15,6 +14,7 @@
import dan200.computercraft.shared.pocket.items.PocketComputerItem; import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4f;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*; import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
@ -43,8 +43,8 @@ protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, I
// Setup various transformations. Note that these are partially adapted from the corresponding method // Setup various transformations. Note that these are partially adapted from the corresponding method
// in ItemRenderer // in ItemRenderer
transform.pushPose(); transform.pushPose();
transform.mulPose(Vector3f.YP.rotationDegrees(180f)); transform.mulPose(Axis.YP.rotationDegrees(180f));
transform.mulPose(Vector3f.ZP.rotationDegrees(180f)); transform.mulPose(Axis.ZP.rotationDegrees(180f));
transform.scale(0.5f, 0.5f, 0.5f); transform.scale(0.5f, 0.5f, 0.5f);
var scale = 0.75f / Math.max(width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT); var scale = 0.75f / Math.max(width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT);

View File

@ -6,7 +6,7 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f; import com.mojang.math.Axis;
import dan200.computercraft.shared.media.items.PrintoutItem; import dan200.computercraft.shared.media.items.PrintoutItem;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -30,7 +30,7 @@ private PrintoutItemRenderer() {
@Override @Override
protected void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) { protected void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
transform.mulPose(Vector3f.XP.rotationDegrees(180f)); transform.mulPose(Axis.XP.rotationDegrees(180f));
transform.scale(0.42f, 0.42f, -0.42f); transform.scale(0.42f, 0.42f, -0.42f);
transform.translate(-0.5f, -0.48f, 0.0f); transform.translate(-0.5f, -0.48f, 0.0f);
@ -42,7 +42,7 @@ public static void onRenderInFrame(PoseStack transform, MultiBufferSource render
// Move a little bit forward to ensure we're not clipping with the frame // Move a little bit forward to ensure we're not clipping with the frame
transform.translate(0.0f, 0.0f, -0.001f); transform.translate(0.0f, 0.0f, -0.001f);
transform.mulPose(Vector3f.ZP.rotationDegrees(180f)); transform.mulPose(Axis.ZP.rotationDegrees(180f));
transform.scale(0.95f, 0.95f, -0.95f); transform.scale(0.95f, 0.95f, -0.95f);
transform.translate(-0.5f, -0.5f, 0.0f); transform.translate(-0.5f, -0.5f, 0.0f);

View File

@ -7,11 +7,11 @@
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Palette; import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import org.joml.Matrix4f;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.PrintoutItem.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.PrintoutItem.LINES_PER_PAGE;

View File

@ -15,7 +15,7 @@
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceProvider;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
@ -60,7 +60,7 @@ public static ShaderInstance getTerminalShader() {
return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered"); return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered");
} }
public static void registerShaders(ResourceManager resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException { public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
load.accept( load.accept(
new MonitorTextureBufferShader( new MonitorTextureBufferShader(
resources, resources,

View File

@ -7,8 +7,8 @@
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
import com.mojang.math.Vector3f;
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.client.platform.ClientPlatformHelper; import dan200.computercraft.client.platform.ClientPlatformHelper;
@ -37,8 +37,8 @@
import java.util.List; import java.util.List;
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> { public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation("computercraft:turtle_normal", "inventory"); private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_normal", "inventory");
private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation("computercraft:turtle_advanced", "inventory"); private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_advanced", "inventory");
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_colour"); private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
private static final ResourceLocation ELF_OVERLAY_MODEL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_elf_overlay"); private static final ResourceLocation ELF_OVERLAY_MODEL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_elf_overlay");
@ -96,7 +96,7 @@ public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack trans
transform.translate(offset.x, offset.y, offset.z); transform.translate(offset.x, offset.y, offset.z);
transform.translate(0.5f, 0.5f, 0.5f); transform.translate(0.5f, 0.5f, 0.5f);
transform.mulPose(Vector3f.YP.rotationDegrees(180.0f - yaw)); transform.mulPose(Axis.YP.rotationDegrees(180.0f - yaw));
if (label != null && (label.equals("Dinnerbone") || label.equals("Grumm"))) { if (label != null && (label.equals("Dinnerbone") || label.equals("Grumm"))) {
// Flip the model // Flip the model
transform.scale(1.0f, -1.0f, 1.0f); transform.scale(1.0f, -1.0f, 1.0f);
@ -131,7 +131,7 @@ private void renderUpgrade(PoseStack transform, VertexConsumer renderer, int lig
var toolAngle = turtle.getToolRenderAngle(side, f); var toolAngle = turtle.getToolRenderAngle(side, f);
transform.translate(0.0f, 0.5f, 0.5f); transform.translate(0.0f, 0.5f, 0.5f);
transform.mulPose(Vector3f.XN.rotationDegrees(toolAngle)); transform.mulPose(Axis.XN.rotationDegrees(toolAngle));
transform.translate(0.0f, -0.5f, -0.5f); transform.translate(0.0f, -0.5f, -0.5f);
var model = TurtleUpgradeModellers.getModel(upgrade, turtle.getAccess(), side); var model = TurtleUpgradeModellers.getModel(upgrade, turtle.getAccess(), side);

View File

@ -12,9 +12,7 @@
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexBuffer; import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f; import com.mojang.math.Axis;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.integration.ShaderMod; import dan200.computercraft.client.integration.ShaderMod;
import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.RenderTypes;
@ -28,10 +26,11 @@
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity; import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.Util;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
@ -56,7 +55,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
*/ */
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1); private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
private static final Matrix3f IDENTITY_NORMAL = Util.make(new Matrix3f(), Matrix3f::setIdentity); private static final Matrix3f IDENTITY_NORMAL = new Matrix3f().identity();
private static @Nullable ByteBuffer backingBuffer; private static @Nullable ByteBuffer backingBuffer;
@ -100,8 +99,8 @@ public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack tra
originPos.getZ() - monitorPos.getZ() + 0.5 originPos.getZ() - monitorPos.getZ() + 0.5
); );
transform.mulPose(Vector3f.YN.rotationDegrees(yaw)); transform.mulPose(Axis.YN.rotationDegrees(yaw));
transform.mulPose(Vector3f.XP.rotationDegrees(pitch)); transform.mulPose(Axis.XP.rotationDegrees(pitch));
transform.translate( transform.translate(
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN, -0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
origin.getHeight() - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0, origin.getHeight() - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,

View File

@ -7,14 +7,14 @@
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity; import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import java.util.EnumSet; import java.util.EnumSet;

View File

@ -7,14 +7,14 @@
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.core.terminal.Palette; import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour; import dan200.computercraft.core.util.Colour;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
@ -197,13 +197,13 @@ public static void drawTerminal(
// Render the foreground with a slight offset. By calling .translate() on the matrix itself, we're translating // Render the foreground with a slight offset. By calling .translate() on the matrix itself, we're translating
// in screen space, rather than in model/view space. // in screen space, rather than in model/view space.
// It's definitely not perfect, but better than z fighting! // It's definitely not perfect, but better than z fighting!
var transformBackup = emitter.poseMatrix().copy(); var transformBackup = new Matrix4f(emitter.poseMatrix());
emitter.poseMatrix().translate(new Vector3f(0, 0, Z_OFFSET)); emitter.poseMatrix().translate(new Vector3f(0, 0, Z_OFFSET));
drawTerminalForeground(emitter, x, y, terminal); drawTerminalForeground(emitter, x, y, terminal);
drawCursor(emitter, x, y, terminal); drawCursor(emitter, x, y, terminal);
emitter.poseMatrix().load(transformBackup); emitter.poseMatrix().set(transformBackup);
} }
public static void drawEmptyTerminal(QuadEmitter emitter, float x, float y, float width, float height) { public static void drawEmptyTerminal(QuadEmitter emitter, float x, float y, float width, float height) {

View File

@ -9,8 +9,8 @@
import com.mojang.blaze3d.vertex.BufferUploader; import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.VertexBuffer; import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Matrix4f;
import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.client.renderer.ShaderInstance;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C; import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45C; import org.lwjgl.opengl.GL45C;

View File

@ -6,15 +6,15 @@
package dan200.computercraft.mixin.client; package dan200.computercraft.mixin.client;
import dan200.computercraft.client.ClientHooks; import dan200.computercraft.client.ClientHooks;
import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.multiplayer.ClientPacketListener;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LocalPlayer.class) @Mixin(ClientPacketListener.class)
class LocalPlayerMixin { class ClientPacketListenerMixin {
@Inject(method = "commandUnsigned", at = @At("HEAD"), cancellable = true) @Inject(method = "sendUnsignedCommand", at = @At("HEAD"), cancellable = true)
void commandUnsigned(String message, CallbackInfoReturnable<Boolean> ci) { void commandUnsigned(String message, CallbackInfoReturnable<Boolean> ci) {
if (ClientHooks.onChatMessage(message)) ci.setReturnValue(true); if (ClientHooks.onChatMessage(message)) ci.setReturnValue(true);
} }

View File

@ -7,7 +7,7 @@
"defaultRequire": 1 "defaultRequire": 1
}, },
"client": [ "client": [
"LocalPlayerMixin" "ClientPacketListenerMixin"
], ],
"refmap": "client-computercraft.refmap.json" "refmap": "client-computercraft.refmap.json"
} }

View File

@ -5,62 +5,50 @@
*/ */
package dan200.computercraft.data; package dan200.computercraft.data;
import com.mojang.datafixers.util.Pair;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.loot.LootTableProvider.SubProviderEntry;
import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.models.ItemModelGenerators;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.tags.TagsProvider; import net.minecraft.data.tags.TagsProvider;
import net.minecraft.resources.ResourceLocation;
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 net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
/** /**
* All data providers for ComputerCraft. We require a mod-loader abstraction {@link DataProviders.GeneratorFactory} to * All data providers for ComputerCraft. We require a mod-loader abstraction {@link GeneratorSink} (instead of
* handle the slight differences between how Forge and Fabric expose Minecraft's data providers. * {@link PackOutput})to handle the slight differences between how Forge and Fabric expose Minecraft's data providers.
*/ */
public final class DataProviders { public final class DataProviders {
private DataProviders() { private DataProviders() {
} }
public static void add(DataGenerator generator, GeneratorFactory generators, boolean includeServer, boolean includeClient) { public static void add(GeneratorSink generator) {
var turtleUpgrades = new TurtleUpgradeProvider(generator); var turtleUpgrades = generator.add(TurtleUpgradeProvider::new);
var pocketUpgrades = new PocketUpgradeProvider(generator); var pocketUpgrades = generator.add(PocketUpgradeProvider::new);
generator.add(out -> new RecipeProvider(out, turtleUpgrades, pocketUpgrades));
generator.addProvider(includeServer, turtleUpgrades); var blockTags = generator.blockTags(TagProvider::blockTags);
generator.addProvider(includeServer, pocketUpgrades); generator.itemTags(TagProvider::itemTags, blockTags);
generator.addProvider(includeServer, generators.recipes(new RecipeProvider(turtleUpgrades, pocketUpgrades)::addRecipes));
var blockTags = generators.blockTags(TagProvider::blockTags); generator.lootTable(LootTableProvider.getTables());
generator.addProvider(includeServer, blockTags);
generator.addProvider(includeServer, generators.itemTags(TagProvider::itemTags, blockTags));
for (var provider : generators.lootTable(LootTableProvider.getTables())) { generator.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels);
generator.addProvider(includeServer, provider);
}
generator.addProvider(includeClient, generators.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels)); generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades));
generator.addProvider(includeServer, new LanguageProvider(generator, turtleUpgrades, pocketUpgrades));
} }
interface GeneratorFactory { interface GeneratorSink {
DataProvider recipes(Consumer<Consumer<FinishedRecipe>> recipes); <T extends DataProvider> T add(DataProvider.Factory<T> factory);
List<DataProvider> lootTable(List<Pair<Supplier<Consumer<BiConsumer<ResourceLocation, LootTable.Builder>>>, LootContextParamSet>> tables); void lootTable(List<SubProviderEntry> tables);
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);
DataProvider models(Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items); void models(Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items);
} }
} }

View File

@ -18,35 +18,35 @@
import dan200.computercraft.shared.computer.metrics.basic.Aggregate; import dan200.computercraft.shared.computer.metrics.basic.Aggregate;
import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric; import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric;
import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.data.CachedOutput; import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
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 net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream; import java.util.stream.Stream;
public final class LanguageProvider implements DataProvider { public final class LanguageProvider implements DataProvider {
private final DataGenerator generator; private final PackOutput output;
private final TurtleUpgradeDataProvider turtleUpgrades; private final TurtleUpgradeDataProvider turtleUpgrades;
private final PocketUpgradeDataProvider pocketUpgrades; private final PocketUpgradeDataProvider pocketUpgrades;
private final Map<String, String> translations = new HashMap<>(); private final Map<String, String> translations = new HashMap<>();
public LanguageProvider(DataGenerator generator, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) { public LanguageProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
this.generator = generator; this.output = output;
this.turtleUpgrades = turtleUpgrades; this.turtleUpgrades = turtleUpgrades;
this.pocketUpgrades = pocketUpgrades; this.pocketUpgrades = pocketUpgrades;
} }
@Override @Override
public void run(CachedOutput cachedOutput) throws IOException { public CompletableFuture<?> run(CachedOutput cachedOutput) {
addTranslations(); addTranslations();
getExpectedKeys().forEach(x -> { getExpectedKeys().forEach(x -> {
if (!translations.containsKey(x)) throw new IllegalStateException("No translation for " + x); if (!translations.containsKey(x)) throw new IllegalStateException("No translation for " + x);
@ -54,7 +54,7 @@ public void run(CachedOutput cachedOutput) throws IOException {
var json = new JsonObject(); var json = new JsonObject();
for (var pair : translations.entrySet()) json.addProperty(pair.getKey(), pair.getValue()); for (var pair : translations.entrySet()) json.addProperty(pair.getKey(), pair.getValue());
DataProvider.saveStable(cachedOutput, json, generator.getOutputFolder().resolve("assets/" + ComputerCraftAPI.MOD_ID + "/lang/en_us.json")); return DataProvider.saveStable(cachedOutput, json, output.getOutputFolder().resolve("assets/" + ComputerCraftAPI.MOD_ID + "/lang/en_us.json"));
} }
@Override @Override
@ -190,6 +190,7 @@ private void addTranslations() {
add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.COUNT.id(), "%s (count)"); add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.COUNT.id(), "%s (count)");
// Additional UI elements // Additional UI elements
add("gui.computercraft.terminal", "Computer terminal");
add("gui.computercraft.tooltip.copy", "Copy to clipboard"); add("gui.computercraft.tooltip.copy", "Copy to clipboard");
add("gui.computercraft.tooltip.computer_id", "Computer ID: %s"); add("gui.computercraft.tooltip.computer_id", "Computer ID: %s");
add("gui.computercraft.tooltip.disk_id", "Disk ID: %s"); add("gui.computercraft.tooltip.disk_id", "Disk ID: %s");
@ -266,11 +267,11 @@ private void addTranslations() {
private Stream<String> getExpectedKeys() { private Stream<String> getExpectedKeys() {
return Stream.of( return Stream.of(
Registries.BLOCKS.stream() RegistryWrappers.BLOCKS.stream()
.filter(x -> Registries.BLOCKS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID)) .filter(x -> RegistryWrappers.BLOCKS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Block::getDescriptionId), .map(Block::getDescriptionId),
Registries.ITEMS.stream() RegistryWrappers.ITEMS.stream()
.filter(x -> Registries.ITEMS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID)) .filter(x -> RegistryWrappers.ITEMS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Item::getDescriptionId), .map(Item::getDescriptionId),
turtleUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective), turtleUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),
pocketUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective), pocketUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),

View File

@ -5,7 +5,6 @@
*/ */
package dan200.computercraft.data; package dan200.computercraft.data;
import com.mojang.datafixers.util.Pair;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.CommonHooks; import dan200.computercraft.shared.CommonHooks;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
@ -15,6 +14,7 @@
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock; import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
import net.minecraft.advancements.critereon.StatePropertiesPredicate; import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.data.loot.LootTableProvider.SubProviderEntry;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.storage.loot.LootPool; import net.minecraft.world.level.storage.loot.LootPool;
@ -23,7 +23,6 @@
import net.minecraft.world.level.storage.loot.entries.LootItem; import net.minecraft.world.level.storage.loot.entries.LootItem;
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
import net.minecraft.world.level.storage.loot.functions.CopyNameFunction; import net.minecraft.world.level.storage.loot.functions.CopyNameFunction;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.predicates.AlternativeLootItemCondition; import net.minecraft.world.level.storage.loot.predicates.AlternativeLootItemCondition;
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition; import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition;
@ -33,14 +32,13 @@
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
class LootTableProvider { class LootTableProvider {
public static List<Pair<Supplier<Consumer<BiConsumer<ResourceLocation, LootTable.Builder>>>, LootContextParamSet>> getTables() { public static List<SubProviderEntry> getTables() {
return List.of( return List.of(
Pair.of(() -> LootTableProvider::registerBlocks, LootContextParamSets.BLOCK), new SubProviderEntry(() -> LootTableProvider::registerBlocks, LootContextParamSets.BLOCK),
Pair.of(() -> LootTableProvider::registerGeneric, LootContextParamSets.ALL_PARAMS) new SubProviderEntry(() -> LootTableProvider::registerGeneric, LootContextParamSets.ALL_PARAMS)
); );
} }

View File

@ -6,10 +6,11 @@
package dan200.computercraft.data; package dan200.computercraft.data;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.Util;
import net.minecraft.data.CachedOutput; import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.models.ItemModelGenerators;
import net.minecraft.data.models.blockstates.BlockStateGenerator; import net.minecraft.data.models.blockstates.BlockStateGenerator;
@ -18,14 +19,10 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashMap; import java.util.*;
import java.util.HashSet; import java.util.concurrent.CompletableFuture;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -37,24 +34,22 @@
* Please don't sue me Mojang. Or at least make these changes to vanilla before doing so! * Please don't sue me Mojang. Or at least make these changes to vanilla before doing so!
*/ */
public class ModelProvider implements DataProvider { public class ModelProvider implements DataProvider {
private static final Logger LOG = LoggerFactory.getLogger(ModelProvider.class); private final PackOutput.PathProvider blockStatePath;
private final PackOutput.PathProvider modelPath;
private final DataGenerator.PathProvider blockStatePath;
private final DataGenerator.PathProvider modelPath;
private final Consumer<BlockModelGenerators> blocks; private final Consumer<BlockModelGenerators> blocks;
private final Consumer<ItemModelGenerators> items; private final Consumer<ItemModelGenerators> items;
public ModelProvider(DataGenerator generator, Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items) { public ModelProvider(PackOutput output, Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items) {
blockStatePath = generator.createPathProvider(DataGenerator.Target.RESOURCE_PACK, "blockstates"); blockStatePath = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "blockstates");
modelPath = generator.createPathProvider(DataGenerator.Target.RESOURCE_PACK, "models"); modelPath = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "models");
this.blocks = blocks; this.blocks = blocks;
this.items = items; this.items = items;
} }
@Override @Override
public void run(CachedOutput output) { public CompletableFuture<?> run(CachedOutput output) {
Map<Block, BlockStateGenerator> blockStates = new HashMap<>(); Map<Block, BlockStateGenerator> blockStates = new HashMap<>();
Consumer<BlockStateGenerator> addBlockState = generator -> { Consumer<BlockStateGenerator> addBlockState = generator -> {
var block = generator.getBlock(); var block = generator.getBlock();
@ -73,7 +68,7 @@ public void run(CachedOutput output) {
blocks.accept(new BlockModelGenerators(addBlockState, addModel, explicitItems::add)); blocks.accept(new BlockModelGenerators(addBlockState, addModel, explicitItems::add));
items.accept(new ItemModelGenerators(addModel)); items.accept(new ItemModelGenerators(addModel));
for (var block : Registries.BLOCKS) { for (var block : RegistryWrappers.BLOCKS) {
if (!blockStates.containsKey(block)) continue; if (!blockStates.containsKey(block)) continue;
var item = Item.BY_BLOCK.get(block); var item = Item.BY_BLOCK.get(block);
@ -85,18 +80,17 @@ public void run(CachedOutput output) {
} }
} }
saveCollection(output, blockStates, x -> blockStatePath.json(Registries.BLOCKS.getKey(x))); List<CompletableFuture<?>> futures = new ArrayList<>();
saveCollection(output, models, modelPath::json); saveCollection(output, futures, blockStates, x -> blockStatePath.json(RegistryWrappers.BLOCKS.getKey(x)));
saveCollection(output, futures, models, modelPath::json);
return Util.sequenceFailFast(futures);
} }
private <T> void saveCollection(CachedOutput output, Map<T, ? extends Supplier<JsonElement>> items, Function<T, Path> getLocation) { private <T> void saveCollection(CachedOutput output, List<CompletableFuture<?>> futures, Map<T, ? extends Supplier<JsonElement>> items, Function<T, Path> getLocation) {
for (Map.Entry<T, ? extends Supplier<JsonElement>> entry : items.entrySet()) { for (Map.Entry<T, ? extends Supplier<JsonElement>> entry : items.entrySet()) {
var path = getLocation.apply(entry.getKey()); var path = getLocation.apply(entry.getKey());
try {
DataProvider.saveStable(output, entry.getValue().get(), path); futures.add(DataProvider.saveStable(output, entry.getValue().get(), path));
} catch (Exception exception) {
LOG.error("Couldn't save {}", path, exception);
}
} }
} }

View File

@ -8,7 +8,7 @@
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider; import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser; import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import net.minecraft.data.DataGenerator; import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -17,8 +17,8 @@
import static dan200.computercraft.shared.ModRegistry.PocketUpgradeSerialisers; import static dan200.computercraft.shared.ModRegistry.PocketUpgradeSerialisers;
class PocketUpgradeProvider extends PocketUpgradeDataProvider { class PocketUpgradeProvider extends PocketUpgradeDataProvider {
PocketUpgradeProvider(DataGenerator generator) { PocketUpgradeProvider(PackOutput output) {
super(generator); super(output);
} }
@Override @Override

View File

@ -15,16 +15,14 @@
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.RecipeIngredients; import dan200.computercraft.shared.platform.RecipeIngredients;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import net.minecraft.advancements.critereon.InventoryChangeTrigger; import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.advancements.critereon.ItemPredicate; import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries;
import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.*;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.data.recipes.SpecialRecipeBuilder;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
@ -36,7 +34,7 @@
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
@ -46,17 +44,19 @@
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;
class RecipeProvider { 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 TurtleUpgradeDataProvider turtleUpgrades;
private final PocketUpgradeDataProvider pocketUpgrades; private final PocketUpgradeDataProvider pocketUpgrades;
RecipeProvider(TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) { RecipeProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
super(output);
this.turtleUpgrades = turtleUpgrades; this.turtleUpgrades = turtleUpgrades;
this.pocketUpgrades = pocketUpgrades; this.pocketUpgrades = pocketUpgrades;
} }
public void addRecipes(Consumer<FinishedRecipe> add) { @Override
public void buildRecipes(Consumer<FinishedRecipe> add) {
basicRecipes(add); basicRecipes(add);
diskColours(add); diskColours(add);
pocketUpgrades(add); pocketUpgrades(add);
@ -77,7 +77,7 @@ public void addRecipes(Consumer<FinishedRecipe> add) {
private void diskColours(Consumer<FinishedRecipe> add) { private void diskColours(Consumer<FinishedRecipe> add) {
for (var colour : Colour.VALUES) { for (var colour : Colour.VALUES) {
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.DISK.get()) .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.DISK.get())
.requires(ingredients.redstone()) .requires(ingredients.redstone())
.requires(Items.PAPER) .requires(Items.PAPER)
.requires(DyeItem.byColor(ofColour(colour))) .requires(DyeItem.byColor(ofColour(colour)))
@ -106,7 +106,7 @@ private void turtleUpgrades(Consumer<FinishedRecipe> add) {
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) { for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
var result = TurtleItemFactory.create(-1, null, -1, family, null, upgrade, -1, null); var result = TurtleItemFactory.create(-1, null, -1, family, null, upgrade, -1, null);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(result.getItem()) .shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId)) .group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId))
.pattern("#T") .pattern("#T")
.define('T', base.getItem()) .define('T', base.getItem())
@ -138,7 +138,7 @@ private void pocketUpgrades(Consumer<FinishedRecipe> add) {
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) { for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
var result = PocketComputerItemFactory.create(-1, null, -1, family, upgrade); var result = PocketComputerItemFactory.create(-1, null, -1, family, upgrade);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(result.getItem()) .shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId)) .group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId))
.pattern("#") .pattern("#")
.pattern("P") .pattern("P")
@ -158,7 +158,7 @@ private void pocketUpgrades(Consumer<FinishedRecipe> add) {
private void basicRecipes(Consumer<FinishedRecipe> add) { private void basicRecipes(Consumer<FinishedRecipe> add) {
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.CABLE.get(), 6) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.CABLE.get(), 6)
.pattern(" # ") .pattern(" # ")
.pattern("#R#") .pattern("#R#")
.pattern(" # ") .pattern(" # ")
@ -169,7 +169,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_NORMAL.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_NORMAL.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("#G#") .pattern("#G#")
@ -180,7 +180,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("#G#") .pattern("#G#")
@ -191,7 +191,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.COMPUTER_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.COMPUTER_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#C#") .pattern("#C#")
.pattern("# #") .pattern("# #")
@ -204,7 +204,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
); );
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_COMMAND.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_COMMAND.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("#G#") .pattern("#G#")
@ -215,7 +215,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_NORMAL.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_NORMAL.get())
.pattern("###") .pattern("###")
.pattern("#C#") .pattern("#C#")
.pattern("#I#") .pattern("#I#")
@ -226,7 +226,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.NORMAL))); .save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.NORMAL)));
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#C#") .pattern("#C#")
.pattern("#I#") .pattern("#I#")
@ -237,7 +237,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.ADVANCED))); .save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.ADVANCED)));
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#C#") .pattern("#C#")
.pattern(" B ") .pattern(" B ")
@ -251,7 +251,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
); );
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.DISK_DRIVE.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.DISK_DRIVE.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("#R#") .pattern("#R#")
@ -261,7 +261,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.MONITOR_NORMAL.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_NORMAL.get())
.pattern("###") .pattern("###")
.pattern("#G#") .pattern("#G#")
.pattern("###") .pattern("###")
@ -271,7 +271,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.MONITOR_ADVANCED.get(), 4) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_ADVANCED.get(), 4)
.pattern("###") .pattern("###")
.pattern("#G#") .pattern("#G#")
.pattern("###") .pattern("###")
@ -281,7 +281,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get())
.pattern("###") .pattern("###")
.pattern("#A#") .pattern("#A#")
.pattern("#G#") .pattern("#G#")
@ -293,7 +293,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#A#") .pattern("#A#")
.pattern("#G#") .pattern("#G#")
@ -305,7 +305,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#C#") .pattern("#C#")
.pattern("# #") .pattern("# #")
@ -318,7 +318,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
); );
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.PRINTER.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.PRINTER.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("#D#") .pattern("#D#")
@ -329,7 +329,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.SPEAKER.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.SPEAKER.get())
.pattern("###") .pattern("###")
.pattern("#N#") .pattern("#N#")
.pattern("#R#") .pattern("#R#")
@ -340,7 +340,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Items.WIRED_MODEM.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM.get())
.pattern("###") .pattern("###")
.pattern("#R#") .pattern("#R#")
.pattern("###") .pattern("###")
@ -351,18 +351,18 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(ModRegistry.Blocks.WIRED_MODEM_FULL.get()) .shapeless(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRED_MODEM_FULL.get())
.requires(ModRegistry.Items.WIRED_MODEM.get()) .requires(ModRegistry.Items.WIRED_MODEM.get())
.unlockedBy("has_modem", inventoryChange(WIRED_MODEM)) .unlockedBy("has_modem", inventoryChange(WIRED_MODEM))
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_from")); .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_from"));
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.WIRED_MODEM.get()) .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM.get())
.requires(ModRegistry.Blocks.WIRED_MODEM_FULL.get()) .requires(ModRegistry.Blocks.WIRED_MODEM_FULL.get())
.unlockedBy("has_modem", inventoryChange(WIRED_MODEM)) .unlockedBy("has_modem", inventoryChange(WIRED_MODEM))
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_to")); .save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_to"));
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get())
.pattern("###") .pattern("###")
.pattern("#E#") .pattern("#E#")
.pattern("###") .pattern("###")
@ -372,7 +372,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapedRecipeBuilder ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get()) .shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get())
.pattern("###") .pattern("###")
.pattern("#E#") .pattern("#E#")
.pattern("###") .pattern("###")
@ -383,7 +383,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add); .save(add);
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(Items.PLAYER_HEAD) .shapeless(RecipeCategory.DECORATIONS, Items.PLAYER_HEAD)
.requires(ingredients.head()) .requires(ingredients.head())
.requires(ModRegistry.Items.MONITOR_NORMAL.get()) .requires(ModRegistry.Items.MONITOR_NORMAL.get())
.unlockedBy("has_monitor", inventoryChange(ModRegistry.Items.MONITOR_NORMAL.get())) .unlockedBy("has_monitor", inventoryChange(ModRegistry.Items.MONITOR_NORMAL.get()))
@ -394,7 +394,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
); );
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(Items.PLAYER_HEAD) .shapeless(RecipeCategory.DECORATIONS, Items.PLAYER_HEAD)
.requires(ingredients.head()) .requires(ingredients.head())
.requires(ModRegistry.Items.COMPUTER_ADVANCED.get()) .requires(ModRegistry.Items.COMPUTER_ADVANCED.get())
.unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_ADVANCED.get())) .unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_ADVANCED.get()))
@ -405,14 +405,14 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
); );
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.PRINTED_PAGES.get()) .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.PRINTED_PAGES.get())
.requires(ModRegistry.Items.PRINTED_PAGE.get(), 2) .requires(ModRegistry.Items.PRINTED_PAGE.get(), 2)
.requires(ingredients.string()) .requires(ingredients.string())
.unlockedBy("has_printer", inventoryChange(ModRegistry.Blocks.PRINTER.get())) .unlockedBy("has_printer", inventoryChange(ModRegistry.Blocks.PRINTER.get()))
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPELESS.get(), add)); .save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPELESS.get(), add));
ShapelessRecipeBuilder ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.PRINTED_BOOK.get()) .shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.PRINTED_BOOK.get())
.requires(ingredients.leather()) .requires(ingredients.leather())
.requires(ModRegistry.Items.PRINTED_PAGE.get(), 1) .requires(ModRegistry.Items.PRINTED_PAGE.get(), 1)
.requires(ingredients.string()) .requires(ingredients.string())
@ -451,7 +451,7 @@ private static ItemPredicate itemPredicate(Ingredient ingredient) {
if (object.has("item")) { if (object.has("item")) {
return itemPredicate(ShapedRecipe.itemFromJson(object)); return itemPredicate(ShapedRecipe.itemFromJson(object));
} else if (object.has("tag")) { } else if (object.has("tag")) {
return itemPredicate(TagKey.create(Registry.ITEM_REGISTRY, new ResourceLocation(GsonHelper.getAsString(object, "tag")))); return itemPredicate(TagKey.create(Registries.ITEM, new ResourceLocation(GsonHelper.getAsString(object, "tag"))));
} else { } else {
throw new IllegalArgumentException("Unknown ingredient " + json); throw new IllegalArgumentException("Unknown ingredient " + json);
} }
@ -471,7 +471,7 @@ private static Consumer<JsonObject> family(ComputerFamily family) {
return json -> json.addProperty("family", family.toString()); return json -> json.addProperty("family", family.toString());
} }
private static void addSpecial(Consumer<FinishedRecipe> add, SimpleRecipeSerializer<?> special) { private static void addSpecial(Consumer<FinishedRecipe> add, SimpleCraftingRecipeSerializer<?> special) {
SpecialRecipeBuilder.special(special).save(add, Registries.RECIPE_SERIALIZERS.getKey(special).toString()); SpecialRecipeBuilder.special(special).save(add, RegistryWrappers.RECIPE_SERIALIZERS.getKey(special).toString());
} }
} }

View File

@ -7,10 +7,12 @@
import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.api.ComputerCraftTags;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.data.tags.ItemTagsProvider; import net.minecraft.data.tags.ItemTagsProvider;
import net.minecraft.data.tags.TagsProvider; import net.minecraft.data.tags.TagsProvider;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags; import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagBuilder;
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;
@ -91,7 +93,25 @@ public static void itemTags(ItemTagConsumer tags) {
* @param <T> The type of object we're providing tags for. * @param <T> The type of object we're providing tags for.
*/ */
public interface TagConsumer<T> { public interface TagConsumer<T> {
TagsProvider.TagAppender<T> tag(TagKey<T> tag); TagAppender<T> tag(TagKey<T> tag);
}
public record TagAppender<T>(RegistryWrappers.RegistryWrapper<T> registry, TagBuilder builder) {
public TagAppender<T> add(T object) {
builder.addElement(registry.getKey(object));
return this;
}
@SafeVarargs
public final TagAppender<T> add(T... objects) {
for (var object : objects) add(object);
return this;
}
public TagAppender<T> addTag(TagKey<T> tag) {
builder.addTag(tag.location());
return this;
}
} }
/** /**

View File

@ -9,7 +9,7 @@
import dan200.computercraft.api.ComputerCraftTags.Blocks; import dan200.computercraft.api.ComputerCraftTags.Blocks;
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider; import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import net.minecraft.data.DataGenerator; import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -18,8 +18,8 @@
import static dan200.computercraft.shared.ModRegistry.TurtleSerialisers; import static dan200.computercraft.shared.ModRegistry.TurtleSerialisers;
class TurtleUpgradeProvider extends TurtleUpgradeDataProvider { class TurtleUpgradeProvider extends TurtleUpgradeDataProvider {
TurtleUpgradeProvider(DataGenerator generator) { TurtleUpgradeProvider(PackOutput output) {
super(generator); super(output);
} }
@Override @Override

View File

@ -1,24 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.mixin;
import net.minecraft.world.item.CreativeModeTab;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(CreativeModeTab.class)
public interface CreativeModeTabAccessor {
@Accessor("langId")
String computercraft$langId();
@Final
@Mutable
@Accessor("TABS")
static void computercraft$setTabs(CreativeModeTab[] tabs) {
}
}

View File

@ -12,6 +12,9 @@
import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser; import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.core.util.Colour;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.command.arguments.ComputerArgumentType; import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
import dan200.computercraft.shared.command.arguments.ComputersArgumentType; import dan200.computercraft.shared.command.arguments.ComputersArgumentType;
import dan200.computercraft.shared.command.arguments.RepeatArgumentType; import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
@ -75,16 +78,14 @@
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.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.resources.ResourceLocation; import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.*;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.RecordItem;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@ -94,7 +95,6 @@
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function;
/** /**
* Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and * Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and
@ -107,7 +107,7 @@ private ModRegistry() {
} }
public static final class Blocks { public static final class Blocks {
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.BLOCK_REGISTRY); static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
private static BlockBehaviour.Properties properties() { private static BlockBehaviour.Properties properties() {
return BlockBehaviour.Properties.of(Material.STONE).strength(2); return BlockBehaviour.Properties.of(Material.STONE).strength(2);
@ -162,7 +162,7 @@ private static BlockBehaviour.Properties modemProperties() {
} }
public static class BlockEntities { public static class BlockEntities {
static final RegistrationHelper<BlockEntityType<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.BLOCK_ENTITY_TYPE_REGISTRY); static final RegistrationHelper<BlockEntityType<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK_ENTITY_TYPE);
private static <T extends BlockEntity> RegistryEntry<BlockEntityType<T>> ofBlock(RegistryEntry<? extends Block> block, BiFunction<BlockPos, BlockState, T> factory) { private static <T extends BlockEntity> RegistryEntry<BlockEntityType<T>> ofBlock(RegistryEntry<? extends Block> block, BiFunction<BlockPos, BlockState, T> factory) {
return REGISTRY.register(block.id().getPath(), () -> PlatformHelper.get().createBlockEntityType(factory, block.get())); return REGISTRY.register(block.id().getPath(), () -> PlatformHelper.get().createBlockEntityType(factory, block.get()));
@ -203,10 +203,10 @@ private static <T extends BlockEntity> RegistryEntry<BlockEntityType<T>> ofBlock
} }
public static final class Items { public static final class Items {
static final RegistrationHelper<Item> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.ITEM_REGISTRY); static final RegistrationHelper<Item> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.ITEM);
private static Item.Properties properties() { private static Item.Properties properties() {
return new Item.Properties().tab(PlatformHelper.get().getCreativeTab()); return new Item.Properties();
} }
private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier) { private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier) {
@ -279,7 +279,7 @@ public static class PocketUpgradeSerialisers {
} }
public static class Menus { public static class Menus {
static final RegistrationHelper<MenuType<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.MENU_REGISTRY); static final RegistrationHelper<MenuType<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.MENU);
public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> COMPUTER = REGISTRY.register("computer", public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> COMPUTER = REGISTRY.register("computer",
() -> ContainerData.toType(ComputerContainerData::new, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data))); () -> ContainerData.toType(ComputerContainerData::new, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data)));
@ -307,7 +307,7 @@ public static class Menus {
} }
static class ArgumentTypes { static class ArgumentTypes {
static final RegistrationHelper<ArgumentTypeInfo<?, ?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.COMMAND_ARGUMENT_TYPE_REGISTRY); static final RegistrationHelper<ArgumentTypeInfo<?, ?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.COMMAND_ARGUMENT_TYPE);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <T extends ArgumentType<?>> void registerUnsafe(String name, Class<T> type, ArgumentTypeInfo<?, ?> serializer) { private static <T extends ArgumentType<?>> void registerUnsafe(String name, Class<T> type, ArgumentTypeInfo<?, ?> serializer) {
@ -331,7 +331,7 @@ private static <T extends ArgumentType<?>> void register(String name, Class<T> t
} }
public static class LootItemConditionTypes { public static class LootItemConditionTypes {
static final RegistrationHelper<LootItemConditionType> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.LOOT_ITEM_REGISTRY); static final RegistrationHelper<LootItemConditionType> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.LOOT_CONDITION_TYPE);
public static final RegistryEntry<LootItemConditionType> BLOCK_NAMED = REGISTRY.register("block_named", public static final RegistryEntry<LootItemConditionType> BLOCK_NAMED = REGISTRY.register("block_named",
() -> ConstantLootConditionSerializer.type(BlockNamedEntityLootCondition.INSTANCE)); () -> ConstantLootConditionSerializer.type(BlockNamedEntityLootCondition.INSTANCE));
@ -344,18 +344,18 @@ public static class LootItemConditionTypes {
} }
public static class RecipeSerializers { public static class RecipeSerializers {
static final RegistrationHelper<RecipeSerializer<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registry.RECIPE_SERIALIZER_REGISTRY); static final RegistrationHelper<RecipeSerializer<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.RECIPE_SERIALIZER);
private static <T extends CustomRecipe> RegistryEntry<SimpleRecipeSerializer<T>> simple(String name, Function<ResourceLocation, T> factory) { private static <T extends CustomRecipe> RegistryEntry<SimpleCraftingRecipeSerializer<T>> simple(String name, SimpleCraftingRecipeSerializer.Factory<T> factory) {
return REGISTRY.register(name, () -> new SimpleRecipeSerializer<>(factory)); return REGISTRY.register(name, () -> new SimpleCraftingRecipeSerializer<>(factory));
} }
public static final RegistryEntry<SimpleRecipeSerializer<ColourableRecipe>> DYEABLE_ITEM = simple("colour", ColourableRecipe::new); public static final RegistryEntry<SimpleCraftingRecipeSerializer<ColourableRecipe>> DYEABLE_ITEM = simple("colour", ColourableRecipe::new);
public static final RegistryEntry<TurtleRecipe.Serializer> TURTLE = REGISTRY.register("turtle", TurtleRecipe.Serializer::new); public static final RegistryEntry<TurtleRecipe.Serializer> TURTLE = REGISTRY.register("turtle", TurtleRecipe.Serializer::new);
public static final RegistryEntry<SimpleRecipeSerializer<TurtleUpgradeRecipe>> TURTLE_UPGRADE = simple("turtle_upgrade", TurtleUpgradeRecipe::new); public static final RegistryEntry<SimpleCraftingRecipeSerializer<TurtleUpgradeRecipe>> TURTLE_UPGRADE = simple("turtle_upgrade", TurtleUpgradeRecipe::new);
public static final RegistryEntry<SimpleRecipeSerializer<PocketComputerUpgradeRecipe>> POCKET_COMPUTER_UPGRADE = simple("pocket_computer_upgrade", PocketComputerUpgradeRecipe::new); public static final RegistryEntry<SimpleCraftingRecipeSerializer<PocketComputerUpgradeRecipe>> POCKET_COMPUTER_UPGRADE = simple("pocket_computer_upgrade", PocketComputerUpgradeRecipe::new);
public static final RegistryEntry<SimpleRecipeSerializer<PrintoutRecipe>> PRINTOUT = simple("printout", PrintoutRecipe::new); public static final RegistryEntry<SimpleCraftingRecipeSerializer<PrintoutRecipe>> PRINTOUT = simple("printout", PrintoutRecipe::new);
public static final RegistryEntry<SimpleRecipeSerializer<DiskRecipe>> DISK = simple("disk", DiskRecipe::new); public static final RegistryEntry<SimpleCraftingRecipeSerializer<DiskRecipe>> DISK = simple("disk", DiskRecipe::new);
public static final RegistryEntry<ComputerUpgradeRecipe.Serializer> COMPUTER_UPGRADE = REGISTRY.register("computer_upgrade", ComputerUpgradeRecipe.Serializer::new); public static final RegistryEntry<ComputerUpgradeRecipe.Serializer> COMPUTER_UPGRADE = REGISTRY.register("computer_upgrade", ComputerUpgradeRecipe.Serializer::new);
public static final RegistryEntry<ImpostorRecipe.Serializer> IMPOSTOR_SHAPED = REGISTRY.register("impostor_shaped", ImpostorRecipe.Serializer::new); public static final RegistryEntry<ImpostorRecipe.Serializer> IMPOSTOR_SHAPED = REGISTRY.register("impostor_shaped", ImpostorRecipe.Serializer::new);
public static final RegistryEntry<ImpostorShapelessRecipe.Serializer> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", ImpostorShapelessRecipe.Serializer::new); public static final RegistryEntry<ImpostorShapelessRecipe.Serializer> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", ImpostorShapelessRecipe.Serializer::new);
@ -396,4 +396,58 @@ public static void registerMainThread() {
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_NORMAL.get(), TurtleItem.CAULDRON_INTERACTION); CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_NORMAL.get(), TurtleItem.CAULDRON_INTERACTION);
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION); CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
} }
/**
* Configure a {@link CreativeModeTab.Builder} to contain all of ComputerCraft's items.
*
* @param builder The builder to configure.
* @return The same building, for calling {@link CreativeModeTab.Builder#build()} on.
*/
public static CreativeModeTab.Builder registerCreativeTab(CreativeModeTab.Builder builder) {
return builder
.icon(() -> new ItemStack(Items.COMPUTER_NORMAL.get()))
.title(Component.translatable("itemGroup.computercraft"))
.displayItems((flags, out, isOp) -> {
out.accept(new ItemStack(Items.COMPUTER_NORMAL.get()));
out.accept(new ItemStack(Items.COMPUTER_ADVANCED.get()));
if (isOp) out.accept(new ItemStack(Items.COMPUTER_COMMAND.get()));
addTurtle(out, Items.TURTLE_NORMAL.get());
addTurtle(out, Items.TURTLE_ADVANCED.get());
addPocket(out, Items.POCKET_COMPUTER_NORMAL.get());
addPocket(out, Items.POCKET_COMPUTER_ADVANCED.get());
out.accept(Items.WIRELESS_MODEM_NORMAL.get());
out.accept(Items.WIRELESS_MODEM_ADVANCED.get());
out.accept(Items.CABLE.get());
out.accept(Items.WIRED_MODEM.get());
out.accept(Items.WIRED_MODEM_FULL.get());
out.accept(Items.MONITOR_NORMAL.get());
out.accept(Items.MONITOR_ADVANCED.get());
out.accept(Items.SPEAKER.get());
out.accept(Items.PRINTER.get());
out.accept(Items.PRINTED_PAGE.get());
out.accept(Items.PRINTED_PAGES.get());
out.accept(Items.PRINTED_BOOK.get());
out.accept(Items.DISK_DRIVE.get());
for (var colour = 0; colour < 16; colour++) {
out.accept(DiskItem.createFromIDAndColour(-1, null, Colour.VALUES[colour].getHex()));
}
});
}
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
out.accept(turtle.create(-1, null, -1, null, null, 0, null));
TurtleUpgrades.getVanillaUpgrades()
.map(x -> turtle.create(-1, null, -1, null, x, 0, null))
.forEach(out::accept);
}
private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket) {
out.accept(pocket.create(-1, null, -1, null));
PocketUpgrades.getVanillaUpgrades().map(x -> pocket.create(-1, null, -1, x)).forEach(out::accept);
}
} }

View File

@ -9,7 +9,7 @@
import com.mojang.brigadier.Message; import com.mojang.brigadier.Message;
import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@ -25,7 +25,7 @@ public class ArgumentUtils {
public static <A extends ArgumentType<?>> JsonObject serializeToJson(ArgumentTypeInfo.Template<A> template) { public static <A extends ArgumentType<?>> JsonObject serializeToJson(ArgumentTypeInfo.Template<A> template) {
var object = new JsonObject(); var object = new JsonObject();
object.addProperty("type", "argument"); object.addProperty("type", "argument");
object.addProperty("parser", Registries.COMMAND_ARGUMENT_TYPES.getKey(template.type()).toString()); object.addProperty("parser", RegistryWrappers.COMMAND_ARGUMENT_TYPES.getKey(template.type()).toString());
var properties = new JsonObject(); var properties = new JsonObject();
serializeToJson(properties, template.type(), template); serializeToJson(properties, template.type(), template);
@ -45,12 +45,12 @@ public static <A extends ArgumentType<?>> void serializeToNetwork(FriendlyByteBu
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> void serializeToNetwork(FriendlyByteBuf buffer, ArgumentTypeInfo<A, T> type, ArgumentTypeInfo.Template<A> template) { private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> void serializeToNetwork(FriendlyByteBuf buffer, ArgumentTypeInfo<A, T> type, ArgumentTypeInfo.Template<A> template) {
Registries.writeId(buffer, Registries.COMMAND_ARGUMENT_TYPES, type); RegistryWrappers.writeId(buffer, RegistryWrappers.COMMAND_ARGUMENT_TYPES, type);
type.serializeToNetwork((T) template, buffer); type.serializeToNetwork((T) template, buffer);
} }
public static ArgumentTypeInfo.Template<?> deserialize(FriendlyByteBuf buffer) { public static ArgumentTypeInfo.Template<?> deserialize(FriendlyByteBuf buffer) {
var type = Registries.readId(buffer, Registries.COMMAND_ARGUMENT_TYPES); var type = RegistryWrappers.readId(buffer, RegistryWrappers.COMMAND_ARGUMENT_TYPES);
Objects.requireNonNull(type, "Unknown argument type"); Objects.requireNonNull(type, "Unknown argument type");
return type.deserializeFromNetwork(buffer); return type.deserializeFromNetwork(buffer);
} }

View File

@ -11,13 +11,14 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public final class ColourableRecipe extends CustomRecipe { public final class ColourableRecipe extends CustomRecipe {
public ColourableRecipe(ResourceLocation id) { public ColourableRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id); super(id, category);
} }
@Override @Override

View File

@ -15,7 +15,7 @@
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -255,7 +255,7 @@ private Level getLevel(Optional<String> id) throws LuaException {
var dimensionId = ResourceLocation.tryParse(id.get()); var dimensionId = ResourceLocation.tryParse(id.get());
if (dimensionId == null) throw new LuaException("Invalid dimension name"); if (dimensionId == null) throw new LuaException("Invalid dimension name");
Level level = currentLevel.getServer().getLevel(ResourceKey.create(Registry.DIMENSION_REGISTRY, dimensionId)); Level level = currentLevel.getServer().getLevel(ResourceKey.create(Registries.DIMENSION, dimensionId));
if (level == null) throw new LuaException("Unknown dimension"); if (level == null) throw new LuaException("Unknown dimension");
return level; return level;

View File

@ -10,6 +10,7 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -20,8 +21,8 @@
public abstract class ComputerConvertRecipe extends ShapedRecipe { public abstract class ComputerConvertRecipe extends ShapedRecipe {
private final String group; private final String group;
public ComputerConvertRecipe(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result) { public ComputerConvertRecipe(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result) {
super(identifier, group, width, height, ingredients, result); super(identifier, group, category, width, height, ingredients, result);
this.group = group; this.group = group;
} }

View File

@ -13,14 +13,15 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe { public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe {
private final ComputerFamily family; private final ComputerFamily family;
public ComputerFamilyRecipe(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) { public ComputerFamilyRecipe(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
super(identifier, group, width, height, ingredients, result); super(identifier, group, category, width, height, ingredients, result);
this.family = family; this.family = family;
} }
@ -29,31 +30,33 @@ public ComputerFamily getFamily() {
} }
public abstract static class Serializer<T extends ComputerFamilyRecipe> implements RecipeSerializer<T> { public abstract static class Serializer<T extends ComputerFamilyRecipe> implements RecipeSerializer<T> {
protected abstract T create(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family); protected abstract T create(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family);
@Override @Override
public T fromJson(ResourceLocation identifier, JsonObject json) { public T fromJson(ResourceLocation identifier, JsonObject json) {
var group = GsonHelper.getAsString(json, "group", ""); var group = GsonHelper.getAsString(json, "group", "");
var category = CraftingBookCategory.CODEC.byName(GsonHelper.getAsString(json, "category", null), CraftingBookCategory.MISC);
var family = RecipeUtil.getFamily(json, "family"); var family = RecipeUtil.getFamily(json, "family");
var template = RecipeUtil.getTemplate(json); var template = RecipeUtil.getTemplate(json);
var result = itemStackFromJson(GsonHelper.getAsJsonObject(json, "result")); var result = itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
return create(identifier, group, template.width(), template.height(), template.ingredients(), result, family); return create(identifier, group, category, template.width(), template.height(), template.ingredients(), result, family);
} }
@Override @Override
public T fromNetwork(ResourceLocation identifier, FriendlyByteBuf buf) { public T fromNetwork(ResourceLocation identifier, FriendlyByteBuf buf) {
var width = buf.readVarInt(); var width = buf.readVarInt();
var height = buf.readVarInt(); var height = buf.readVarInt();
var group = buf.readUtf(Short.MAX_VALUE); var group = buf.readUtf();
var category = buf.readEnum(CraftingBookCategory.class);
var ingredients = NonNullList.withSize(width * height, Ingredient.EMPTY); var ingredients = NonNullList.withSize(width * height, Ingredient.EMPTY);
for (var i = 0; i < ingredients.size(); i++) ingredients.set(i, Ingredient.fromNetwork(buf)); for (var i = 0; i < ingredients.size(); i++) ingredients.set(i, Ingredient.fromNetwork(buf));
var result = buf.readItem(); var result = buf.readItem();
var family = buf.readEnum(ComputerFamily.class); var family = buf.readEnum(ComputerFamily.class);
return create(identifier, group, width, height, ingredients, result, family); return create(identifier, group, category, width, height, ingredients, result, family);
} }
@Override @Override
@ -61,6 +64,7 @@ public void toNetwork(FriendlyByteBuf buf, T recipe) {
buf.writeVarInt(recipe.getWidth()); buf.writeVarInt(recipe.getWidth());
buf.writeVarInt(recipe.getHeight()); buf.writeVarInt(recipe.getHeight());
buf.writeUtf(recipe.getGroup()); buf.writeUtf(recipe.getGroup());
buf.writeEnum(recipe.category());
for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buf); for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buf);
buf.writeItem(recipe.getResultItem()); buf.writeItem(recipe.getResultItem());
buf.writeEnum(recipe.getFamily()); buf.writeEnum(recipe.getFamily());

View File

@ -11,12 +11,13 @@
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
public final class ComputerUpgradeRecipe extends ComputerFamilyRecipe { public final class ComputerUpgradeRecipe extends ComputerFamilyRecipe {
private ComputerUpgradeRecipe(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) { private ComputerUpgradeRecipe(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
super(identifier, group, width, height, ingredients, result, family); super(identifier, group, category, width, height, ingredients, result, family);
} }
@Override @Override
@ -31,8 +32,8 @@ public RecipeSerializer<?> getSerializer() {
public static class Serializer extends ComputerFamilyRecipe.Serializer<ComputerUpgradeRecipe> { public static class Serializer extends ComputerFamilyRecipe.Serializer<ComputerUpgradeRecipe> {
@Override @Override
protected ComputerUpgradeRecipe create(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) { protected ComputerUpgradeRecipe create(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
return new ComputerUpgradeRecipe(identifier, group, width, height, ingredients, result, family); return new ComputerUpgradeRecipe(identifier, group, category, width, height, ingredients, result, family);
} }
} }
} }

View File

@ -6,7 +6,7 @@
package dan200.computercraft.shared.details; package dan200.computercraft.shared.details;
import dan200.computercraft.api.detail.BlockReference; import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.block.state.properties.Property;
import java.util.HashMap; import java.util.HashMap;
@ -16,7 +16,7 @@ public class BlockDetails {
public static void fillBasic(Map<? super String, Object> data, BlockReference block) { public static void fillBasic(Map<? super String, Object> data, BlockReference block) {
var state = block.state(); var state = block.state();
data.put("name", DetailHelpers.getId(Registries.BLOCKS, state.getBlock())); data.put("name", DetailHelpers.getId(RegistryWrappers.BLOCKS, state.getBlock()));
Map<Object, Object> stateTable = new HashMap<>(); Map<Object, Object> stateTable = new HashMap<>();
for (Map.Entry<Property<?>, ? extends Comparable<?>> entry : state.getValues().entrySet()) { for (Map.Entry<Property<?>, ? extends Comparable<?>> entry : state.getValues().entrySet()) {

View File

@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.shared.details; package dan200.computercraft.shared.details;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
@ -25,7 +25,7 @@ public static <T> Map<String, Boolean> getTags(Stream<TagKey<T>> tags) {
return tags.collect(Collectors.toMap(x -> x.location().toString(), x -> true)); return tags.collect(Collectors.toMap(x -> x.location().toString(), x -> true));
} }
public static <T> String getId(Registries.RegistryWrapper<T> registry, T entry) { public static <T> String getId(RegistryWrappers.RegistryWrapper<T> registry, T entry) {
return registry.getKey(entry).toString(); return registry.getKey(entry).toString();
} }
} }

View File

@ -6,13 +6,13 @@
package dan200.computercraft.shared.details; package dan200.computercraft.shared.details;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import dan200.computercraft.mixin.CreativeModeTabAccessor;
import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.EnchantedBookItem;
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;
@ -25,7 +25,7 @@
*/ */
public class ItemDetails { public class ItemDetails {
public static <T extends Map<? super String, Object>> T fillBasicSafe(T data, ItemStack stack) { public static <T extends Map<? super String, Object>> T fillBasicSafe(T data, ItemStack stack) {
data.put("name", DetailHelpers.getId(Registries.ITEMS, stack.getItem())); data.put("name", DetailHelpers.getId(RegistryWrappers.ITEMS, stack.getItem()));
data.put("count", stack.getCount()); data.put("count", stack.getCount());
return data; return data;
} }
@ -98,14 +98,15 @@ private static Component parseTextComponent(Tag x) {
private static List<Map<String, Object>> getItemGroups(ItemStack stack) { private static List<Map<String, Object>> getItemGroups(ItemStack stack) {
List<Map<String, Object>> groups = new ArrayList<>(1); List<Map<String, Object>> groups = new ArrayList<>(1);
for (var group : PlatformHelper.get().getCreativeTabs(stack)) { CreativeModeTabs.tabs().stream().filter(x -> x.contains(stack)).forEach(group -> {
if (group == null) continue;
Map<String, Object> groupData = new HashMap<>(2); Map<String, Object> groupData = new HashMap<>(2);
groupData.put("id", ((CreativeModeTabAccessor) group).computercraft$langId());
var id = PlatformHelper.get().getCreativeTabId(group);
if (id != null) groupData.put("id", id.toString());
groupData.put("displayName", group.getDisplayName().getString()); groupData.put("displayName", group.getDisplayName().getString());
groups.add(groupData); groups.add(groupData);
} });
return groups; return groups;
} }
@ -152,7 +153,7 @@ private static void addEnchantments(ListTag rawEnchants, ArrayList<Map<String, O
var enchantment = entry.getKey(); var enchantment = entry.getKey();
var level = entry.getValue(); var level = entry.getValue();
var enchant = new HashMap<String, Object>(3); var enchant = new HashMap<String, Object>(3);
enchant.put("name", DetailHelpers.getId(Registries.ENCHANTMENTS, enchantment)); enchant.put("name", DetailHelpers.getId(RegistryWrappers.ENCHANTMENTS, enchantment));
enchant.put("level", level); enchant.put("level", level);
enchant.put("displayName", enchantment.getFullname(level).getString()); enchant.put("displayName", enchantment.getFullname(level).getString());
enchants.add(enchant); enchants.add(enchant);

View File

@ -20,6 +20,7 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipe;
@ -233,11 +234,11 @@ private static ItemStack pocketWith(ItemStack stack, @Nullable IPocketUpgrade ba
} }
private T pocket(Ingredient upgrade, Ingredient pocketComputer, ItemStack result) { private T pocket(Ingredient upgrade, Ingredient pocketComputer, ItemStack result) {
return wrap.apply(new ShapedRecipe(POCKET_UPGRADE, "", 1, 2, NonNullList.of(Ingredient.EMPTY, upgrade, pocketComputer), result)); return wrap.apply(new ShapedRecipe(POCKET_UPGRADE, "", CraftingBookCategory.MISC, 1, 2, NonNullList.of(Ingredient.EMPTY, upgrade, pocketComputer), result));
} }
private T turtle(Ingredient left, Ingredient right, ItemStack result) { private T turtle(Ingredient left, Ingredient right, ItemStack result) {
return wrap.apply(new ShapedRecipe(TURTLE_UPGRADE, "", 2, 1, NonNullList.of(Ingredient.EMPTY, left, right), result)); return wrap.apply(new ShapedRecipe(TURTLE_UPGRADE, "", CraftingBookCategory.MISC, 2, 1, NonNullList.of(Ingredient.EMPTY, left, right), result));
} }
private class UpgradeInfo { private class UpgradeInfo {

View File

@ -15,11 +15,9 @@
import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.config.Config;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@ -44,14 +42,6 @@ public static ItemStack createFromIDAndColour(int id, @Nullable String label, in
return stack; return stack;
} }
@Override
public void fillItemCategory(CreativeModeTab tabs, NonNullList<ItemStack> list) {
if (!allowedIn(tabs)) return;
for (var colour = 0; colour < 16; colour++) {
list.add(createFromIDAndColour(-1, null, Colour.VALUES[colour].getHex()));
}
}
@Override @Override
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag options) { public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag options) {
if (options.isAdvanced()) { if (options.isAdvanced()) {

View File

@ -13,11 +13,9 @@
import dan200.computercraft.core.util.Colour; import dan200.computercraft.core.util.Colour;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@ -37,10 +35,6 @@ public TreasureDiskItem(Properties settings) {
super(settings); super(settings);
} }
@Override
public void fillItemCategory(CreativeModeTab group, NonNullList<ItemStack> stacks) {
}
@Override @Override
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag tooltipOptions) { public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag tooltipOptions) {
var label = getTitle(stack); var label = getTitle(stack);

View File

@ -15,6 +15,7 @@
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
@ -23,8 +24,8 @@
public class DiskRecipe extends CustomRecipe { public class DiskRecipe extends CustomRecipe {
private final Ingredient redstone; private final Ingredient redstone;
public DiskRecipe(ResourceLocation id) { public DiskRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id); super(id, category);
redstone = PlatformHelper.get().getRecipeIngredients().redstone(); redstone = PlatformHelper.get().getRecipeIngredients().redstone();
} }

View File

@ -12,6 +12,7 @@
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
@ -21,8 +22,8 @@ public final class PrintoutRecipe extends CustomRecipe {
private final Ingredient leather; private final Ingredient leather;
private final Ingredient string; private final Ingredient string;
public PrintoutRecipe(ResourceLocation id) { public PrintoutRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id); super(id, category);
var ingredients = PlatformHelper.get().getRecipeIngredients(); var ingredients = PlatformHelper.get().getRecipeIngredients();
leather = ingredients.leather(); leather = ingredients.leather();

View File

@ -7,7 +7,7 @@
import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity; import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
@ -41,14 +41,14 @@ public PlayRecordClientMessage(BlockPos pos) {
public PlayRecordClientMessage(FriendlyByteBuf buf) { public PlayRecordClientMessage(FriendlyByteBuf buf) {
pos = buf.readBlockPos(); pos = buf.readBlockPos();
soundEvent = buf.readBoolean() ? Registries.readKey(buf, Registries.SOUND_EVENTS) : null; soundEvent = buf.readBoolean() ? RegistryWrappers.readKey(buf, RegistryWrappers.SOUND_EVENTS) : null;
name = buf.readBoolean() ? buf.readUtf(Short.MAX_VALUE) : null; name = buf.readBoolean() ? buf.readUtf(Short.MAX_VALUE) : null;
} }
@Override @Override
public void toBytes(FriendlyByteBuf buf) { public void toBytes(FriendlyByteBuf buf) {
buf.writeBlockPos(pos); buf.writeBlockPos(pos);
writeOptional(buf, soundEvent, (b, e) -> Registries.writeKey(b, Registries.SOUND_EVENTS, e)); writeOptional(buf, soundEvent, (b, e) -> RegistryWrappers.writeKey(b, RegistryWrappers.SOUND_EVENTS, e));
writeOptional(buf, name, FriendlyByteBuf::writeUtf); writeOptional(buf, name, FriendlyByteBuf::writeUtf);
} }

View File

@ -27,10 +27,10 @@ public class SpeakerPlayClientMessage implements NetworkMessage<ClientNetworkCon
private final float volume; private final float volume;
private final float pitch; private final float pitch;
public SpeakerPlayClientMessage(UUID source, SpeakerPosition pos, ResourceLocation event, float volume, float pitch) { public SpeakerPlayClientMessage(UUID source, SpeakerPosition pos, ResourceLocation sound, float volume, float pitch) {
this.source = source; this.source = source;
this.pos = pos.asMessage(); this.pos = pos.asMessage();
sound = event; this.sound = sound;
this.volume = volume; this.volume = volume;
this.pitch = pitch; this.pitch = pitch;
} }

View File

@ -12,7 +12,7 @@
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IDynamicPeripheral;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -26,7 +26,7 @@ class GenericPeripheral implements IDynamicPeripheral {
private final List<SaturatedMethod> methods; private final List<SaturatedMethod> methods;
GenericPeripheral(BlockEntity tile, @Nullable String name, Set<String> additionalTypes, List<SaturatedMethod> methods) { GenericPeripheral(BlockEntity tile, @Nullable String name, Set<String> additionalTypes, List<SaturatedMethod> methods) {
var type = Registries.BLOCK_ENTITY_TYPES.getKey(tile.getType()); var type = RegistryWrappers.BLOCK_ENTITY_TYPES.getKey(tile.getType());
this.tile = tile; this.tile = tile;
this.type = name != null ? name : type.toString(); this.type = name != null ? name : type.toString();
this.additionalTypes = additionalTypes; this.additionalTypes = additionalTypes;

View File

@ -6,15 +6,12 @@
package dan200.computercraft.shared.peripheral.modem.wired; package dan200.computercraft.shared.peripheral.modem.wired;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -51,15 +48,10 @@ boolean placeAtCorrected(Level world, BlockPos pos, BlockState state) {
return placeAt(world, pos, correctConnections(world, pos, state)); return placeAt(world, pos, correctConnections(world, pos, state));
} }
@Override
public void fillItemCategory(CreativeModeTab group, NonNullList<ItemStack> list) {
if (allowedIn(group)) list.add(new ItemStack(this));
}
@Override @Override
public String getDescriptionId() { public String getDescriptionId() {
if (translationKey == null) { if (translationKey == null) {
translationKey = Util.makeDescriptionId("block", Registries.ITEMS.getKey(this)); translationKey = Util.makeDescriptionId("block", RegistryWrappers.ITEMS.getKey(this));
} }
return translationKey; return translationKey;
} }

View File

@ -18,13 +18,14 @@
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage; import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage; import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.Registries;
import dan200.computercraft.shared.util.PauseAwareTimer; import dan200.computercraft.shared.util.PauseAwareTimer;
import net.minecraft.ResourceLocationException; import net.minecraft.ResourceLocationException;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundCustomSoundPacket; import net.minecraft.core.Holder;
import net.minecraft.network.protocol.game.ClientboundSoundPacket;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
@ -64,11 +65,11 @@ public abstract class SpeakerPeripheral implements IPeripheral {
private long lastPlayTime; private long lastPlayTime;
private final List<PendingSound> pendingNotes = new ArrayList<>(); private final List<PendingSound<Holder<SoundEvent>>> pendingNotes = new ArrayList<>();
private final Object lock = new Object(); private final Object lock = new Object();
private boolean shouldStop; private boolean shouldStop;
private @Nullable PendingSound pendingSound = null; private @Nullable PendingSound<ResourceLocation> pendingSound = null;
private @Nullable DfpwmState dfpwmState; private @Nullable DfpwmState dfpwmState;
public void update() { public void update() {
@ -85,7 +86,7 @@ public void update() {
lastPlayTime = clock; lastPlayTime = clock;
server.getPlayerList().broadcast( server.getPlayerList().broadcast(
null, pos.x, pos.y, pos.z, sound.volume * 16, level.dimension(), null, pos.x, pos.y, pos.z, sound.volume * 16, level.dimension(),
new ClientboundCustomSoundPacket(sound.location, SoundSource.RECORDS, pos, sound.volume, sound.pitch, level.getRandom().nextLong()) new ClientboundSoundPacket(sound.sound, SoundSource.RECORDS, pos.x, pos.y, pos.z, sound.volume, sound.pitch, level.getRandom().nextLong())
); );
} }
pendingNotes.clear(); pendingNotes.clear();
@ -96,7 +97,7 @@ public void update() {
// dfpwmState will only ever transition from having a buffer to not having a buffer on the main thread (so this // dfpwmState will only ever transition from having a buffer to not having a buffer on the main thread (so this
// method), so we don't need to bother locking that. // method), so we don't need to bother locking that.
boolean shouldStop; boolean shouldStop;
PendingSound sound; PendingSound<ResourceLocation> sound;
DfpwmState dfpwmState; DfpwmState dfpwmState;
synchronized (lock) { synchronized (lock) {
sound = pendingSound; sound = pendingSound;
@ -122,7 +123,7 @@ public void update() {
if (sound != null) { if (sound != null) {
lastPlayTime = clock; lastPlayTime = clock;
PlatformHelper.get().sendToAllAround( PlatformHelper.get().sendToAllAround(
new SpeakerPlayClientMessage(getSource(), position, sound.location, sound.volume, sound.pitch), new SpeakerPlayClientMessage(getSource(), position, sound.sound, sound.volume, sound.pitch),
(ServerLevel) level, pos, sound.volume * 16 (ServerLevel) level, pos, sound.volume * 16
); );
syncedPosition(position); syncedPosition(position);
@ -218,7 +219,7 @@ public final boolean playNote(ILuaContext context, String instrumentA, Optional<
synchronized (pendingNotes) { synchronized (pendingNotes) {
if (pendingNotes.size() >= Config.maxNotesPerTick) return false; if (pendingNotes.size() >= Config.maxNotesPerTick) return false;
pendingNotes.add(new PendingSound(Registries.SOUND_EVENTS.getKey(instrument.getSoundEvent()), volume, (float) Math.pow(2.0, (pitch - 12.0) / 12.0))); pendingNotes.add(new PendingSound<>(instrument.getSoundEvent(), volume, (float) Math.pow(2.0, (pitch - 12.0) / 12.0)));
} }
return true; return true;
} }
@ -260,7 +261,7 @@ public final boolean playSound(ILuaContext context, String name, Optional<Double
synchronized (lock) { synchronized (lock) {
if (dfpwmState != null && dfpwmState.isPlaying()) return false; if (dfpwmState != null && dfpwmState.isPlaying()) return false;
dfpwmState = null; dfpwmState = null;
pendingSound = new PendingSound(identifier, volume, pitch); pendingSound = new PendingSound<>(identifier, volume, pitch);
return true; return true;
} }
} }
@ -360,6 +361,6 @@ public void detach(IComputerAccess computer) {
} }
} }
private record PendingSound(ResourceLocation location, float volume, float pitch) { private record PendingSound<T>(T sound, float volume, float pitch) {
} }
} }

View File

@ -67,13 +67,6 @@ static PlatformHelper get() {
return (PlatformHelper) dan200.computercraft.impl.PlatformHelper.get(); return (PlatformHelper) dan200.computercraft.impl.PlatformHelper.get();
} }
/**
* Get ComputerCraft's creative tab all its items should appear under.
*
* @return The creative tab.
*/
CreativeModeTab getCreativeTab();
/** /**
* Wrap a Minecraft registry in our own abstraction layer. * Wrap a Minecraft registry in our own abstraction layer.
* *
@ -81,7 +74,7 @@ static PlatformHelper get() {
* @param <T> The type of object stored in this registry. * @param <T> The type of object stored in this registry.
* @return The wrapped registry. * @return The wrapped registry.
*/ */
<T> Registries.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> registry); <T> RegistryWrappers.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> registry);
/** /**
* Create a registration helper for a specific registry. * Create a registration helper for a specific registry.
@ -262,12 +255,13 @@ static PlatformHelper get() {
int getBurnTime(ItemStack stack); int getBurnTime(ItemStack stack);
/** /**
* Get the creative tabs this stack belongs to. * Get a unique identifier for this creative tab.
* *
* @param stack The current item. * @param tab The tab to get
* @return The creative tabs the item belongs to. * @return The unique identifier, or {@code null} if not available.
*/ */
Collection<CreativeModeTab> getCreativeTabs(ItemStack stack); @Nullable
ResourceLocation getCreativeTabId(CreativeModeTab tab);
/** /**
* Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return * Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return

View File

@ -7,6 +7,7 @@
import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
@ -25,16 +26,16 @@
/** /**
* Mimics {@link Registry} but using {@link PlatformHelper}'s recipe abstractions. * Mimics {@link Registry} but using {@link PlatformHelper}'s recipe abstractions.
*/ */
public final class Registries { public final class RegistryWrappers {
public static final RegistryWrapper<Item> ITEMS = PlatformHelper.get().wrap(Registry.ITEM_REGISTRY); public static final RegistryWrapper<Item> ITEMS = PlatformHelper.get().wrap(Registries.ITEM);
public static final RegistryWrapper<Block> BLOCKS = PlatformHelper.get().wrap(Registry.BLOCK_REGISTRY); public static final RegistryWrapper<Block> BLOCKS = PlatformHelper.get().wrap(Registries.BLOCK);
public static final RegistryWrapper<BlockEntityType<?>> BLOCK_ENTITY_TYPES = PlatformHelper.get().wrap(Registry.BLOCK_ENTITY_TYPE_REGISTRY); public static final RegistryWrapper<BlockEntityType<?>> BLOCK_ENTITY_TYPES = PlatformHelper.get().wrap(Registries.BLOCK_ENTITY_TYPE);
public static final RegistryWrapper<Fluid> FLUIDS = PlatformHelper.get().wrap(Registry.FLUID_REGISTRY); public static final RegistryWrapper<Fluid> FLUIDS = PlatformHelper.get().wrap(Registries.FLUID);
public static final RegistryWrapper<Enchantment> ENCHANTMENTS = PlatformHelper.get().wrap(Registry.ENCHANTMENT_REGISTRY); public static final RegistryWrapper<Enchantment> ENCHANTMENTS = PlatformHelper.get().wrap(Registries.ENCHANTMENT);
public static final RegistryWrapper<ArgumentTypeInfo<?, ?>> COMMAND_ARGUMENT_TYPES = PlatformHelper.get().wrap(Registry.COMMAND_ARGUMENT_TYPE_REGISTRY); public static final RegistryWrapper<ArgumentTypeInfo<?, ?>> COMMAND_ARGUMENT_TYPES = PlatformHelper.get().wrap(Registries.COMMAND_ARGUMENT_TYPE);
public static final RegistryWrapper<SoundEvent> SOUND_EVENTS = PlatformHelper.get().wrap(Registry.SOUND_EVENT_REGISTRY); public static final RegistryWrapper<SoundEvent> SOUND_EVENTS = PlatformHelper.get().wrap(Registries.SOUND_EVENT);
public static final RegistryWrapper<RecipeSerializer<?>> RECIPE_SERIALIZERS = PlatformHelper.get().wrap(Registry.RECIPE_SERIALIZER_REGISTRY); public static final RegistryWrapper<RecipeSerializer<?>> RECIPE_SERIALIZERS = PlatformHelper.get().wrap(Registries.RECIPE_SERIALIZER);
public static final RegistryWrapper<MenuType<?>> MENU = PlatformHelper.get().wrap(Registry.MENU_REGISTRY); public static final RegistryWrapper<MenuType<?>> MENU = PlatformHelper.get().wrap(Registries.MENU);
public interface RegistryWrapper<T> extends Iterable<T> { public interface RegistryWrapper<T> extends Iterable<T> {
int getId(T object); int getId(T object);
@ -53,7 +54,7 @@ default Stream<T> stream() {
} }
} }
private Registries() { private RegistryWrappers() {
} }
public static <K> void writeId(FriendlyByteBuf buf, RegistryWrapper<K> registry, K object) { public static <K> void writeId(FriendlyByteBuf buf, RegistryWrapper<K> registry, K object) {

View File

@ -24,7 +24,6 @@
import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider; import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider;
import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@ -36,7 +35,6 @@
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@ -70,13 +68,6 @@ public ItemStack create(int id, @Nullable String label, int colour, @Nullable IP
return result; return result;
} }
@Override
public void fillItemCategory(CreativeModeTab group, NonNullList<ItemStack> stacks) {
if (!allowedIn(group)) return;
stacks.add(create(-1, null, -1, null));
PocketUpgrades.getVanillaUpgrades().map(x -> create(-1, null, -1, x)).forEach(stacks::add);
}
private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerComputer computer) { private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerComputer computer) {
var upgrade = getUpgrade(stack); var upgrade = getUpgrade(stack);

View File

@ -14,13 +14,14 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public final class PocketComputerUpgradeRecipe extends CustomRecipe { public final class PocketComputerUpgradeRecipe extends CustomRecipe {
public PocketComputerUpgradeRecipe(ResourceLocation identifier) { public PocketComputerUpgradeRecipe(ResourceLocation identifier, CraftingBookCategory category) {
super(identifier); super(identifier, category);
} }
@Override @Override

View File

@ -14,12 +14,10 @@
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.AbstractComputerItem; import dan200.computercraft.shared.computer.items.AbstractComputerItem;
import dan200.computercraft.shared.turtle.blocks.TurtleBlock; import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
import net.minecraft.core.NonNullList;
import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.LayeredCauldronBlock; import net.minecraft.world.level.block.LayeredCauldronBlock;
@ -56,16 +54,6 @@ public ItemStack create(
return stack; return stack;
} }
@Override
public void fillItemCategory(CreativeModeTab group, NonNullList<ItemStack> list) {
if (!allowedIn(group)) return;
list.add(create(-1, null, -1, null, null, 0, null));
TurtleUpgrades.getVanillaUpgrades()
.map(x -> create(-1, null, -1, null, x, 0, null))
.forEach(list::add);
}
@Override @Override
public Component getName(ItemStack stack) { public Component getName(ItemStack stack) {
var baseString = getDescriptionId(stack); var baseString = getDescriptionId(stack);

View File

@ -13,12 +13,13 @@
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
public final class TurtleRecipe extends ComputerFamilyRecipe { public final class TurtleRecipe extends ComputerFamilyRecipe {
public TurtleRecipe(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) { public TurtleRecipe(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
super(identifier, group, width, height, ingredients, result, family); super(identifier, group, category, width, height, ingredients, result, family);
} }
@Override @Override
@ -36,8 +37,8 @@ protected ItemStack convert(IComputerItem item, ItemStack stack) {
public static class Serializer extends ComputerFamilyRecipe.Serializer<TurtleRecipe> { public static class Serializer extends ComputerFamilyRecipe.Serializer<TurtleRecipe> {
@Override @Override
protected TurtleRecipe create(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) { protected TurtleRecipe create(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
return new TurtleRecipe(identifier, group, width, height, ingredients, result, family); return new TurtleRecipe(identifier, group, category, width, height, ingredients, result, family);
} }
} }
} }

View File

@ -15,13 +15,14 @@
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public final class TurtleUpgradeRecipe extends CustomRecipe { public final class TurtleUpgradeRecipe extends CustomRecipe {
public TurtleUpgradeRecipe(ResourceLocation id) { public TurtleUpgradeRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id); super(id, category);
} }
@Override @Override

View File

@ -8,8 +8,8 @@
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeBase;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
@ -33,7 +33,7 @@ public TurtleTool fromJson(ResourceLocation id, JsonObject object) {
TagKey<Block> breakable = null; TagKey<Block> breakable = null;
if (object.has("breakable")) { if (object.has("breakable")) {
var tag = new ResourceLocation(GsonHelper.getAsString(object, "breakable")); var tag = new ResourceLocation(GsonHelper.getAsString(object, "breakable"));
breakable = TagKey.create(Registry.BLOCK_REGISTRY, tag); breakable = TagKey.create(Registries.BLOCK, tag);
} }
return new TurtleTool(id, adjective, craftingItem, new ItemStack(toolItem), damageMultiplier, breakable); return new TurtleTool(id, adjective, craftingItem, new ItemStack(toolItem), damageMultiplier, breakable);
@ -42,20 +42,20 @@ public TurtleTool fromJson(ResourceLocation id, JsonObject object) {
@Override @Override
public TurtleTool fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { public TurtleTool fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
var adjective = buffer.readUtf(); var adjective = buffer.readUtf();
var craftingItem = Registries.readId(buffer, Registries.ITEMS); var craftingItem = RegistryWrappers.readId(buffer, RegistryWrappers.ITEMS);
var toolItem = buffer.readItem(); var toolItem = buffer.readItem();
// damageMultiplier and breakable aren't used by the client, but we need to construct the upgrade exactly // 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! // as otherwise syncing on an SP world will overwrite the (shared) upgrade registry with an invalid upgrade!
var damageMultiplier = buffer.readFloat(); var damageMultiplier = buffer.readFloat();
var breakable = buffer.readBoolean() ? TagKey.create(Registry.BLOCK_REGISTRY, buffer.readResourceLocation()) : null; var breakable = buffer.readBoolean() ? TagKey.create(Registries.BLOCK, buffer.readResourceLocation()) : null;
return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, breakable); return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, breakable);
} }
@Override @Override
public void toNetwork(FriendlyByteBuf buffer, TurtleTool upgrade) { public void toNetwork(FriendlyByteBuf buffer, TurtleTool upgrade) {
buffer.writeUtf(upgrade.getUnlocalisedAdjective()); buffer.writeUtf(upgrade.getUnlocalisedAdjective());
Registries.writeId(buffer, Registries.ITEMS, upgrade.getCraftingItem().getItem()); RegistryWrappers.writeId(buffer, RegistryWrappers.ITEMS, upgrade.getCraftingItem().getItem());
buffer.writeItem(upgrade.item); buffer.writeItem(upgrade.item);
buffer.writeFloat(upgrade.damageMulitiplier); buffer.writeFloat(upgrade.damageMulitiplier);
buffer.writeBoolean(upgrade.breakable != null); buffer.writeBoolean(upgrade.breakable != null);

View File

@ -6,7 +6,7 @@
package dan200.computercraft.shared.util; package dan200.computercraft.shared.util;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.ResourceLocationException; import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -32,7 +32,7 @@ public static void assertBetween(int value, int min, int max, String message) th
} }
} }
public static <T> T getRegistryEntry(String name, String typeName, Registries.RegistryWrapper<T> registry) throws LuaException { public static <T> T getRegistryEntry(String name, String typeName, RegistryWrappers.RegistryWrapper<T> registry) throws LuaException {
ResourceLocation id; ResourceLocation id;
try { try {
id = new ResourceLocation(name); id = new ResourceLocation(name);

View File

@ -13,6 +13,7 @@
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapedRecipe;
@ -21,8 +22,8 @@
public final class ImpostorRecipe extends ShapedRecipe { public final class ImpostorRecipe extends ShapedRecipe {
private final String group; private final String group;
private ImpostorRecipe(ResourceLocation id, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result) { private ImpostorRecipe(ResourceLocation id, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result) {
super(id, group, width, height, ingredients, result); super(id, group, category, width, height, ingredients, result);
this.group = group; this.group = group;
} }
@ -50,9 +51,10 @@ public static class Serializer implements RecipeSerializer<ImpostorRecipe> {
@Override @Override
public ImpostorRecipe fromJson(ResourceLocation identifier, JsonObject json) { public ImpostorRecipe fromJson(ResourceLocation identifier, JsonObject json) {
var group = GsonHelper.getAsString(json, "group", ""); var group = GsonHelper.getAsString(json, "group", "");
var category = CraftingBookCategory.CODEC.byName(GsonHelper.getAsString(json, "category", null), CraftingBookCategory.MISC);
var recipe = RecipeSerializer.SHAPED_RECIPE.fromJson(identifier, json); var recipe = RecipeSerializer.SHAPED_RECIPE.fromJson(identifier, json);
var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result")); var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
return new ImpostorRecipe(identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result); return new ImpostorRecipe(identifier, group, category, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result);
} }
@Override @Override
@ -60,10 +62,11 @@ public ImpostorRecipe fromNetwork(ResourceLocation identifier, FriendlyByteBuf b
var width = buf.readVarInt(); var width = buf.readVarInt();
var height = buf.readVarInt(); var height = buf.readVarInt();
var group = buf.readUtf(Short.MAX_VALUE); var group = buf.readUtf(Short.MAX_VALUE);
var category = buf.readEnum(CraftingBookCategory.class);
var items = NonNullList.withSize(width * height, Ingredient.EMPTY); var items = NonNullList.withSize(width * height, Ingredient.EMPTY);
for (var k = 0; k < items.size(); k++) items.set(k, Ingredient.fromNetwork(buf)); for (var k = 0; k < items.size(); k++) items.set(k, Ingredient.fromNetwork(buf));
var result = buf.readItem(); var result = buf.readItem();
return new ImpostorRecipe(identifier, group, width, height, items, result); return new ImpostorRecipe(identifier, group, category, width, height, items, result);
} }
@Override @Override
@ -71,6 +74,7 @@ public void toNetwork(FriendlyByteBuf buf, ImpostorRecipe recipe) {
buf.writeVarInt(recipe.getWidth()); buf.writeVarInt(recipe.getWidth());
buf.writeVarInt(recipe.getHeight()); buf.writeVarInt(recipe.getHeight());
buf.writeUtf(recipe.getGroup()); buf.writeUtf(recipe.getGroup());
buf.writeEnum(recipe.category());
for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buf); for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buf);
buf.writeItem(recipe.getResultItem()); buf.writeItem(recipe.getResultItem());
} }

View File

@ -15,17 +15,14 @@
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.*;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public final class ImpostorShapelessRecipe extends ShapelessRecipe { public final class ImpostorShapelessRecipe extends ShapelessRecipe {
private final String group; private final String group;
private ImpostorShapelessRecipe(ResourceLocation id, String group, ItemStack result, NonNullList<Ingredient> ingredients) { private ImpostorShapelessRecipe(ResourceLocation id, String group, CraftingBookCategory category, ItemStack result, NonNullList<Ingredient> ingredients) {
super(id, group, result, ingredients); super(id, group, category, result, ingredients);
this.group = group; this.group = group;
} }
@ -52,7 +49,8 @@ public RecipeSerializer<?> getSerializer() {
public static final class Serializer implements RecipeSerializer<ImpostorShapelessRecipe> { public static final class Serializer implements RecipeSerializer<ImpostorShapelessRecipe> {
@Override @Override
public ImpostorShapelessRecipe fromJson(ResourceLocation id, JsonObject json) { public ImpostorShapelessRecipe fromJson(ResourceLocation id, JsonObject json) {
var s = GsonHelper.getAsString(json, "group", ""); var group = GsonHelper.getAsString(json, "group", "");
var category = CraftingBookCategory.CODEC.byName(GsonHelper.getAsString(json, "category", null), CraftingBookCategory.MISC);
var ingredients = readIngredients(GsonHelper.getAsJsonArray(json, "ingredients")); var ingredients = readIngredients(GsonHelper.getAsJsonArray(json, "ingredients"));
if (ingredients.isEmpty()) throw new JsonParseException("No ingredients for shapeless recipe"); if (ingredients.isEmpty()) throw new JsonParseException("No ingredients for shapeless recipe");
@ -61,7 +59,7 @@ public ImpostorShapelessRecipe fromJson(ResourceLocation id, JsonObject json) {
} }
var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result")); var result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
return new ImpostorShapelessRecipe(id, s, result, ingredients); return new ImpostorShapelessRecipe(id, group, category, result, ingredients);
} }
private NonNullList<Ingredient> readIngredients(JsonArray arrays) { private NonNullList<Ingredient> readIngredients(JsonArray arrays) {
@ -76,19 +74,21 @@ private NonNullList<Ingredient> readIngredients(JsonArray arrays) {
@Override @Override
public ImpostorShapelessRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { public ImpostorShapelessRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
var s = buffer.readUtf(32767); var group = buffer.readUtf();
var i = buffer.readVarInt(); var category = buffer.readEnum(CraftingBookCategory.class);
var items = NonNullList.withSize(i, Ingredient.EMPTY); var count = buffer.readVarInt();
var items = NonNullList.withSize(count, Ingredient.EMPTY);
for (var j = 0; j < items.size(); j++) items.set(j, Ingredient.fromNetwork(buffer)); for (var j = 0; j < items.size(); j++) items.set(j, Ingredient.fromNetwork(buffer));
var result = buffer.readItem(); var result = buffer.readItem();
return new ImpostorShapelessRecipe(id, s, result, items); return new ImpostorShapelessRecipe(id, group, category, result, items);
} }
@Override @Override
public void toNetwork(FriendlyByteBuf buffer, ImpostorShapelessRecipe recipe) { public void toNetwork(FriendlyByteBuf buffer, ImpostorShapelessRecipe recipe) {
buffer.writeUtf(recipe.getGroup()); buffer.writeUtf(recipe.getGroup());
buffer.writeEnum(recipe.category());
buffer.writeVarInt(recipe.getIngredients().size()); buffer.writeVarInt(recipe.getIngredients().size());
for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buffer); for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buffer);

View File

@ -4,6 +4,7 @@ accessWidener v1 named
# that we actually use # that we actually use
accessible method net/minecraft/client/renderer/item/ItemProperties register (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/item/ClampedItemPropertyFunction;)V accessible method net/minecraft/client/renderer/item/ItemProperties register (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/item/ClampedItemPropertyFunction;)V
accessible class net/minecraft/world/item/CreativeModeTab$Output
# Containers # Containers
accessible class net/minecraft/world/inventory/MenuType$MenuSupplier accessible class net/minecraft/world/inventory/MenuType$MenuSupplier
@ -12,6 +13,7 @@ accessible class net/minecraft/client/gui/screens/MenuScreens$ScreenConstructor
accessible method net/minecraft/client/gui/screens/MenuScreens register (Lnet/minecraft/world/inventory/MenuType;Lnet/minecraft/client/gui/screens/MenuScreens$ScreenConstructor;)V accessible method net/minecraft/client/gui/screens/MenuScreens register (Lnet/minecraft/world/inventory/MenuType;Lnet/minecraft/client/gui/screens/MenuScreens$ScreenConstructor;)V
# Data generators # Data generators
accessible class net/minecraft/data/loot/LootTableProvider$SubProviderEntry
accessible class net/minecraft/data/tags/TagsProvider$TagAppender accessible class net/minecraft/data/tags/TagsProvider$TagAppender
accessible field net/minecraft/data/models/BlockModelGenerators blockStateOutput Ljava/util/function/Consumer; accessible field net/minecraft/data/models/BlockModelGenerators blockStateOutput Ljava/util/function/Consumer;
accessible field net/minecraft/data/models/BlockModelGenerators modelOutput Ljava/util/function/BiConsumer; accessible field net/minecraft/data/models/BlockModelGenerators modelOutput Ljava/util/function/BiConsumer;

View File

@ -8,7 +8,6 @@
}, },
"mixins": [ "mixins": [
"CacheUpdaterMixin", "CacheUpdaterMixin",
"CreativeModeTabAccessor",
"ExplosionAccessor" "ExplosionAccessor"
], ],
"refmap": "computercraft.refmap.json" "refmap": "computercraft.refmap.json"

View File

@ -59,7 +59,7 @@
@AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class }) @AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class })
public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper { public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper {
@Override @Override
public <T> Registries.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> registry) { public <T> RegistryWrappers.RegistryWrapper<T> wrap(ResourceKey<Registry<T>> registry) {
throw new UnsupportedOperationException("Cannot query registry inside tests"); throw new UnsupportedOperationException("Cannot query registry inside tests");
} }
@ -113,11 +113,6 @@ public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, Leve
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests"); throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
} }
@Override
public CreativeModeTab getCreativeTab() {
throw new UnsupportedOperationException("Cannot get creative tab inside tests");
}
@Override @Override
public List<TagKey<Item>> getDyeTags() { public List<TagKey<Item>> getDyeTags() {
throw new UnsupportedOperationException("Cannot query tags inside tests"); throw new UnsupportedOperationException("Cannot query tags inside tests");
@ -153,9 +148,11 @@ public boolean onNotifyNeighbour(Level level, BlockPos pos, BlockState block, Di
throw new UnsupportedOperationException("Cannot interact with the world inside tests"); throw new UnsupportedOperationException("Cannot interact with the world inside tests");
} }
@Nullable
@Override @Override
public Collection<CreativeModeTab> getCreativeTabs(ItemStack stack) { public ResourceLocation getCreativeTabId(CreativeModeTab tab) {
throw new UnsupportedOperationException("Cannot get creative tabs inside tests"); return null;
} }
@Override @Override

View File

@ -7,15 +7,15 @@
import dan200.computercraft.api.filesystem.Mount; import dan200.computercraft.api.filesystem.Mount;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.server.packs.FolderPackResources;
import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.PathPackResources;
import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.util.Unit; import net.minecraft.util.Unit;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -32,7 +32,7 @@ public void before() {
var manager = new ReloadableResourceManager(PackType.SERVER_DATA); var manager = new ReloadableResourceManager(PackType.SERVER_DATA);
var done = new CompletableFuture<Unit>(); var done = new CompletableFuture<Unit>();
manager.createReload(Util.backgroundExecutor(), Util.backgroundExecutor(), done, List.of( manager.createReload(Util.backgroundExecutor(), Util.backgroundExecutor(), done, List.of(
new FolderPackResources(new File("../core/src/main/resources")) new PathPackResources("resources", Path.of("../core/src/main/resources"), false)
)); ));
mount = ResourceMount.get("computercraft", "lua/rom", manager); mount = ResourceMount.get("computercraft", "lua/rom", manager);

View File

@ -17,7 +17,7 @@
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.data.PrettyJsonWriter; import dan200.computercraft.data.PrettyJsonWriter;
import dan200.computercraft.gametest.core.TestHooks; import dan200.computercraft.gametest.core.TestHooks;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
@ -74,14 +74,14 @@ private static void export(Path root, ImageRenderer renderer) throws IOException
Set<Item> items = new HashSet<>(); Set<Item> items = new HashSet<>();
// First find all CC items // First find all CC items
for (var item : Registries.ITEMS) { for (var item : RegistryWrappers.ITEMS) {
if (Registries.ITEMS.getKey(item).getNamespace().equals(ComputerCraftAPI.MOD_ID)) items.add(item); if (RegistryWrappers.ITEMS.getKey(item).getNamespace().equals(ComputerCraftAPI.MOD_ID)) items.add(item);
} }
// Now find all CC recipes. // Now find all CC recipes.
for (var recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) { for (var recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) {
var result = recipe.getResultItem(); var result = recipe.getResultItem();
if (!Registries.ITEMS.getKey(result.getItem()).getNamespace().equals(ComputerCraftAPI.MOD_ID)) { if (!RegistryWrappers.ITEMS.getKey(result.getItem()).getNamespace().equals(ComputerCraftAPI.MOD_ID)) {
continue; continue;
} }
if (result.hasTag()) { if (result.hasTag()) {
@ -122,7 +122,7 @@ private static void export(Path root, ImageRenderer renderer) throws IOException
renderer.setupState(); renderer.setupState();
for (var item : items) { for (var item : items) {
var stack = new ItemStack(item); var stack = new ItemStack(item);
var location = Registries.ITEMS.getKey(item); var location = RegistryWrappers.ITEMS.getKey(item);
dump.itemNames.put(location.toString(), stack.getHoverName().getString()); dump.itemNames.put(location.toString(), stack.getHoverName().getString());
renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"), renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"),

View File

@ -8,9 +8,9 @@
import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.FogRenderer;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL12;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -37,7 +37,7 @@ public ImageRenderer() {
public void setupState() { public void setupState() {
projectionMatrix = RenderSystem.getProjectionMatrix(); projectionMatrix = RenderSystem.getProjectionMatrix();
RenderSystem.setProjectionMatrix(Matrix4f.orthographic(0, 16, 0, 16, 1000, 3000)); RenderSystem.setProjectionMatrix(new Matrix4f().identity().ortho(0, 16, 0, 16, 1000, 3000));
var transform = RenderSystem.getModelViewStack(); var transform = RenderSystem.getModelViewStack();
transform.pushPose(); transform.pushPose();

View File

@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.export; package dan200.computercraft.export;
import dan200.computercraft.shared.platform.Registries; import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
@ -23,7 +23,7 @@ public static class Recipe {
public int count; public int count;
public Recipe(ItemStack output) { public Recipe(ItemStack output) {
this.output = Registries.ITEMS.getKey(output.getItem()).toString(); this.output = RegistryWrappers.ITEMS.getKey(output.getItem()).toString();
count = output.getCount(); count = output.getCount();
} }
@ -38,7 +38,7 @@ public void setInput(int pos, Ingredient ingredient, Set<Item> trackedItems) {
if (!canonicalItem.contains(item)) continue; if (!canonicalItem.contains(item)) continue;
trackedItems.add(item); trackedItems.add(item);
inputs[pos] = new String[]{ Registries.ITEMS.getKey(item).toString() }; inputs[pos] = new String[]{ RegistryWrappers.ITEMS.getKey(item).toString() };
return; return;
} }
@ -46,7 +46,7 @@ public void setInput(int pos, Ingredient ingredient, Set<Item> trackedItems) {
for (var i = 0; i < items.length; i++) { for (var i = 0; i < items.length; i++) {
var item = items[i].getItem(); var item = items[i].getItem();
trackedItems.add(item); trackedItems.add(item);
itemIds[i] = Registries.ITEMS.getKey(item).toString(); itemIds[i] = RegistryWrappers.ITEMS.getKey(item).toString();
} }
Arrays.sort(itemIds); Arrays.sort(itemIds);

View File

@ -19,7 +19,7 @@ class Loot_Test {
/** /**
* Test that the loot tables will spawn in treasure disks. * Test that the loot tables will spawn in treasure disks.
*/ */
@GameTest(template = Structures.DEFAULT) @GameTest(template = Structures.DEFAULT, required = false) // FIXME: We may need to inject this as a datapack instead
fun Chest_contains_disk(context: GameTestHelper) = context.sequence { fun Chest_contains_disk(context: GameTestHelper) = context.sequence {
thenExecute { thenExecute {
val pos = BlockPos(2, 2, 2) val pos = BlockPos(2, 2, 2)

View File

@ -2,7 +2,7 @@
import dan200.computercraft.gametest.core.MinecraftExtensions import dan200.computercraft.gametest.core.MinecraftExtensions
import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor
import dan200.computercraft.shared.platform.Registries import dan200.computercraft.shared.platform.RegistryWrappers
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.Screenshot import net.minecraft.client.Screenshot
import net.minecraft.client.gui.screens.inventory.MenuAccess import net.minecraft.client.gui.screens.inventory.MenuAccess
@ -117,7 +117,7 @@ fun screenshot(name: String, callback: () -> Unit = {}) {
* Get the currently open [AbstractContainerMenu], ensuring it is of a specific type. * Get the currently open [AbstractContainerMenu], ensuring it is of a specific type.
*/ */
fun <T : AbstractContainerMenu> getOpenMenu(type: MenuType<T>): T { fun <T : AbstractContainerMenu> getOpenMenu(type: MenuType<T>): T {
fun getName(type: MenuType<*>) = Registries.MENU.getKey(type) fun getName(type: MenuType<*>) = RegistryWrappers.MENU.getKey(type)
val screen = minecraft.screen val screen = minecraft.screen
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")

View File

@ -10,7 +10,7 @@
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor
import dan200.computercraft.shared.platform.PlatformHelper import dan200.computercraft.shared.platform.PlatformHelper
import dan200.computercraft.shared.platform.Registries import dan200.computercraft.shared.platform.RegistryWrappers
import dan200.computercraft.test.core.computer.LuaTaskContext import dan200.computercraft.test.core.computer.LuaTaskContext
import dan200.computercraft.test.shared.ItemStackMatcher.isStack import dan200.computercraft.test.shared.ItemStackMatcher.isStack
import net.minecraft.commands.arguments.blocks.BlockInput import net.minecraft.commands.arguments.blocks.BlockInput
@ -154,7 +154,7 @@ override fun getMessageToShowAtBlock(): String = message!!.lineSequence().first(
fun <T : Comparable<T>> GameTestHelper.assertBlockHas(pos: BlockPos, property: Property<T>, value: T, message: String = "") { fun <T : Comparable<T>> GameTestHelper.assertBlockHas(pos: BlockPos, property: Property<T>, value: T, message: String = "") {
val state = getBlockState(pos) val state = getBlockState(pos)
if (!state.hasProperty(property)) { if (!state.hasProperty(property)) {
val id = Registries.BLOCKS.getKey(state.block) val id = RegistryWrappers.BLOCKS.getKey(state.block)
fail(message, "block $id does not have property ${property.name}", pos) fail(message, "block $id does not have property ${property.name}", pos)
} else if (state.getValue(property) != value) { } else if (state.getValue(property) != value) {
fail(message, "${property.name} is ${state.getValue(property)}, expected $value", pos) fail(message, "${property.name} is ${state.getValue(property)}, expected $value", pos)
@ -227,7 +227,7 @@ Items do not match (first mismatch at slot $slot).
} }
} }
private fun getName(type: BlockEntityType<*>): ResourceLocation = Registries.BLOCK_ENTITY_TYPES.getKey(type)!! private fun getName(type: BlockEntityType<*>): ResourceLocation = RegistryWrappers.BLOCK_ENTITY_TYPES.getKey(type)!!
/** /**
* Get a [BlockEntity] of a specific type. * Get a [BlockEntity] of a specific type.

View File

@ -10,18 +10,16 @@
import net.minecraft.client.gui.screens.TitleScreen import net.minecraft.client.gui.screens.TitleScreen
import net.minecraft.client.tutorial.TutorialSteps import net.minecraft.client.tutorial.TutorialSteps
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Registry
import net.minecraft.core.RegistryAccess
import net.minecraft.gametest.framework.* import net.minecraft.gametest.framework.*
import net.minecraft.server.MinecraftServer import net.minecraft.server.MinecraftServer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource
import net.minecraft.world.Difficulty import net.minecraft.world.Difficulty
import net.minecraft.world.level.DataPackConfig
import net.minecraft.world.level.GameRules import net.minecraft.world.level.GameRules
import net.minecraft.world.level.GameType import net.minecraft.world.level.GameType
import net.minecraft.world.level.LevelSettings import net.minecraft.world.level.LevelSettings
import net.minecraft.world.level.WorldDataConfiguration
import net.minecraft.world.level.block.Rotation import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.levelgen.WorldOptions
import net.minecraft.world.level.levelgen.presets.WorldPresets import net.minecraft.world.level.levelgen.presets.WorldPresets
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -73,8 +71,8 @@ private fun openWorld() {
minecraft.options.tutorialStep = TutorialSteps.NONE minecraft.options.tutorialStep = TutorialSteps.NONE
minecraft.options.renderDistance().set(6) minecraft.options.renderDistance().set(6)
minecraft.options.gamma().set(1.0) minecraft.options.gamma().set(1.0)
minecraft.options.setSoundCategoryVolume(SoundSource.MUSIC, 0.0f) minecraft.options.getSoundSourceOptionInstance(SoundSource.MUSIC).set(0.0)
minecraft.options.setSoundCategoryVolume(SoundSource.AMBIENT, 0.0f) minecraft.options.getSoundSourceOptionInstance(SoundSource.AMBIENT).set(0.0)
if (minecraft.levelSource.levelExists(LEVEL_NAME)) { if (minecraft.levelSource.levelExists(LEVEL_NAME)) {
LOG.info("World already exists, opening.") LOG.info("World already exists, opening.")
@ -86,16 +84,11 @@ private fun openWorld() {
rules.getRule(GameRules.RULE_DAYLIGHT).set(false, null) rules.getRule(GameRules.RULE_DAYLIGHT).set(false, null)
rules.getRule(GameRules.RULE_WEATHER_CYCLE).set(false, null) rules.getRule(GameRules.RULE_WEATHER_CYCLE).set(false, null)
val registries = RegistryAccess.builtinCopy().freeze()
minecraft.createWorldOpenFlows().createFreshLevel( minecraft.createWorldOpenFlows().createFreshLevel(
LEVEL_NAME, LEVEL_NAME,
LevelSettings("Test Level", GameType.CREATIVE, false, Difficulty.EASY, true, rules, DataPackConfig.DEFAULT), LevelSettings("Test Level", GameType.CREATIVE, false, Difficulty.EASY, true, rules, WorldDataConfiguration.DEFAULT),
registries, WorldOptions(WorldOptions.randomSeed(), false, false),
registries ) { WorldPresets.createNormalWorldDimensions(it) }
.registryOrThrow(Registry.WORLD_PRESET_REGISTRY)
.getHolderOrThrow(WorldPresets.FLAT).value()
.createWorldGenSettings(RandomSource.create().nextLong(), false, false),
)
} }
} }

View File

@ -71,6 +71,7 @@ dependencies {
testModImplementation(testFixtures(project(":core"))) testModImplementation(testFixtures(project(":core")))
testModImplementation(testFixtures(project(":fabric"))) testModImplementation(testFixtures(project(":fabric")))
testImplementation(libs.byteBuddy)
testImplementation(libs.byteBuddyAgent) testImplementation(libs.byteBuddyAgent)
testImplementation(libs.bundles.test) testImplementation(libs.bundles.test)
testRuntimeOnly(libs.bundles.testRuntime) testRuntimeOnly(libs.bundles.testRuntime)

View File

@ -8,14 +8,14 @@
import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormatElement; import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.mojang.math.Matrix4f;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
import com.mojang.math.Vector4f;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@ -64,8 +64,7 @@ private BakedQuad transformQuad(BakedQuad quad) {
// Transform the position // Transform the position
var pos = new Vector4f(x, y, z, 1); var pos = new Vector4f(x, y, z, 1);
pos.transform(transformation); transformation.transformProject(pos);
pos.perspectiveDivide();
vertexData[start] = Float.floatToRawIntBits(pos.x()); vertexData[start] = Float.floatToRawIntBits(pos.x());
vertexData[start + 1] = Float.floatToRawIntBits(pos.y()); vertexData[start + 1] = Float.floatToRawIntBits(pos.y());

View File

@ -5,7 +5,6 @@
*/ */
package dan200.computercraft.client.model.turtle; package dan200.computercraft.client.model.turtle;
import com.mojang.datafixers.util.Pair;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import net.fabricmc.fabric.api.client.model.ModelProviderException; import net.fabricmc.fabric.api.client.model.ModelProviderException;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@ -16,7 +15,9 @@
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
public final class TurtleModelLoader { public final class TurtleModelLoader {
@ -57,15 +58,13 @@ public Collection<ResourceLocation> getDependencies() {
} }
@Override @Override
public Collection<Material> getMaterials(Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) { public void resolveParents(Function<ResourceLocation, UnbakedModel> function) {
Set<Material> materials = new HashSet<>(); function.apply(model).resolveParents(function);
materials.addAll(modelGetter.apply(model).getMaterials(modelGetter, missingTextureErrors)); function.apply(COLOUR_TURTLE_MODEL).resolveParents(function);
materials.addAll(modelGetter.apply(COLOUR_TURTLE_MODEL).getMaterials(modelGetter, missingTextureErrors));
return materials;
} }
@Override @Override
public BakedModel bake(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ResourceLocation location) { public BakedModel bake(ModelBaker bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ResourceLocation location) {
var mainModel = bakery.bake(model, transform); var mainModel = bakery.bake(model, transform);
if (mainModel == null) throw new NullPointerException(model + " failed to bake"); if (mainModel == null) throw new NullPointerException(model + " failed to bake");

View File

@ -8,7 +8,7 @@
import dan200.computercraft.client.ClientRegistry; import dan200.computercraft.client.ClientRegistry;
import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceProvider;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -29,7 +29,7 @@ class GameRendererMixin {
@Inject(method = "reloadShaders", at = @At(value = "TAIL")) @Inject(method = "reloadShaders", at = @At(value = "TAIL"))
@SuppressWarnings("UnusedMethod") @SuppressWarnings("UnusedMethod")
private void onReloadShaders(ResourceManager resourceManager, CallbackInfo ci) { private void onReloadShaders(ResourceProvider resourceManager, CallbackInfo ci) {
try { try {
ClientRegistry.registerShaders(resourceManager, (shader, callback) -> { ClientRegistry.registerShaders(resourceManager, (shader, callback) -> {
shaders.put(shader.getName(), shader); shaders.put(shader.getName(), shader);

View File

@ -20,7 +20,7 @@
class ItemFrameRendererMixin { class ItemFrameRendererMixin {
@Inject( @Inject(
method = "render(Lnet/minecraft/world/entity/decoration/ItemFrame;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", method = "render(Lnet/minecraft/world/entity/decoration/ItemFrame;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lcom/mojang/math/Quaternion;)V", ordinal = 2, shift = At.Shift.AFTER), at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 2, shift = At.Shift.AFTER),
cancellable = true cancellable = true
) )
@SuppressWarnings("UnusedMethod") @SuppressWarnings("UnusedMethod")

View File

@ -166,6 +166,7 @@
"gui.computercraft.config.upload_nag_delay": "Upload nag delay", "gui.computercraft.config.upload_nag_delay": "Upload nag delay",
"gui.computercraft.config.upload_nag_delay.tooltip": "The delay in seconds after which we'll notify about unhandled imports. Set to 0 to disable.\nRange: 0 ~ 60", "gui.computercraft.config.upload_nag_delay.tooltip": "The delay in seconds after which we'll notify about unhandled imports. Set to 0 to disable.\nRange: 0 ~ 60",
"gui.computercraft.pocket_computer_overlay": "Pocket computer open. Press ESC to close.", "gui.computercraft.pocket_computer_overlay": "Pocket computer open. Press ESC to close.",
"gui.computercraft.terminal": "Computer terminal",
"gui.computercraft.tooltip.computer_id": "Computer ID: %s", "gui.computercraft.tooltip.computer_id": "Computer ID: %s",
"gui.computercraft.tooltip.copy": "Copy to clipboard", "gui.computercraft.tooltip.copy": "Copy to clipboard",
"gui.computercraft.tooltip.disk_id": "Disk ID: %s", "gui.computercraft.tooltip.disk_id": "Disk ID: %s",

Some files were not shown because too many files have changed in this diff Show More