mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 12:10:30 +00:00
Allow changing turtle upgrades from the GUI
This adds two slots to the right of the turtle interface which contain the left and right upgrades of a turtle. - Add turtle_upgrade_{left,right} indicators, which used as the background texture for the two upgrade slots. In order to use Slot.getNoItemIcon, we need to bake these into the block texture atlas. This is done with the new atlas JSON and a data generator - it's mostly pretty simple, but we do now need a client-side data generator, which is a little ugly to do. - Add a new UpgradeContainer/UpgradeSlot, which exposes a turtle's upgrades in an inventory-like way. - Update the turtle menu and screen to handle these new slots.
This commit is contained in:
parent
8ccd5a560c
commit
7b4ba11fb4
@ -26,9 +26,11 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
|
||||
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_normal.png");
|
||||
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_advanced.png");
|
||||
|
||||
private static final int TEX_WIDTH = 254;
|
||||
private static final int TEX_WIDTH = 278;
|
||||
private static final int TEX_HEIGHT = 217;
|
||||
|
||||
private static final int FULL_TEX_SIZE = 512;
|
||||
|
||||
public TurtleScreen(TurtleMenu container, Inventory player, Component title) {
|
||||
super(container, player, title, BORDER);
|
||||
|
||||
@ -45,16 +47,16 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
|
||||
protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) {
|
||||
var advanced = family == ComputerFamily.ADVANCED;
|
||||
RenderSystem.setShaderTexture(0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL);
|
||||
blit(transform, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT);
|
||||
blit(transform, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE);
|
||||
|
||||
// Render selected slot
|
||||
var slot = getMenu().getSelectedSlot();
|
||||
if (slot >= 0) {
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
var slotX = slot % 4;
|
||||
var slotY = slot / 4;
|
||||
blit(transform,
|
||||
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18,
|
||||
0, 217, 24, 24
|
||||
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0,
|
||||
0, 217, 24, 24, FULL_TEX_SIZE, FULL_TEX_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.data.client;
|
||||
|
||||
import dan200.computercraft.data.DataProviders;
|
||||
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
|
||||
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
|
||||
import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A version of {@link DataProviders} which relies on client-side classes.
|
||||
* <p>
|
||||
* This is called from {@link DataProviders#add(DataProviders.GeneratorSink)}.
|
||||
*/
|
||||
public final class ClientDataProviders {
|
||||
private ClientDataProviders() {
|
||||
}
|
||||
|
||||
public static void add(DataProviders.GeneratorSink generator) {
|
||||
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||
out.accept(new ResourceLocation("blocks"), List.of(
|
||||
new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()),
|
||||
new SingleFile(UpgradeSlot.RIGHT_UPGRADE, Optional.empty())
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
@ -41,6 +41,15 @@ public final class DataProviders {
|
||||
generator.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels);
|
||||
|
||||
generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades));
|
||||
|
||||
// Unfortunately we rely on some client-side classes in this code. We just load in the client side data provider
|
||||
// and invoke that.
|
||||
try {
|
||||
Class.forName("dan200.computercraft.data.client.ClientDataProviders")
|
||||
.getMethod("add", GeneratorSink.class).invoke(null, generator);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface GeneratorSink {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.shared.turtle.inventory;
|
||||
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
@ -29,12 +30,13 @@ public final class TurtleMenu extends AbstractComputerMenu {
|
||||
public static final int PLAYER_START_Y = 134;
|
||||
public static final int TURTLE_START_X = SIDEBAR_WIDTH + 175;
|
||||
public static final int PLAYER_START_X = SIDEBAR_WIDTH + BORDER;
|
||||
public static final int UPGRADE_START_X = SIDEBAR_WIDTH + 254;
|
||||
|
||||
private final ContainerData data;
|
||||
|
||||
private TurtleMenu(
|
||||
int id, Predicate<Player> canUse, ComputerFamily family, @Nullable ServerComputer computer, @Nullable ComputerContainerData menuData,
|
||||
Inventory playerInventory, Container inventory, ContainerData data
|
||||
Inventory playerInventory, Container inventory, Container turtleUpgrades, ContainerData data
|
||||
) {
|
||||
super(ModRegistry.Menus.TURTLE.get(), id, canUse, family, computer, menuData);
|
||||
this.data = data;
|
||||
@ -58,19 +60,24 @@ public final class TurtleMenu extends AbstractComputerMenu {
|
||||
for (var x = 0; x < 9; x++) {
|
||||
addSlot(new Slot(playerInventory, x, PLAYER_START_X + x * 18, PLAYER_START_Y + 3 * 18 + 5));
|
||||
}
|
||||
|
||||
// Turtle upgrades
|
||||
addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.LEFT, 0, UPGRADE_START_X, PLAYER_START_Y + 1));
|
||||
addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.RIGHT, 1, UPGRADE_START_X, PLAYER_START_Y + 1 + 18));
|
||||
}
|
||||
|
||||
public static TurtleMenu ofBrain(int id, Inventory player, TurtleBrain turtle) {
|
||||
return new TurtleMenu(
|
||||
// Laziness in turtle.getOwner() is important here!
|
||||
id, p -> turtle.getOwner().stillValid(p), turtle.getFamily(), turtle.getOwner().createServerComputer(), null,
|
||||
player, turtle.getInventory(), (SingleContainerData) turtle::getSelectedSlot
|
||||
player, turtle.getInventory(), new UpgradeContainer(turtle), (SingleContainerData) turtle::getSelectedSlot
|
||||
);
|
||||
}
|
||||
|
||||
public static TurtleMenu ofMenuData(int id, Inventory player, ComputerContainerData data) {
|
||||
return new TurtleMenu(
|
||||
id, x -> true, data.family(), null, data, player, new SimpleContainer(TurtleBlockEntity.INVENTORY_SIZE), new SimpleContainerData(1)
|
||||
id, x -> true, data.family(), null, data,
|
||||
player, new SimpleContainer(TurtleBlockEntity.INVENTORY_SIZE), new SimpleContainer(2), new SimpleContainerData(1)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,108 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.turtle.inventory;
|
||||
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.impl.TurtleUpgrades;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fake {@link Container} which exposes the {@linkplain ITurtleAccess#getUpgrade(TurtleSide) upgrades} a turtle has.
|
||||
*
|
||||
* @see TurtleMenu
|
||||
* @see UpgradeSlot
|
||||
*/
|
||||
class UpgradeContainer implements Container {
|
||||
private static final int SIZE = 2;
|
||||
|
||||
private final ITurtleAccess turtle;
|
||||
|
||||
private final List<ITurtleUpgrade> lastUpgrade = Arrays.asList(null, null);
|
||||
private final NonNullList<ItemStack> lastStack = NonNullList.withSize(2, ItemStack.EMPTY);
|
||||
|
||||
UpgradeContainer(ITurtleAccess turtle) {
|
||||
this.turtle = turtle;
|
||||
}
|
||||
|
||||
private TurtleSide getSide(int slot) {
|
||||
return switch (slot) {
|
||||
case 0 -> TurtleSide.LEFT;
|
||||
case 1 -> TurtleSide.RIGHT;
|
||||
default -> throw new IllegalArgumentException("Invalid slot " + slot);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
var upgrade = turtle.getUpgrade(getSide(slot));
|
||||
|
||||
// We don't want to return getCraftingItem directly here, as consumers may mutate the stack (they shouldn't!,
|
||||
// but if they do it's a pain to track down). To avoid recreating the stack each tick, we maintain a simple
|
||||
// cache.
|
||||
if (upgrade == lastUpgrade.get(slot)) return lastStack.get(slot);
|
||||
|
||||
var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getCraftingItem().copy();
|
||||
lastUpgrade.set(slot, upgrade);
|
||||
lastStack.set(slot, stack);
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int slot, ItemStack itemStack) {
|
||||
turtle.setUpgrade(getSide(slot), TurtleUpgrades.instance().get(itemStack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (var i = 0; i < SIZE; i++) {
|
||||
if (!getItem(i).isEmpty()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(int slot, int count) {
|
||||
return count <= 0 ? ItemStack.EMPTY : removeItemNoUpdate(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int slot) {
|
||||
var current = getItem(slot);
|
||||
setItem(slot, ItemStack.EMPTY);
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
for (var i = 0; i < SIZE; i++) setItem(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.turtle.inventory;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.impl.TurtleUpgrades;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.inventory.InventoryMenu;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A slot in the turtle UI which holds the turtle's current upgrade.
|
||||
*
|
||||
* @see TurtleMenu
|
||||
*/
|
||||
public class UpgradeSlot extends Slot {
|
||||
public static final ResourceLocation LEFT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_left");
|
||||
public static final ResourceLocation RIGHT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_right");
|
||||
|
||||
private final TurtleSide side;
|
||||
|
||||
public UpgradeSlot(Container container, TurtleSide side, int slot, int xPos, int yPos) {
|
||||
super(container, slot, xPos, yPos);
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace(ItemStack stack) {
|
||||
return TurtleUpgrades.instance().get(stack) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Pair<ResourceLocation, ResourceLocation> getNoItemIcon() {
|
||||
return Pair.of(InventoryMenu.BLOCK_ATLAS, side == TurtleSide.LEFT ? LEFT_UPGRADE : RIGHT_UPGRADE);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 983 B After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 129 B |
@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
Binary file not shown.
After Width: | Height: | Size: 129 B |
@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
@ -119,7 +119,7 @@ loom {
|
||||
|
||||
register("data") {
|
||||
configName = "Datagen"
|
||||
server()
|
||||
client()
|
||||
|
||||
runDir("run/dataGen")
|
||||
property("cct.pretty-json")
|
||||
|
6
projects/fabric/src/generated/resources/assets/minecraft/atlases/blocks.json
generated
Normal file
6
projects/fabric/src/generated/resources/assets/minecraft/atlases/blocks.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"sources": [
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_left"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_right"}
|
||||
]
|
||||
}
|
6
projects/forge/src/generated/resources/assets/minecraft/atlases/blocks.json
generated
Normal file
6
projects/forge/src/generated/resources/assets/minecraft/atlases/blocks.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"sources": [
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_left"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_right"}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user