1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-16 10:09:55 +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
# 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
# MC version is specified in gradle.properties, as we need that in settings.gradle.
fabric-api = "0.67.0+1.19.2"
fabric-loader = "0.14.10"
forge = "43.1.1"
fabric-api = "0.68.1+1.19.3"
fabric-loader = "0.14.11"
forge = "44.0.0"
forgeSpi = "6.0.0"
mixin = "0.8.5"
parchment = "2022.10.16"
parchment = "2022.11.27"
parchmentMc = "1.19.2"
# Normal dependencies
@ -28,16 +28,16 @@ slf4j = "1.7.36"
# Minecraft mods
forgeConfig = "4.2.7"
iris = "1.19.x-v1.4.0"
iris = "1.19.3-v1.4.6"
jei = "11.3.0.262"
modmenu = "4.1.0"
modmenu = "5.0.1"
oculus = "1.2.5"
rei = "9.1.550"
rubidium = "0.6.1"
sodium = "mc1.19.2-0.4.4"
sodium = "mc1.19.3-0.4.6"
# Testing
byteBuddy = "1.12.18"
byteBuddy = "1.12.19"
hamcrest = "2.2"
jqwik = "1.7.0"
junit = "5.9.1"
@ -100,6 +100,7 @@ sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
# Testing
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" }
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
@ -143,10 +144,10 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
# Minecraft
externalMods-common = ["jei-api", "forgeConfig", "nightConfig-core", "nightConfig-toml"]
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-compile = ["iris", "jei-api", "rei-api", "rei-builtin"]
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
externalMods-fabric-runtime = ["modmenu"]
# Testing
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]

View File

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

View File

@ -5,7 +5,7 @@
*/
package dan200.computercraft.api;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
@ -22,7 +22,7 @@ public static class Items {
public static final TagKey<Item> MONITOR = make("monitor");
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");
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 net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import java.util.function.Consumer;
/**
* A data provider to generate pocket computer upgrades.
* <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function,
* construct each upgrade, and pass them off to the provided consumer to generate them.
* This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the
* {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
* generate them.
*
* @see PocketUpgradeSerialiser
*/
public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPocketUpgrade, PocketUpgradeSerialiser<?>> {
public PocketUpgradeDataProvider(DataGenerator generator) {
super(generator, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", PocketUpgradeSerialiser.REGISTRY_ID);
public PocketUpgradeDataProvider(PackOutput output) {
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.ResourceLocation;
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.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"));
/**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for
* upgrades.
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer},
* but for upgrades.
* <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
*

View File

@ -9,8 +9,9 @@
import dan200.computercraft.api.ComputerCraftTags;
import dan200.computercraft.api.upgrades.UpgradeDataProvider;
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.PackOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.ai.attributes.Attributes;
@ -23,16 +24,17 @@
/**
* A data provider to generate turtle upgrades.
* <p>
* This should be subclassed and registered to a {@link DataGenerator}. Override the {@link #addUpgrades(Consumer)} function,
* construct each upgrade, and pass them off to the provided consumer to generate them.
* This should be subclassed and registered to a {@link DataGenerator.PackGenerator}. Override the
* {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
* generate them.
*
* @see TurtleUpgradeSerialiser
*/
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> {
private static final ResourceLocation TOOL_ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "tool");
public TurtleUpgradeDataProvider(DataGenerator generator) {
super(generator, "Turtle Upgrades", "computercraft/turtle_upgrades", TurtleUpgradeSerialiser.REGISTRY_ID);
public TurtleUpgradeDataProvider(PackOutput output) {
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) {
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 (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 (breakable != null) s.addProperty("breakable", breakable.location().toString());

View File

@ -15,7 +15,7 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
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.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"));
/**
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleRecipeSerializer}, but for
* upgrades.
* Create an upgrade serialiser for a simple upgrade. This is similar to a {@link SimpleCraftingRecipeSerializer},
* but for upgrades.
* <p>
* If you might want to vary the item, it's suggested you use {@link #simpleWithCustomItem(BiFunction)} instead.
*

View File

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

View File

@ -29,7 +29,7 @@
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
import net.minecraft.client.renderer.item.ItemProperties;
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.item.Item;
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);
}
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);
}

View File

@ -77,19 +77,12 @@ protected final TerminalWidget getTerminal() {
@Override
protected void init() {
super.init();
minecraft.keyboardHandler.setSendRepeatsToGui(true);
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);
}
@Override
public void removed() {
super.removed();
minecraft.keyboardHandler.setSendRepeatsToGui(false);
}
@Override
public void 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
var terminal = getTerminal();
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()
);
ComputerSidebar.renderBackground(stack, leftPos, topPos + sidebarYOffset);

View File

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

View File

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

View File

@ -7,17 +7,15 @@
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.gui.widgets.DynamicImageButton.HintedMessage;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.InputHandler;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@ -44,29 +42,29 @@ public final class 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;
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(
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),
() -> isOn.getAsBoolean() ? Arrays.asList(
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")
)
() -> isOn.getAsBoolean() ? turnOff : turnOn
));
y += ICON_HEIGHT + ICON_MARGIN * 2;
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"),
Arrays.asList(
new HintedMessage(
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.vertex.PoseStack;
import net.minecraft.ChatFormatting;
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.resources.ResourceLocation;
import java.util.List;
import javax.annotation.Nullable;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
@ -21,42 +22,39 @@
* dynamically.
*/
public class DynamicImageButton extends Button {
private final Screen screen;
private final ResourceLocation texture;
private final IntSupplier xTexStart;
private final int yTexStart;
private final int yDiffTex;
private final int textureWidth;
private final int textureHeight;
private final Supplier<List<Component>> tooltip;
private final Supplier<HintedMessage> message;
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,
OnPress onPress, List<Component> tooltip
OnPress onPress, HintedMessage message
) {
this(
screen, x, y, width, height, () -> xTexStart, yTexStart, yDiffTex,
x, y, width, height, () -> xTexStart, yTexStart, yDiffTex,
texture, textureWidth, textureHeight,
onPress, () -> tooltip
onPress, () -> message
);
}
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,
OnPress onPress, Supplier<List<Component>> tooltip
OnPress onPress, Supplier<HintedMessage> message
) {
super(x, y, width, height, Component.empty(), onPress);
this.screen = screen;
super(x, y, width, height, Component.empty(), onPress, DEFAULT_NARRATION);
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
this.xTexStart = xTexStart;
this.yTexStart = yTexStart;
this.yDiffTex = yDiffTex;
this.texture = texture;
this.tooltip = tooltip;
this.message = message;
}
@Override
@ -67,23 +65,29 @@ public void renderButton(PoseStack stack, int mouseX, int mouseY, float partialT
var yTex = yTexStart;
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();
if (isHovered) renderToolTip(stack, mouseX, mouseY);
}
@Override
public Component getMessage() {
var tooltip = this.tooltip.get();
return tooltip.isEmpty() ? Component.empty() : tooltip.get(0);
return message.get().message;
}
@Override
public void renderToolTip(PoseStack stack, int mouseX, int mouseY) {
var tooltip = this.tooltip.get();
if (!tooltip.isEmpty()) {
screen.renderComponentTooltip(stack, tooltip, mouseX, mouseY);
public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
setTooltip(message.get().tooltip());
super.render(stack, mouseX, mouseY, partialTicks);
}
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.client.Minecraft;
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.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component;
@ -26,6 +27,8 @@
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
public class TerminalWidget extends AbstractWidget {
private static final Component DESCRIPTION = Component.translatable("gui.computercraft.terminal");
private static final float TERMINATE_TIME = 0.5f;
private final Terminal terminal;
@ -48,7 +51,7 @@ public class TerminalWidget extends AbstractWidget {
private final BitSet keysDown = new BitSet(256);
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.computer = computer;
@ -278,8 +281,8 @@ public void render(PoseStack transform, int mouseX, int mouseY, float partialTic
}
@Override
public void updateNarration(NarrationElementOutput output) {
// I'm not sure what the right option is here.
protected void updateWidgetNarration(NarrationElementOutput output) {
output.add(NarratedElementType.TITLE, getMessage());
}
public static int getWidth(int termWidth) {

View File

@ -7,12 +7,12 @@
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
public class ComputerBorderRenderer {
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;
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.renderer.ItemInHandRenderer;
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 (!minecraft.player.isInvisible()) {
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);
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 f5 = -0.3f * Mth.sin(swingProgress * (float) Math.PI);
transform.translate(offset * f3, f4 - 0.3f * f2, f5);
transform.mulPose(Vector3f.XP.rotationDegrees(f2 * -45f));
transform.mulPose(Vector3f.YP.rotationDegrees(offset * f2 * -30f));
transform.mulPose(Axis.XP.rotationDegrees(f2 * -45f));
transform.mulPose(Axis.YP.rotationDegrees(offset * f2 * -30f));
renderItem(transform, render, stack, combinedLight);
@ -114,17 +114,17 @@ private void renderItemFirstPersonCenter(PoseStack transform, MultiBufferSource
var pitchAngle = renderer.calculateMapTilt(pitch);
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()) {
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.LEFT);
transform.popPose();
}
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);
renderItem(transform, render, stack, combinedLight);

View File

@ -6,8 +6,7 @@
package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import com.mojang.math.Axis;
import dan200.computercraft.client.pocket.ClientPocketComputers;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.util.Colour;
@ -15,6 +14,7 @@
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4f;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
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
// in ItemRenderer
transform.pushPose();
transform.mulPose(Vector3f.YP.rotationDegrees(180f));
transform.mulPose(Vector3f.ZP.rotationDegrees(180f));
transform.mulPose(Axis.YP.rotationDegrees(180f));
transform.mulPose(Axis.ZP.rotationDegrees(180f));
transform.scale(0.5f, 0.5f, 0.5f);
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;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f;
import com.mojang.math.Axis;
import dan200.computercraft.shared.media.items.PrintoutItem;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.entity.EntityType;
@ -30,7 +30,7 @@ private PrintoutItemRenderer() {
@Override
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.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
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.translate(-0.5f, -0.5f, 0.0f);

View File

@ -7,11 +7,11 @@
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.TextBuffer;
import net.minecraft.client.renderer.MultiBufferSource;
import org.joml.Matrix4f;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
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.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceProvider;
import javax.annotation.Nullable;
import java.io.IOException;
@ -60,7 +60,7 @@ public static ShaderInstance getTerminalShader() {
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(
new MonitorTextureBufferShader(
resources,

View File

@ -7,8 +7,8 @@
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import com.mojang.math.Transformation;
import com.mojang.math.Vector3f;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.client.platform.ClientPlatformHelper;
@ -37,8 +37,8 @@
import java.util.List;
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation("computercraft:turtle_normal", "inventory");
private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation("computercraft:turtle_advanced", "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(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 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(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"))) {
// Flip the model
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);
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);
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.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import com.mojang.math.Axis;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.integration.ShaderMod;
import dan200.computercraft.client.render.RenderTypes;
@ -28,10 +26,11 @@
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.Util;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
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 Matrix3f IDENTITY_NORMAL = Util.make(new Matrix3f(), Matrix3f::setIdentity);
private static final Matrix3f IDENTITY_NORMAL = new Matrix3f().identity();
private static @Nullable ByteBuffer backingBuffer;
@ -100,8 +99,8 @@ public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack tra
originPos.getZ() - monitorPos.getZ() + 0.5
);
transform.mulPose(Vector3f.YN.rotationDegrees(yaw));
transform.mulPose(Vector3f.XP.rotationDegrees(pitch));
transform.mulPose(Axis.YN.rotationDegrees(yaw));
transform.mulPose(Axis.XP.rotationDegrees(pitch));
transform.translate(
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
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.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.BlockHitResult;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import java.util.EnumSet;

View File

@ -7,14 +7,14 @@
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour;
import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
import org.joml.Vector3f;
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
// in screen space, rather than in model/view space.
// 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));
drawTerminalForeground(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) {

View File

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

View File

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

View File

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

View File

@ -5,62 +5,50 @@
*/
package dan200.computercraft.data;
import com.mojang.datafixers.util.Pair;
import net.minecraft.data.DataGenerator;
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.ItemModelGenerators;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.tags.TagsProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
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.function.BiConsumer;
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
* handle the slight differences between how Forge and Fabric expose Minecraft's data providers.
* All data providers for ComputerCraft. We require a mod-loader abstraction {@link GeneratorSink} (instead of
* {@link PackOutput})to handle the slight differences between how Forge and Fabric expose Minecraft's data providers.
*/
public final class DataProviders {
private DataProviders() {
}
public static void add(DataGenerator generator, GeneratorFactory generators, boolean includeServer, boolean includeClient) {
var turtleUpgrades = new TurtleUpgradeProvider(generator);
var pocketUpgrades = new PocketUpgradeProvider(generator);
public static void add(GeneratorSink generator) {
var turtleUpgrades = generator.add(TurtleUpgradeProvider::new);
var pocketUpgrades = generator.add(PocketUpgradeProvider::new);
generator.add(out -> new RecipeProvider(out, turtleUpgrades, pocketUpgrades));
generator.addProvider(includeServer, turtleUpgrades);
generator.addProvider(includeServer, pocketUpgrades);
generator.addProvider(includeServer, generators.recipes(new RecipeProvider(turtleUpgrades, pocketUpgrades)::addRecipes));
var blockTags = generator.blockTags(TagProvider::blockTags);
generator.itemTags(TagProvider::itemTags, blockTags);
var blockTags = generators.blockTags(TagProvider::blockTags);
generator.addProvider(includeServer, blockTags);
generator.addProvider(includeServer, generators.itemTags(TagProvider::itemTags, blockTags));
generator.lootTable(LootTableProvider.getTables());
for (var provider : generators.lootTable(LootTableProvider.getTables())) {
generator.addProvider(includeServer, provider);
}
generator.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels);
generator.addProvider(includeClient, generators.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels));
generator.addProvider(includeServer, new LanguageProvider(generator, turtleUpgrades, pocketUpgrades));
generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades));
}
interface GeneratorFactory {
DataProvider recipes(Consumer<Consumer<FinishedRecipe>> recipes);
interface GeneratorSink {
<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<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.AggregatedMetric;
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.DataGenerator;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.ForgeConfigSpec;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
public final class LanguageProvider implements DataProvider {
private final DataGenerator generator;
private final PackOutput output;
private final TurtleUpgradeDataProvider turtleUpgrades;
private final PocketUpgradeDataProvider pocketUpgrades;
private final Map<String, String> translations = new HashMap<>();
public LanguageProvider(DataGenerator generator, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
this.generator = generator;
public LanguageProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
this.output = output;
this.turtleUpgrades = turtleUpgrades;
this.pocketUpgrades = pocketUpgrades;
}
@Override
public void run(CachedOutput cachedOutput) throws IOException {
public CompletableFuture<?> run(CachedOutput cachedOutput) {
addTranslations();
getExpectedKeys().forEach(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();
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
@ -190,6 +190,7 @@ private void addTranslations() {
add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.COUNT.id(), "%s (count)");
// Additional UI elements
add("gui.computercraft.terminal", "Computer terminal");
add("gui.computercraft.tooltip.copy", "Copy to clipboard");
add("gui.computercraft.tooltip.computer_id", "Computer ID: %s");
add("gui.computercraft.tooltip.disk_id", "Disk ID: %s");
@ -266,11 +267,11 @@ private void addTranslations() {
private Stream<String> getExpectedKeys() {
return Stream.of(
Registries.BLOCKS.stream()
.filter(x -> Registries.BLOCKS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
RegistryWrappers.BLOCKS.stream()
.filter(x -> RegistryWrappers.BLOCKS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Block::getDescriptionId),
Registries.ITEMS.stream()
.filter(x -> Registries.ITEMS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
RegistryWrappers.ITEMS.stream()
.filter(x -> RegistryWrappers.ITEMS.getKey(x).getNamespace().equals(ComputerCraftAPI.MOD_ID))
.map(Item::getDescriptionId),
turtleUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),
pocketUpgrades.getGeneratedUpgrades().stream().map(UpgradeBase::getUnlocalisedAdjective),

View File

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

View File

@ -6,10 +6,11 @@
package dan200.computercraft.data;
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.DataGenerator;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.ItemModelGenerators;
import net.minecraft.data.models.blockstates.BlockStateGenerator;
@ -18,14 +19,10 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
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!
*/
public class ModelProvider implements DataProvider {
private static final Logger LOG = LoggerFactory.getLogger(ModelProvider.class);
private final DataGenerator.PathProvider blockStatePath;
private final DataGenerator.PathProvider modelPath;
private final PackOutput.PathProvider blockStatePath;
private final PackOutput.PathProvider modelPath;
private final Consumer<BlockModelGenerators> blocks;
private final Consumer<ItemModelGenerators> items;
public ModelProvider(DataGenerator generator, Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items) {
blockStatePath = generator.createPathProvider(DataGenerator.Target.RESOURCE_PACK, "blockstates");
modelPath = generator.createPathProvider(DataGenerator.Target.RESOURCE_PACK, "models");
public ModelProvider(PackOutput output, Consumer<BlockModelGenerators> blocks, Consumer<ItemModelGenerators> items) {
blockStatePath = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "blockstates");
modelPath = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "models");
this.blocks = blocks;
this.items = items;
}
@Override
public void run(CachedOutput output) {
public CompletableFuture<?> run(CachedOutput output) {
Map<Block, BlockStateGenerator> blockStates = new HashMap<>();
Consumer<BlockStateGenerator> addBlockState = generator -> {
var block = generator.getBlock();
@ -73,7 +68,7 @@ public void run(CachedOutput output) {
blocks.accept(new BlockModelGenerators(addBlockState, addModel, explicitItems::add));
items.accept(new ItemModelGenerators(addModel));
for (var block : Registries.BLOCKS) {
for (var block : RegistryWrappers.BLOCKS) {
if (!blockStates.containsKey(block)) continue;
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)));
saveCollection(output, models, modelPath::json);
List<CompletableFuture<?>> futures = new ArrayList<>();
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()) {
var path = getLocation.apply(entry.getKey());
try {
DataProvider.saveStable(output, entry.getValue().get(), path);
} catch (Exception exception) {
LOG.error("Couldn't save {}", path, exception);
}
futures.add(DataProvider.saveStable(output, entry.getValue().get(), path));
}
}

View File

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

View File

@ -15,16 +15,14 @@
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.platform.PlatformHelper;
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.turtle.items.TurtleItemFactory;
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.core.Registry;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.ShapedRecipeBuilder;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.data.recipes.SpecialRecipeBuilder;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.*;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
@ -36,7 +34,7 @@
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
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.block.Blocks;
@ -46,17 +44,19 @@
import static dan200.computercraft.api.ComputerCraftTags.Items.COMPUTER;
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 TurtleUpgradeDataProvider turtleUpgrades;
private final PocketUpgradeDataProvider pocketUpgrades;
RecipeProvider(TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
RecipeProvider(PackOutput output, TurtleUpgradeDataProvider turtleUpgrades, PocketUpgradeDataProvider pocketUpgrades) {
super(output);
this.turtleUpgrades = turtleUpgrades;
this.pocketUpgrades = pocketUpgrades;
}
public void addRecipes(Consumer<FinishedRecipe> add) {
@Override
public void buildRecipes(Consumer<FinishedRecipe> add) {
basicRecipes(add);
diskColours(add);
pocketUpgrades(add);
@ -77,7 +77,7 @@ public void addRecipes(Consumer<FinishedRecipe> add) {
private void diskColours(Consumer<FinishedRecipe> add) {
for (var colour : Colour.VALUES) {
ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.DISK.get())
.shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.DISK.get())
.requires(ingredients.redstone())
.requires(Items.PAPER)
.requires(DyeItem.byColor(ofColour(colour)))
@ -106,7 +106,7 @@ private void turtleUpgrades(Consumer<FinishedRecipe> add) {
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
var result = TurtleItemFactory.create(-1, null, -1, family, null, upgrade, -1, null);
ShapedRecipeBuilder
.shaped(result.getItem())
.shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId))
.pattern("#T")
.define('T', base.getItem())
@ -138,7 +138,7 @@ private void pocketUpgrades(Consumer<FinishedRecipe> add) {
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
var result = PocketComputerItemFactory.create(-1, null, -1, family, upgrade);
ShapedRecipeBuilder
.shaped(result.getItem())
.shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId))
.pattern("#")
.pattern("P")
@ -158,7 +158,7 @@ private void pocketUpgrades(Consumer<FinishedRecipe> add) {
private void basicRecipes(Consumer<FinishedRecipe> add) {
ShapedRecipeBuilder
.shaped(ModRegistry.Items.CABLE.get(), 6)
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.CABLE.get(), 6)
.pattern(" # ")
.pattern("#R#")
.pattern(" # ")
@ -169,7 +169,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_NORMAL.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_NORMAL.get())
.pattern("###")
.pattern("#R#")
.pattern("#G#")
@ -180,7 +180,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_ADVANCED.get())
.pattern("###")
.pattern("#R#")
.pattern("#G#")
@ -191,7 +191,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Items.COMPUTER_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.COMPUTER_ADVANCED.get())
.pattern("###")
.pattern("#C#")
.pattern("# #")
@ -204,7 +204,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.COMPUTER_COMMAND.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.COMPUTER_COMMAND.get())
.pattern("###")
.pattern("#R#")
.pattern("#G#")
@ -215,7 +215,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_NORMAL.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_NORMAL.get())
.pattern("###")
.pattern("#C#")
.pattern("#I#")
@ -226,7 +226,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.NORMAL)));
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get())
.pattern("###")
.pattern("#C#")
.pattern("#I#")
@ -237,7 +237,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.TURTLE.get(), add).withExtraData(family(ComputerFamily.ADVANCED)));
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.TURTLE_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.TURTLE_ADVANCED.get())
.pattern("###")
.pattern("#C#")
.pattern(" B ")
@ -251,7 +251,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.DISK_DRIVE.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.DISK_DRIVE.get())
.pattern("###")
.pattern("#R#")
.pattern("#R#")
@ -261,7 +261,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.MONITOR_NORMAL.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_NORMAL.get())
.pattern("###")
.pattern("#G#")
.pattern("###")
@ -271,7 +271,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.MONITOR_ADVANCED.get(), 4)
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.MONITOR_ADVANCED.get(), 4)
.pattern("###")
.pattern("#G#")
.pattern("###")
@ -281,7 +281,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_NORMAL.get())
.pattern("###")
.pattern("#A#")
.pattern("#G#")
@ -293,7 +293,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.pattern("###")
.pattern("#A#")
.pattern("#G#")
@ -305,7 +305,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get())
.pattern("###")
.pattern("#C#")
.pattern("# #")
@ -318,7 +318,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.PRINTER.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.PRINTER.get())
.pattern("###")
.pattern("#R#")
.pattern("#D#")
@ -329,7 +329,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.SPEAKER.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.SPEAKER.get())
.pattern("###")
.pattern("#N#")
.pattern("#R#")
@ -340,7 +340,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Items.WIRED_MODEM.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM.get())
.pattern("###")
.pattern("#R#")
.pattern("###")
@ -351,18 +351,18 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapelessRecipeBuilder
.shapeless(ModRegistry.Blocks.WIRED_MODEM_FULL.get())
.shapeless(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRED_MODEM_FULL.get())
.requires(ModRegistry.Items.WIRED_MODEM.get())
.unlockedBy("has_modem", inventoryChange(WIRED_MODEM))
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_from"));
ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.WIRED_MODEM.get())
.shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.WIRED_MODEM.get())
.requires(ModRegistry.Blocks.WIRED_MODEM_FULL.get())
.unlockedBy("has_modem", inventoryChange(WIRED_MODEM))
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_modem_full_to"));
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get())
.pattern("###")
.pattern("#E#")
.pattern("###")
@ -372,7 +372,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapedRecipeBuilder
.shaped(ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get())
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get())
.pattern("###")
.pattern("#E#")
.pattern("###")
@ -383,7 +383,7 @@ private void basicRecipes(Consumer<FinishedRecipe> add) {
.save(add);
ShapelessRecipeBuilder
.shapeless(Items.PLAYER_HEAD)
.shapeless(RecipeCategory.DECORATIONS, Items.PLAYER_HEAD)
.requires(ingredients.head())
.requires(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
.shapeless(Items.PLAYER_HEAD)
.shapeless(RecipeCategory.DECORATIONS, Items.PLAYER_HEAD)
.requires(ingredients.head())
.requires(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
.shapeless(ModRegistry.Items.PRINTED_PAGES.get())
.shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.PRINTED_PAGES.get())
.requires(ModRegistry.Items.PRINTED_PAGE.get(), 2)
.requires(ingredients.string())
.unlockedBy("has_printer", inventoryChange(ModRegistry.Blocks.PRINTER.get()))
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPELESS.get(), add));
ShapelessRecipeBuilder
.shapeless(ModRegistry.Items.PRINTED_BOOK.get())
.shapeless(RecipeCategory.REDSTONE, ModRegistry.Items.PRINTED_BOOK.get())
.requires(ingredients.leather())
.requires(ModRegistry.Items.PRINTED_PAGE.get(), 1)
.requires(ingredients.string())
@ -451,7 +451,7 @@ private static ItemPredicate itemPredicate(Ingredient ingredient) {
if (object.has("item")) {
return itemPredicate(ShapedRecipe.itemFromJson(object));
} 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 {
throw new IllegalArgumentException("Unknown ingredient " + json);
}
@ -471,7 +471,7 @@ private static Consumer<JsonObject> family(ComputerFamily family) {
return json -> json.addProperty("family", family.toString());
}
private static void addSpecial(Consumer<FinishedRecipe> add, SimpleRecipeSerializer<?> special) {
SpecialRecipeBuilder.special(special).save(add, Registries.RECIPE_SERIALIZERS.getKey(special).toString());
private static void addSpecial(Consumer<FinishedRecipe> add, SimpleCraftingRecipeSerializer<?> special) {
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.shared.ModRegistry;
import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.data.tags.ItemTagsProvider;
import net.minecraft.data.tags.TagsProvider;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagBuilder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
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.
*/
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.turtle.TurtleUpgradeDataProvider;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation;
import java.util.function.Consumer;
@ -18,8 +18,8 @@
import static dan200.computercraft.shared.ModRegistry.TurtleSerialisers;
class TurtleUpgradeProvider extends TurtleUpgradeDataProvider {
TurtleUpgradeProvider(DataGenerator generator) {
super(generator);
TurtleUpgradeProvider(PackOutput output) {
super(output);
}
@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.pocket.PocketUpgradeSerialiser;
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.ComputersArgumentType;
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
@ -75,16 +78,14 @@
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
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.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.RecordItem;
import net.minecraft.world.item.*;
import net.minecraft.world.item.crafting.CustomRecipe;
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.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
@ -94,7 +95,6 @@
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* 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 {
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() {
return BlockBehaviour.Properties.of(Material.STONE).strength(2);
@ -162,7 +162,7 @@ private static BlockBehaviour.Properties modemProperties() {
}
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) {
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 {
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() {
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) {
@ -279,7 +279,7 @@ public static class PocketUpgradeSerialisers {
}
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",
() -> 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 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")
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 {
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",
() -> ConstantLootConditionSerializer.type(BlockNamedEntityLootCondition.INSTANCE));
@ -344,18 +344,18 @@ public static class LootItemConditionTypes {
}
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) {
return REGISTRY.register(name, () -> new SimpleRecipeSerializer<>(factory));
private static <T extends CustomRecipe> RegistryEntry<SimpleCraftingRecipeSerializer<T>> simple(String name, SimpleCraftingRecipeSerializer.Factory<T> 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<SimpleRecipeSerializer<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<SimpleRecipeSerializer<PrintoutRecipe>> PRINTOUT = simple("printout", PrintoutRecipe::new);
public static final RegistryEntry<SimpleRecipeSerializer<DiskRecipe>> DISK = simple("disk", DiskRecipe::new);
public static final RegistryEntry<SimpleCraftingRecipeSerializer<TurtleUpgradeRecipe>> TURTLE_UPGRADE = simple("turtle_upgrade", TurtleUpgradeRecipe::new);
public static final RegistryEntry<SimpleCraftingRecipeSerializer<PocketComputerUpgradeRecipe>> POCKET_COMPUTER_UPGRADE = simple("pocket_computer_upgrade", PocketComputerUpgradeRecipe::new);
public static final RegistryEntry<SimpleCraftingRecipeSerializer<PrintoutRecipe>> PRINTOUT = simple("printout", PrintoutRecipe::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<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);
@ -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_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.arguments.ArgumentType;
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.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
@ -25,7 +25,7 @@ public class ArgumentUtils {
public static <A extends ArgumentType<?>> JsonObject serializeToJson(ArgumentTypeInfo.Template<A> template) {
var object = new JsonObject();
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();
serializeToJson(properties, template.type(), template);
@ -45,12 +45,12 @@ public static <A extends ArgumentType<?>> void serializeToNetwork(FriendlyByteBu
@SuppressWarnings("unchecked")
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);
}
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");
return type.deserializeFromNetwork(buffer);
}

View File

@ -11,13 +11,14 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
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.RecipeSerializer;
import net.minecraft.world.level.Level;
public final class ColourableRecipe extends CustomRecipe {
public ColourableRecipe(ResourceLocation id) {
super(id);
public ColourableRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id, category);
}
@Override

View File

@ -15,7 +15,7 @@
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.commands.CommandSourceStack;
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.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
@ -255,7 +255,7 @@ private Level getLevel(Optional<String> id) throws LuaException {
var dimensionId = ResourceLocation.tryParse(id.get());
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");
return level;

View File

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

View File

@ -13,14 +13,15 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
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.RecipeSerializer;
public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe {
private final ComputerFamily family;
public ComputerFamilyRecipe(ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
super(identifier, group, width, height, ingredients, result);
public ComputerFamilyRecipe(ResourceLocation identifier, String group, CraftingBookCategory category, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family) {
super(identifier, group, category, width, height, ingredients, result);
this.family = family;
}
@ -29,31 +30,33 @@ public ComputerFamily getFamily() {
}
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
public T fromJson(ResourceLocation identifier, JsonObject json) {
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 template = RecipeUtil.getTemplate(json);
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
public T fromNetwork(ResourceLocation identifier, FriendlyByteBuf buf) {
var width = 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);
for (var i = 0; i < ingredients.size(); i++) ingredients.set(i, Ingredient.fromNetwork(buf));
var result = buf.readItem();
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
@ -61,6 +64,7 @@ public void toNetwork(FriendlyByteBuf buf, T recipe) {
buf.writeVarInt(recipe.getWidth());
buf.writeVarInt(recipe.getHeight());
buf.writeUtf(recipe.getGroup());
buf.writeEnum(recipe.category());
for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buf);
buf.writeItem(recipe.getResultItem());
buf.writeEnum(recipe.getFamily());

View File

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

View File

@ -6,7 +6,7 @@
package dan200.computercraft.shared.details;
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 java.util.HashMap;
@ -16,7 +16,7 @@ public class BlockDetails {
public static void fillBasic(Map<? super String, Object> data, BlockReference block) {
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<>();
for (Map.Entry<Property<?>, ? extends Comparable<?>> entry : state.getValues().entrySet()) {

View File

@ -5,7 +5,7 @@
*/
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.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));
}
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();
}
}

View File

@ -6,13 +6,13 @@
package dan200.computercraft.shared.details;
import com.google.gson.JsonParseException;
import dan200.computercraft.mixin.CreativeModeTabAccessor;
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 net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.EnchantedBookItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
@ -25,7 +25,7 @@
*/
public class ItemDetails {
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());
return data;
}
@ -98,14 +98,15 @@ private static Component parseTextComponent(Tag x) {
private static List<Map<String, Object>> getItemGroups(ItemStack stack) {
List<Map<String, Object>> groups = new ArrayList<>(1);
for (var group : PlatformHelper.get().getCreativeTabs(stack)) {
if (group == null) continue;
CreativeModeTabs.tabs().stream().filter(x -> x.contains(stack)).forEach(group -> {
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());
groups.add(groupData);
}
});
return groups;
}
@ -152,7 +153,7 @@ private static void addEnchantments(ListTag rawEnchants, ArrayList<Map<String, O
var enchantment = entry.getKey();
var level = entry.getValue();
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("displayName", enchantment.getFullname(level).getString());
enchants.add(enchant);

View File

@ -20,6 +20,7 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
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.Ingredient;
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) {
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) {
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 {

View File

@ -15,11 +15,9 @@
import dan200.computercraft.shared.config.Config;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
@ -44,14 +42,6 @@ public static ItemStack createFromIDAndColour(int id, @Nullable String label, in
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
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> list, TooltipFlag options) {
if (options.isAdvanced()) {

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@
import dan200.computercraft.shared.network.NetworkMessage;
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.network.FriendlyByteBuf;
import net.minecraft.sounds.SoundEvent;
@ -41,14 +41,14 @@ public PlayRecordClientMessage(BlockPos pos) {
public PlayRecordClientMessage(FriendlyByteBuf buf) {
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;
}
@Override
public void toBytes(FriendlyByteBuf buf) {
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);
}

View File

@ -27,10 +27,10 @@ public class SpeakerPlayClientMessage implements NetworkMessage<ClientNetworkCon
private final float volume;
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.pos = pos.asMessage();
sound = event;
this.sound = sound;
this.volume = volume;
this.pitch = pitch;
}

View File

@ -12,7 +12,7 @@
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IDynamicPeripheral;
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 javax.annotation.Nullable;
@ -26,7 +26,7 @@ class GenericPeripheral implements IDynamicPeripheral {
private final 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.type = name != null ? name : type.toString();
this.additionalTypes = additionalTypes;

View File

@ -6,15 +6,12 @@
package dan200.computercraft.shared.peripheral.modem.wired;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.platform.Registries;
import dan200.computercraft.shared.platform.RegistryWrappers;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult;
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.level.Level;
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));
}
@Override
public void fillItemCategory(CreativeModeTab group, NonNullList<ItemStack> list) {
if (allowedIn(group)) list.add(new ItemStack(this));
}
@Override
public String getDescriptionId() {
if (translationKey == null) {
translationKey = Util.makeDescriptionId("block", Registries.ITEMS.getKey(this));
translationKey = Util.makeDescriptionId("block", RegistryWrappers.ITEMS.getKey(this));
}
return translationKey;
}

View File

@ -18,13 +18,14 @@
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.platform.Registries;
import dan200.computercraft.shared.util.PauseAwareTimer;
import net.minecraft.ResourceLocationException;
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.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
@ -64,11 +65,11 @@ public abstract class SpeakerPeripheral implements IPeripheral {
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 boolean shouldStop;
private @Nullable PendingSound pendingSound = null;
private @Nullable PendingSound<ResourceLocation> pendingSound = null;
private @Nullable DfpwmState dfpwmState;
public void update() {
@ -85,7 +86,7 @@ public void update() {
lastPlayTime = clock;
server.getPlayerList().broadcast(
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();
@ -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
// method), so we don't need to bother locking that.
boolean shouldStop;
PendingSound sound;
PendingSound<ResourceLocation> sound;
DfpwmState dfpwmState;
synchronized (lock) {
sound = pendingSound;
@ -122,7 +123,7 @@ public void update() {
if (sound != null) {
lastPlayTime = clock;
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
);
syncedPosition(position);
@ -218,7 +219,7 @@ public final boolean playNote(ILuaContext context, String instrumentA, Optional<
synchronized (pendingNotes) {
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;
}
@ -260,7 +261,7 @@ public final boolean playSound(ILuaContext context, String name, Optional<Double
synchronized (lock) {
if (dfpwmState != null && dfpwmState.isPlaying()) return false;
dfpwmState = null;
pendingSound = new PendingSound(identifier, volume, pitch);
pendingSound = new PendingSound<>(identifier, volume, pitch);
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();
}
/**
* 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.
*
@ -81,7 +74,7 @@ static PlatformHelper get() {
* @param <T> The type of object stored in this 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.
@ -262,12 +255,13 @@ static PlatformHelper get() {
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.
* @return The creative tabs the item belongs to.
* @param tab The tab to get
* @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

View File

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

View File

@ -24,7 +24,6 @@
import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider;
import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.ChatFormatting;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
@ -36,7 +35,6 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
@ -70,13 +68,6 @@ public ItemStack create(int id, @Nullable String label, int colour, @Nullable IP
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) {
var upgrade = getUpgrade(stack);

View File

@ -14,13 +14,14 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
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.RecipeSerializer;
import net.minecraft.world.level.Level;
public final class PocketComputerUpgradeRecipe extends CustomRecipe {
public PocketComputerUpgradeRecipe(ResourceLocation identifier) {
super(identifier);
public PocketComputerUpgradeRecipe(ResourceLocation identifier, CraftingBookCategory category) {
super(identifier, category);
}
@Override

View File

@ -14,12 +14,10 @@
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
import net.minecraft.core.NonNullList;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.LayeredCauldronBlock;
@ -56,16 +54,6 @@ public ItemStack create(
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
public Component getName(ItemStack stack) {
var baseString = getDescriptionId(stack);

View File

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

View File

@ -15,13 +15,14 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
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.RecipeSerializer;
import net.minecraft.world.level.Level;
public final class TurtleUpgradeRecipe extends CustomRecipe {
public TurtleUpgradeRecipe(ResourceLocation id) {
super(id);
public TurtleUpgradeRecipe(ResourceLocation id, CraftingBookCategory category) {
super(id, category);
}
@Override

View File

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

View File

@ -6,7 +6,7 @@
package dan200.computercraft.shared.util;
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.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;
try {
id = new ResourceLocation(name);

View File

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

View File

@ -15,17 +15,14 @@
import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
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.item.crafting.*;
import net.minecraft.world.level.Level;
public final class ImpostorShapelessRecipe extends ShapelessRecipe {
private final String group;
private ImpostorShapelessRecipe(ResourceLocation id, String group, ItemStack result, NonNullList<Ingredient> ingredients) {
super(id, group, result, ingredients);
private ImpostorShapelessRecipe(ResourceLocation id, String group, CraftingBookCategory category, ItemStack result, NonNullList<Ingredient> ingredients) {
super(id, group, category, result, ingredients);
this.group = group;
}
@ -52,7 +49,8 @@ public RecipeSerializer<?> getSerializer() {
public static final class Serializer implements RecipeSerializer<ImpostorShapelessRecipe> {
@Override
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"));
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"));
return new ImpostorShapelessRecipe(id, s, result, ingredients);
return new ImpostorShapelessRecipe(id, group, category, result, ingredients);
}
private NonNullList<Ingredient> readIngredients(JsonArray arrays) {
@ -76,19 +74,21 @@ private NonNullList<Ingredient> readIngredients(JsonArray arrays) {
@Override
public ImpostorShapelessRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
var s = buffer.readUtf(32767);
var i = buffer.readVarInt();
var items = NonNullList.withSize(i, Ingredient.EMPTY);
var group = buffer.readUtf();
var category = buffer.readEnum(CraftingBookCategory.class);
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));
var result = buffer.readItem();
return new ImpostorShapelessRecipe(id, s, result, items);
return new ImpostorShapelessRecipe(id, group, category, result, items);
}
@Override
public void toNetwork(FriendlyByteBuf buffer, ImpostorShapelessRecipe recipe) {
buffer.writeUtf(recipe.getGroup());
buffer.writeEnum(recipe.category());
buffer.writeVarInt(recipe.getIngredients().size());
for (var ingredient : recipe.getIngredients()) ingredient.toNetwork(buffer);

View File

@ -4,6 +4,7 @@ accessWidener v1 named
# 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 class net/minecraft/world/item/CreativeModeTab$Output
# Containers
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
# Data generators
accessible class net/minecraft/data/loot/LootTableProvider$SubProviderEntry
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 modelOutput Ljava/util/function/BiConsumer;

View File

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

View File

@ -59,7 +59,7 @@
@AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class })
public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper {
@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");
}
@ -113,11 +113,6 @@ public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, Leve
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
}
@Override
public CreativeModeTab getCreativeTab() {
throw new UnsupportedOperationException("Cannot get creative tab inside tests");
}
@Override
public List<TagKey<Item>> getDyeTags() {
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");
}
@Nullable
@Override
public Collection<CreativeModeTab> getCreativeTabs(ItemStack stack) {
throw new UnsupportedOperationException("Cannot get creative tabs inside tests");
public ResourceLocation getCreativeTabId(CreativeModeTab tab) {
return null;
}
@Override

View File

@ -7,15 +7,15 @@
import dan200.computercraft.api.filesystem.Mount;
import net.minecraft.Util;
import net.minecraft.server.packs.FolderPackResources;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.PathPackResources;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.util.Unit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -32,7 +32,7 @@ public void before() {
var manager = new ReloadableResourceManager(PackType.SERVER_DATA);
var done = new CompletableFuture<Unit>();
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);

View File

@ -17,7 +17,7 @@
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.data.PrettyJsonWriter;
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.network.chat.Component;
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<>();
// First find all CC items
for (var item : Registries.ITEMS) {
if (Registries.ITEMS.getKey(item).getNamespace().equals(ComputerCraftAPI.MOD_ID)) items.add(item);
for (var item : RegistryWrappers.ITEMS) {
if (RegistryWrappers.ITEMS.getKey(item).getNamespace().equals(ComputerCraftAPI.MOD_ID)) items.add(item);
}
// Now find all CC recipes.
for (var recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) {
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;
}
if (result.hasTag()) {
@ -122,7 +122,7 @@ private static void export(Path root, ImageRenderer renderer) throws IOException
renderer.setupState();
for (var item : items) {
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());
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.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.FogRenderer;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL12;
import javax.annotation.Nullable;
@ -37,7 +37,7 @@ public ImageRenderer() {
public void setupState() {
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();
transform.pushPose();

View File

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

View File

@ -19,7 +19,7 @@ class Loot_Test {
/**
* 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 {
thenExecute {
val pos = BlockPos(2, 2, 2)

View File

@ -2,7 +2,7 @@
import dan200.computercraft.gametest.core.MinecraftExtensions
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.Screenshot
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.
*/
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
@Suppress("UNCHECKED_CAST")

View File

@ -10,7 +10,7 @@
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor
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.shared.ItemStackMatcher.isStack
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 = "") {
val state = getBlockState(pos)
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)
} else if (state.getValue(property) != value) {
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@
class ItemFrameRendererMixin {
@Inject(
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
)
@SuppressWarnings("UnusedMethod")

View File

@ -166,6 +166,7 @@
"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.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.copy": "Copy to clipboard",
"gui.computercraft.tooltip.disk_id": "Disk ID: %s",

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