1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-07 08:52:59 +00:00

Introduce UpgradeData as main record for passing upgrade with data here and there

This commit is contained in:
SirEdvin
2023-06-18 18:16:31 +03:00
parent 593a1e2e8e
commit dcd895edbc
21 changed files with 277 additions and 114 deletions

View File

@@ -8,6 +8,7 @@ import com.mojang.authlib.GameProfile;
import dan200.computercraft.api.lua.ILuaCallback;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.upgrades.UpgradeData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@@ -254,6 +255,16 @@ public interface ITurtleAccess {
@Nullable
ITurtleUpgrade getUpgrade(TurtleSide side);
default @Nullable UpgradeData<ITurtleUpgrade> getUpgradeData(TurtleSide side) {
var upgrade = getUpgrade(side);
if (upgrade == null) {
return null;
}
return new UpgradeData<>(
upgrade, getUpgradeNBTData(side)
);
}
/**
* Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data.
*
@@ -263,6 +274,15 @@ public interface ITurtleAccess {
*/
void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade);
/**
* Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data.
*
* @param side The side to set the upgrade on.
* @param upgrade The upgrade to set, may be {@code null} to clear.
* @see #getUpgrade(TurtleSide)
*/
void setUpgrade(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade);
/**
* Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
*

View File

@@ -52,14 +52,45 @@ public interface UpgradeBase {
*/
ItemStack getCraftingItem();
default @Nonnull ItemStack produceCraftingItem(@Nonnull CompoundTag upgradeData) {
/**
* Return an item stack representing the instance of upgrade with passed upgrade data.
* By default, this method output equals to {@link #getCraftingItem()} because default behavior of
* upgrades is ignored any upgrade data.
* <p>
* But if your upgrade required this, you can redefine this behavior and pass some information from upgrade data
* to item stack. Please, use this method with cautions.
* <p>
* This method will be used by {@code turtle.unequipLeft()} and {@code pocket.unequipBack()} to determine item stack
* that should be placed inside inventory
*
* @param upgradeData NBT information that was stored inside turtle/pocket by upgrade
* @return The item stack, that should be stored inside inventory
*/
default @Nonnull ItemStack getUpgradeItem(@Nonnull CompoundTag upgradeData) {
return getCraftingItem();
}
default @Nonnull CompoundTag produceUpgradeData(@Nonnull ItemStack stack) {
/**
* Returns initial upgrade data, that should be set for turtle/pocket, that uses this upgrade, based on item stack
* that used for installing upgrade right now.
* @param stack Item Stack that used for upgrade
* @return Upgrade NBT data that should be set in time of adding this upgrade to turtle/pocket
*/
default @Nonnull CompoundTag getUpgradeData(@Nonnull ItemStack stack) {
return new CompoundTag();
}
/**
* Specific hook, that allow you to filter data, that should be stored when turtle was broken.
* Use this in cases when you don't need to store all upgrade data by default, and you want to change this
* behavior, for example, as modem do.
* @param upgradeData NBT data that currently stored for this upgrade
* @return filtered version of this data, by default just all of it
*/
default @Nonnull CompoundTag getPersistedData(CompoundTag upgradeData) {
return upgradeData;
}
/**
* Determine if an item is suitable for being used for this upgrade.
* <p>

View File

@@ -0,0 +1,64 @@
package dan200.computercraft.api.upgrades;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nullable;
public record UpgradeData<T extends UpgradeBase>(T upgrade, CompoundTag data) {
/** Utility function, that provide ability to build default version of upgrade data
* based only on upgrade object.
* @param upgrade any upgrade
* @param <T> Upgrade class
* @return default instance of upgrade data
*/
public static <T extends UpgradeBase> UpgradeData<T> wrap(T upgrade) {
return new UpgradeData<>(upgrade, upgrade.getUpgradeData(upgrade.getCraftingItem()));
}
/** Transform UpgradeData to it persistent variant that should be stored, when turtle or pocket items stop functioning.
* @see UpgradeBase#getPersistedData(CompoundTag)
* @param upgrade UpgradeData that should be persisted or null
* @return UpgradeData instance with only persistent upgrade information or null
*/
public static <T extends UpgradeBase> @Nullable UpgradeData<T> persist(@Nullable UpgradeData<T> upgrade) {
if (upgrade == null) {
return null;
}
return new UpgradeData<>(
upgrade.upgrade, upgrade.upgrade.getPersistedData(upgrade.data)
);
}
/** Utility functions, that allows to compare two upgrade data and check if they have same upgrades.
*
* @param first first upgrade data
* @param second second upgrade data
* @param <T> UpgradeBase class
* @return true if upgrades data have same upgrades or both null
*/
public static <T extends UpgradeBase> boolean isSame(@Nullable UpgradeData<T> first, @Nullable UpgradeData<T> second) {
if (first == null) {
return second == null;
}
if (second == null) {
return false;
}
return first.upgrade == second.upgrade;
}
/** Build ItemStack from upgrade and data pair.
* @return ItemStack that correspond current upgrade + data pair
*/
public ItemStack getUpgradeItem() {
return upgrade.getUpgradeItem(data);
}
/** Wrapper that just pass upgrade ID.
* @return upgrade id
*/
public ResourceLocation getUpgradeID() {
return upgrade.getUpgradeID();
}
}

View File

@@ -82,7 +82,9 @@ public final class TurtleModelParts {
var label = turtle.getLabel(stack);
var flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
return new Combination(colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip);
return new Combination(
colour != -1, leftUpgrade == null ? null : leftUpgrade.upgrade(),
rightUpgrade == null ? null : rightUpgrade.upgrade(), overlay, christmas, flip);
}
public List<BakedModel> buildModel(Combination combo) {

View File

@@ -8,6 +8,7 @@ import com.google.gson.JsonObject;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.util.Colour;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.common.IColouredItem;
@@ -105,12 +106,12 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
*/
private void turtleUpgrades(Consumer<FinishedRecipe> add) {
for (var turtleItem : turtleItems()) {
var base = turtleItem.create(-1, null, -1, null, null, 0, null, null, null);
var base = turtleItem.create(-1, null, -1, null, null, 0, null);
var nameId = turtleItem.getFamily().name().toLowerCase(Locale.ROOT);
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
var result = turtleItem.create(-1, null, -1, null, upgrade, -1, null, null, null);
var result = turtleItem.create(-1, null, -1, null, UpgradeData.wrap(upgrade), -1, null);
ShapedRecipeBuilder
.shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId))
@@ -146,7 +147,7 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
var nameId = pocket.getFamily().name().toLowerCase(Locale.ROOT);
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
var result = pocket.create(-1, null, -1, upgrade);
var result = pocket.create(-1, null, -1, UpgradeData.wrap(upgrade));
ShapedRecipeBuilder
.shaped(RecipeCategory.REDSTONE, result.getItem())
.group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId))
@@ -189,7 +190,7 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
private void turtleOverlay(Consumer<FinishedRecipe> add, String overlay, Consumer<ShapelessRecipeBuilder> build) {
for (var turtleItem : turtleItems()) {
var base = turtleItem.create(-1, null, -1, null, null, 0, null, null, null);
var base = turtleItem.create(-1, null, -1, null, null, 0, null);
var nameId = turtleItem.getFamily().name().toLowerCase(Locale.ROOT);
var group = "%s:turtle_%s_overlay".formatted(ComputerCraftAPI.MOD_ID, nameId);

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.impl;
import com.google.gson.*;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.upgrades.UpgradeBase;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.core.Registry;
@@ -74,13 +75,16 @@ public class UpgradeManager<R extends UpgradeSerialiser<? extends T>, T extends
}
@Nullable
public T get(ItemStack stack) {
public UpgradeData<T> get(ItemStack stack) {
if (stack.isEmpty()) return null;
for (var wrapper : current.values()) {
var craftingStack = wrapper.upgrade().getCraftingItem();
if (!craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade().isItemSuitable(stack)) {
return wrapper.upgrade();
return new UpgradeData<>(
wrapper.upgrade,
wrapper.upgrade.getUpgradeData(stack)
);
}
}

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.util.Colour;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.impl.TurtleUpgrades;
@@ -444,14 +445,14 @@ public final class ModRegistry {
}
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
out.accept(turtle.create(-1, null, -1, null, null, 0, null, null, null));
out.accept(turtle.create(-1, null, -1, null, null, 0, null));
TurtleUpgrades.getVanillaUpgrades()
.map(x -> turtle.create(-1, null, -1, null, x, 0, null, null, null))
.map(x -> turtle.create(-1, null, -1, null, UpgradeData.wrap(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);
PocketUpgrades.getVanillaUpgrades().map(x -> pocket.create(-1, null, -1, UpgradeData.wrap(x))).forEach(out::accept);
}
}

View File

@@ -5,6 +5,7 @@
package dan200.computercraft.shared.integration;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.ModRegistry;
@@ -56,14 +57,14 @@ public final class RecipeModHelpers {
for (var turtleSupplier : TURTLES) {
var turtle = turtleSupplier.get();
for (var upgrade : TurtleUpgrades.instance().getUpgrades()) {
upgradeItems.add(turtle.create(-1, null, -1, null, upgrade, 0, null, null, null));
upgradeItems.add(turtle.create(-1, null, -1, null, UpgradeData.wrap(upgrade), 0, null));
}
}
for (var pocketSupplier : POCKET_COMPUTERS) {
var pocket = pocketSupplier.get();
for (var upgrade : PocketUpgrades.instance().getUpgrades()) {
upgradeItems.add(pocket.create(-1, null, -1, upgrade));
upgradeItems.add(pocket.create(-1, null, -1, UpgradeData.wrap(upgrade)));
}
}

View File

@@ -9,6 +9,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeBase;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
@@ -118,13 +119,16 @@ public class UpgradeRecipeGenerator<T> {
List<T> recipes = new ArrayList<>();
var ingredient = Ingredient.of(stack);
for (var upgrade : turtleUpgrades) {
if (upgrade.turtle == null) {
continue;
}
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
if (left == null) {
recipes.add(turtle(ingredient, upgrade.ingredient, turtleWith(stack, upgrade.turtle, right)));
recipes.add(turtle(ingredient, upgrade.ingredient, turtleWith(stack, UpgradeData.wrap(upgrade.turtle), right)));
}
if (right == null) {
recipes.add(turtle(upgrade.ingredient, ingredient, turtleWith(stack, left, upgrade.turtle)));
recipes.add(turtle(upgrade.ingredient, ingredient, turtleWith(stack, left, UpgradeData.wrap(upgrade.turtle))));
}
}
@@ -137,7 +141,10 @@ public class UpgradeRecipeGenerator<T> {
List<T> recipes = new ArrayList<>();
var ingredient = Ingredient.of(stack);
for (var upgrade : pocketUpgrades) {
recipes.add(pocket(upgrade.ingredient, ingredient, pocketWith(stack, upgrade.pocket)));
if (upgrade.pocket == null) {
continue;
}
recipes.add(pocket(upgrade.ingredient, ingredient, pocketWith(stack, UpgradeData.wrap(upgrade.pocket))));
}
return Collections.unmodifiableList(recipes);
@@ -187,14 +194,14 @@ public class UpgradeRecipeGenerator<T> {
if (left != null) {
recipes.add(turtle(
Ingredient.of(turtleWith(stack, null, right)),
Ingredient.of(left.getCraftingItem()),
Ingredient.of(left.upgrade().getCraftingItem()),
stack
));
}
if (right != null) {
recipes.add(turtle(
Ingredient.of(right.getCraftingItem()),
Ingredient.of(right.upgrade().getCraftingItem()),
Ingredient.of(turtleWith(stack, left, null)),
stack
));
@@ -206,7 +213,7 @@ public class UpgradeRecipeGenerator<T> {
var back = PocketComputerItem.getUpgrade(stack);
if (back != null) {
recipes.add(pocket(Ingredient.of(back.getCraftingItem()), Ingredient.of(pocketWith(stack, null)), stack));
recipes.add(pocket(Ingredient.of(back.upgrade().getCraftingItem()), Ingredient.of(pocketWith(stack, null)), stack));
}
return Collections.unmodifiableList(recipes);
@@ -215,16 +222,15 @@ public class UpgradeRecipeGenerator<T> {
}
}
private static ItemStack turtleWith(ItemStack stack, @Nullable ITurtleUpgrade left, @Nullable ITurtleUpgrade right) {
private static ItemStack turtleWith(ItemStack stack, @Nullable UpgradeData<ITurtleUpgrade> left, @Nullable UpgradeData<ITurtleUpgrade> right) {
var item = (TurtleItem) stack.getItem();
return item.create(
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack),
left, right, item.getFuelLevel(stack), item.getOverlay(stack),
null, null
left, right, item.getFuelLevel(stack), item.getOverlay(stack)
);
}
private static ItemStack pocketWith(ItemStack stack, @Nullable IPocketUpgrade back) {
private static ItemStack pocketWith(ItemStack stack, @Nullable UpgradeData<IPocketUpgrade> back) {
var item = (PocketComputerItem) stack.getItem();
return item.create(
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack), back
@@ -272,8 +278,8 @@ public class UpgradeRecipeGenerator<T> {
var turtleItem = turtleSupplier.get();
recipes.add(turtle(
ingredient, // Right upgrade, recipe on left
Ingredient.of(turtleItem.create(-1, null, -1, null, null, 0, null, null, null)),
turtleItem.create(-1, null, -1, null, turtle, 0, null, null, null)
Ingredient.of(turtleItem.create(-1, null, -1, null, null, 0, null)),
turtleItem.create(-1, null, -1, null, UpgradeData.wrap(turtle), 0, null)
));
}
}
@@ -284,7 +290,7 @@ public class UpgradeRecipeGenerator<T> {
recipes.add(pocket(
ingredient,
Ingredient.of(pocketItem.create(-1, null, -1, null)),
pocketItem.create(-1, null, -1, pocket)
pocketItem.create(-1, null, -1, UpgradeData.wrap(pocket))
));
}
}

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.shared.pocket.apis;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
import net.minecraft.core.NonNullList;
@@ -57,7 +58,7 @@ public class PocketAPI implements ILuaAPI {
var entity = computer.getEntity();
if (!(entity instanceof Player player)) return new Object[]{ false, "Cannot find player" };
var inventory = player.getInventory();
var previousUpgrade = computer.getUpgrade();
var previousUpgrade = computer.getUpgradeData();
// Attempt to find the upgrade, starting in the main segment, and then looking in the opposite
// one. We start from the position the item is currently in and loop round to the start.
@@ -71,11 +72,10 @@ public class PocketAPI implements ILuaAPI {
if (newUpgrade == null) return new Object[]{ false, "Cannot find a valid upgrade" };
// Remove the current upgrade
if (previousUpgrade != null) storeItem(player, previousUpgrade.produceCraftingItem(computer.getUpgradeNBTData()).copy());
if (previousUpgrade != null) storeItem(player, previousUpgrade.getUpgradeItem().copy());
// Set the new upgrade
computer.setUpgrade(newUpgrade);
computer.getUpgradeNBTData().merge(newUpgrade.produceUpgradeData(newUpgradeItem));
return new Object[]{ true };
}
@@ -91,13 +91,13 @@ public class PocketAPI implements ILuaAPI {
public final Object[] unequipBack() {
var entity = computer.getEntity();
if (!(entity instanceof Player player)) return new Object[]{ false, "Cannot find player" };
var previousUpgrade = computer.getUpgrade();
var previousUpgrade = computer.getUpgradeData();
if (previousUpgrade == null) return new Object[]{ false, "Nothing to unequip" };
computer.setUpgrade(null);
storeItem(player, previousUpgrade.getCraftingItem().copy());
storeItem(player, previousUpgrade.getUpgradeItem().copy());
return new Object[]{ true };
}
@@ -109,13 +109,13 @@ public class PocketAPI implements ILuaAPI {
}
}
private static @Nullable ItemStack findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable IPocketUpgrade previous) {
private static @Nullable ItemStack findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable UpgradeData<IPocketUpgrade> previous) {
for (var i = 0; i < inv.size(); i++) {
var invStack = inv.get((i + start) % inv.size());
if (!invStack.isEmpty()) {
var newUpgrade = PocketUpgrades.instance().get(invStack);
if (newUpgrade != null && newUpgrade != previous) {
if (newUpgrade != null && !UpgradeData.isSame(newUpgrade, previous)) {
// Consume an item from this stack and exit the loop
invStack = invStack.copy();
invStack.shrink(1);

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.shared.pocket.core;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.IPocketAccess;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -112,6 +113,13 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
return upgrade;
}
public @Nullable UpgradeData<IPocketUpgrade> getUpgradeData() {
if (upgrade == null) return null;
return new UpgradeData<>(
upgrade, getUpgradeNBTData()
);
}
/**
* Set the upgrade for this pocket computer, also updating the item stack.
* <p>
@@ -119,13 +127,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
*
* @param upgrade The new upgrade to set it to, may be {@code null}.
*/
public void setUpgrade(@Nullable IPocketUpgrade upgrade) {
if (this.upgrade == upgrade) return;
public void setUpgrade(@Nullable UpgradeData<IPocketUpgrade> upgrade) {
var upgradeInstance = upgrade == null ? null : upgrade.upgrade();
if (this.upgrade == upgradeInstance) return;
synchronized (this) {
PocketComputerItem.setUpgrade(stack, upgrade);
updateUpgradeNBTData();
this.upgrade = upgrade;
this.upgrade = upgradeInstance;
invalidatePeripheral();
}
}

View File

@@ -10,6 +10,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.shared.ModRegistry;
@@ -58,7 +59,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
this.family = family;
}
public static ItemStack create(int id, @Nullable String label, int colour, ComputerFamily family, @Nullable IPocketUpgrade upgrade) {
public static ItemStack create(int id, @Nullable String label, int colour, ComputerFamily family, @Nullable UpgradeData<IPocketUpgrade> upgrade) {
return switch (family) {
case NORMAL -> ModRegistry.Items.POCKET_COMPUTER_NORMAL.get().create(id, label, colour, upgrade);
case ADVANCED -> ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get().create(id, label, colour, upgrade);
@@ -66,11 +67,14 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
};
}
public ItemStack create(int id, @Nullable String label, int colour, @Nullable IPocketUpgrade upgrade) {
public ItemStack create(int id, @Nullable String label, int colour, @Nullable UpgradeData<IPocketUpgrade> upgrade) {
var result = new ItemStack(this);
if (id >= 0) result.getOrCreateTag().putInt(NBT_ID, id);
if (label != null) result.setHoverName(Component.literal(label));
if (upgrade != null) result.getOrCreateTag().putString(NBT_UPGRADE, upgrade.getUpgradeID().toString());
if (upgrade != null) {
result.getOrCreateTag().putString(NBT_UPGRADE, upgrade.getUpgradeID().toString());
if (!upgrade.data().isEmpty()) result.getOrCreateTag().put(NBT_UPGRADE_INFO, upgrade.data());
}
if (colour != -1) result.getOrCreateTag().putInt(NBT_COLOUR, colour);
return result;
}
@@ -79,7 +83,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
var upgrade = getUpgrade(stack);
computer.setLevel((ServerLevel) world);
computer.updateValues(entity, stack, upgrade);
computer.updateValues(entity, stack, upgrade != null ? upgrade.upgrade() : null);
var changed = false;
@@ -104,7 +108,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
}
// Update pocket upgrade
if (upgrade != null) upgrade.update(computer, computer.getPeripheral(ComputerSide.BACK));
if (upgrade != null) upgrade.upgrade().update(computer, computer.getPeripheral(ComputerSide.BACK));
return changed;
}
@@ -139,8 +143,8 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
var stop = false;
var upgrade = getUpgrade(stack);
if (upgrade != null) {
computer.updateValues(player, stack, upgrade);
stop = upgrade.onRightClick(world, computer, computer.getPeripheral(ComputerSide.BACK));
computer.updateValues(player, stack, upgrade.upgrade());
stop = upgrade.upgrade().onRightClick(world, computer, computer.getPeripheral(ComputerSide.BACK));
}
if (!stop) {
@@ -157,7 +161,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
var upgrade = getUpgrade(stack);
if (upgrade != null) {
return Component.translatable(baseString + ".upgraded",
Component.translatable(upgrade.getUnlocalisedAdjective())
Component.translatable(upgrade.upgrade().getUnlocalisedAdjective())
);
} else {
return super.getName(stack);
@@ -183,7 +187,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
if (upgrade != null) {
// If we're a non-vanilla, non-CC upgrade then return whichever mod this upgrade
// belongs to.
var mod = PocketUpgrades.instance().getOwner(upgrade);
var mod = PocketUpgrades.instance().getOwner(upgrade.upgrade());
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
}
@@ -207,7 +211,9 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
setInstanceID(stack, computer.register());
setSessionID(stack, registry.getSessionID());
computer.updateValues(entity, stack, getUpgrade(stack));
var upgrade = getUpgrade(stack);
computer.updateValues(entity, stack, upgrade != null ? upgrade.upgrade() : null);
computer.addAPI(new PocketAPI(computer));
// Only turn on when initially creating the computer, rather than each tick.
@@ -292,22 +298,27 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
return nbt != null && nbt.getBoolean(NBT_ON);
}
public static @Nullable IPocketUpgrade getUpgrade(ItemStack stack) {
public static @Nullable UpgradeData<IPocketUpgrade> getUpgrade(ItemStack stack) {
var compound = stack.getTag();
return compound != null && compound.contains(NBT_UPGRADE)
? PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE)) : null;
if (compound == null || !compound.contains(NBT_UPGRADE)) return null;
var upgrade = PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE));
if (upgrade == null) return null;
return new UpgradeData<>(
upgrade,
compound.getCompound(NBT_UPGRADE_INFO)
);
}
public static void setUpgrade(ItemStack stack, @Nullable IPocketUpgrade upgrade) {
public static void setUpgrade(ItemStack stack, @Nullable UpgradeData<IPocketUpgrade> upgrade) {
var compound = stack.getOrCreateTag();
if (upgrade == null) {
compound.remove(NBT_UPGRADE);
compound.remove(NBT_UPGRADE_INFO);
} else {
compound.putString(NBT_UPGRADE, upgrade.getUpgradeID().toString());
compound.put(NBT_UPGRADE_INFO, upgrade.data());
}
compound.remove(NBT_UPGRADE_INFO);
}
public static CompoundTag getUpgradeInfo(ItemStack stack) {

View File

@@ -5,6 +5,7 @@
package dan200.computercraft.shared.pocket.recipes;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.PocketUpgrades;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
@@ -62,7 +63,7 @@ public final class PocketComputerUpgradeRecipe extends CustomRecipe {
if (PocketComputerItem.getUpgrade(computer) != null) return ItemStack.EMPTY;
// Check for upgrades around the item
IPocketUpgrade upgrade = null;
UpgradeData<IPocketUpgrade> upgrade = null;
for (var y = 0; y < inventory.getHeight(); y++) {
for (var x = 0; x < inventory.getWidth(); x++) {
var item = inventory.getItem(x + y * inventory.getWidth());

View File

@@ -6,6 +6,7 @@ package dan200.computercraft.shared.turtle.blocks;
import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock;
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity;
import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -129,10 +130,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
// Set Upgrades
for (var side : TurtleSide.values()) {
turtle.getAccess().setUpgrade(side, item.getUpgrade(stack, side));
var updateData = item.getUpgradeData(stack, side);
if (updateData != null && !updateData.isEmpty()) {
turtle.getAccess().getUpgradeNBTData(side).merge(updateData);
}
}
turtle.getAccess().setFuelLevel(item.getFuelLevel(stack));
@@ -165,9 +162,9 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
var access = turtle.getAccess();
return TurtleItem.create(
turtle.getComputerID(), turtle.getLabel(), access.getColour(), turtle.getFamily(),
access.getUpgrade(TurtleSide.LEFT), access.getUpgrade(TurtleSide.RIGHT),
access.getFuelLevel(), turtle.getOverlay(),
access.getUpgradeNBTData(TurtleSide.LEFT), access.getUpgradeNBTData(TurtleSide.RIGHT)
UpgradeData.persist(access.getUpgradeData(TurtleSide.LEFT)),
UpgradeData.persist(access.getUpgradeData(TurtleSide.RIGHT)),
access.getFuelLevel(), turtle.getOverlay()
);
}

View File

@@ -13,6 +13,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommand;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.util.Colour;
import dan200.computercraft.impl.TurtleUpgrades;
@@ -529,6 +530,20 @@ public class TurtleBrain implements TurtleAccessInternal {
owner.updateInputsImmediately();
}
@Override
public void setUpgrade(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
if (!setUpgradeDirect(side, upgrade) || owner.getLevel() == null) return;
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
// either the block is newly placed (and so won't have changed) or is being updated with /data, which calls
// updateBlock for us.
BlockEntityHelpers.updateBlock(owner);
// Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
// TODO: Only update peripherals, or even only two sides?
owner.updateInputsImmediately();
}
private boolean setUpgradeDirect(TurtleSide side, @Nullable ITurtleUpgrade upgrade) {
// Remove old upgrade
if (upgrades.containsKey(side)) {
@@ -551,6 +566,13 @@ public class TurtleBrain implements TurtleAccessInternal {
return true;
}
private boolean setUpgradeDirect(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
if (upgrade == null) return setUpgradeDirect(side, (ITurtleUpgrade) null);
var result = setUpgradeDirect(side, upgrade.upgrade());
if (result) upgradeNBTData.put(side, upgrade.data());
return result;
}
@Override
public @Nullable IPeripheral getPeripheral(TurtleSide side) {
return peripherals.get(side);

View File

@@ -5,9 +5,9 @@
package dan200.computercraft.shared.turtle.core;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.turtle.TurtleUtil;
import net.minecraft.nbt.CompoundTag;
public class TurtleEquipCommand implements TurtleCommand {
private final TurtleSide side;
@@ -22,7 +22,7 @@ public class TurtleEquipCommand implements TurtleCommand {
var oldUpgrade = turtle.getUpgrade(side);
// Determine the upgrade to equipLeft
ITurtleUpgrade newUpgrade;
UpgradeData<ITurtleUpgrade> newUpgrade;
var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot());
if (!selectedStack.isEmpty()) {
newUpgrade = TurtleUpgrades.instance().get(selectedStack);
@@ -31,16 +31,12 @@ public class TurtleEquipCommand implements TurtleCommand {
newUpgrade = null;
}
CompoundTag upgradeData = null;
// Do the swapping:
if (newUpgrade != null) {
var upgradeItem = turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1);
upgradeData = newUpgrade.produceUpgradeData(upgradeItem);
turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1);
}
if (oldUpgrade != null) TurtleUtil.storeItemOrDrop(turtle, oldUpgrade.produceCraftingItem(turtle.getUpgradeNBTData(side)).copy());
if (oldUpgrade != null) TurtleUtil.storeItemOrDrop(turtle, oldUpgrade.getUpgradeItem(turtle.getUpgradeNBTData(side)).copy());
turtle.setUpgrade(side, newUpgrade);
if (upgradeData != null) turtle.getUpgradeNBTData(side).merge(upgradeData);
// Animate
if (newUpgrade != null || oldUpgrade != null) {

View File

@@ -8,6 +8,7 @@ import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.common.IColouredItem;
@@ -15,7 +16,6 @@ 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.cauldron.CauldronInteraction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionResult;
@@ -33,24 +33,22 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
public static ItemStack create(
int id, @Nullable String label, int colour, ComputerFamily family,
@Nullable ITurtleUpgrade leftUpgrade, @Nullable ITurtleUpgrade rightUpgrade,
int fuelLevel, @Nullable ResourceLocation overlay,
@Nullable CompoundTag leftUpgradeData, @Nullable CompoundTag rightUpdateData
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade, @Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
int fuelLevel, @Nullable ResourceLocation overlay
) {
return switch (family) {
case NORMAL ->
ModRegistry.Items.TURTLE_NORMAL.get().create(id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay, leftUpgradeData, rightUpdateData);
ModRegistry.Items.TURTLE_NORMAL.get().create(id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay);
case ADVANCED ->
ModRegistry.Items.TURTLE_ADVANCED.get().create(id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay, leftUpgradeData, rightUpdateData);
ModRegistry.Items.TURTLE_ADVANCED.get().create(id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay);
default -> ItemStack.EMPTY;
};
}
public ItemStack create(
int id, @Nullable String label, int colour,
@Nullable ITurtleUpgrade leftUpgrade, @Nullable ITurtleUpgrade rightUpgrade,
int fuelLevel, @Nullable ResourceLocation overlay,
@Nullable CompoundTag leftUpgradeData, @Nullable CompoundTag rightUpdateData
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade, @Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
int fuelLevel, @Nullable ResourceLocation overlay
) {
// Build the stack
var stack = new ItemStack(this);
@@ -62,20 +60,17 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
if (leftUpgrade != null) {
stack.getOrCreateTag().putString(NBT_LEFT_UPGRADE, leftUpgrade.getUpgradeID().toString());
}
if (leftUpgradeData != null && !leftUpgradeData.isEmpty()) {
stack.getOrCreateTag().put(NBT_LEFT_UPGRADE_DATA, leftUpgradeData);
if (!leftUpgrade.data().isEmpty()) {
stack.getOrCreateTag().put(NBT_LEFT_UPGRADE_DATA, leftUpgrade.data());
}
}
if (rightUpgrade != null) {
stack.getOrCreateTag().putString(NBT_RIGHT_UPGRADE, rightUpgrade.getUpgradeID().toString());
if (!rightUpgrade.data().isEmpty()) {
stack.getOrCreateTag().put(NBT_RIGHT_UPGRADE_DATA, rightUpgrade.data());
}
}
if (rightUpdateData != null && !rightUpdateData.isEmpty()) {
stack.getOrCreateTag().put(NBT_RIGHT_UPGRADE_DATA, rightUpdateData);
}
return stack;
}
@@ -86,16 +81,16 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
var right = getUpgrade(stack, TurtleSide.RIGHT);
if (left != null && right != null) {
return Component.translatable(baseString + ".upgraded_twice",
Component.translatable(right.getUnlocalisedAdjective()),
Component.translatable(left.getUnlocalisedAdjective())
Component.translatable(right.upgrade().getUnlocalisedAdjective()),
Component.translatable(left.upgrade().getUnlocalisedAdjective())
);
} else if (left != null) {
return Component.translatable(baseString + ".upgraded",
Component.translatable(left.getUnlocalisedAdjective())
Component.translatable(left.upgrade().getUnlocalisedAdjective())
);
} else if (right != null) {
return Component.translatable(baseString + ".upgraded",
Component.translatable(right.getUnlocalisedAdjective())
Component.translatable(right.upgrade().getUnlocalisedAdjective())
);
} else {
return Component.translatable(baseString);
@@ -110,13 +105,13 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
var left = getUpgrade(stack, TurtleSide.LEFT);
if (left != null) {
var mod = TurtleUpgrades.instance().getOwner(left);
var mod = TurtleUpgrades.instance().getOwner(left.upgrade());
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
}
var right = getUpgrade(stack, TurtleSide.RIGHT);
if (right != null) {
var mod = TurtleUpgrades.instance().getOwner(right);
var mod = TurtleUpgrades.instance().getOwner(right.upgrade());
if (mod != null && !mod.equals(ComputerCraftAPI.MOD_ID)) return mod;
}
@@ -129,25 +124,22 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
getComputerID(stack), getLabel(stack),
getColour(stack), family,
getUpgrade(stack, TurtleSide.LEFT), getUpgrade(stack, TurtleSide.RIGHT),
getFuelLevel(stack), getOverlay(stack),
getUpgradeData(stack, TurtleSide.LEFT), getUpgradeData(stack, TurtleSide.RIGHT)
getFuelLevel(stack), getOverlay(stack)
);
}
public @Nullable ITurtleUpgrade getUpgrade(ItemStack stack, TurtleSide side) {
public @Nullable UpgradeData<ITurtleUpgrade> getUpgrade(ItemStack stack, TurtleSide side) {
var tag = stack.getTag();
if (tag == null) return null;
var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE;
return tag.contains(key) ? TurtleUpgrades.instance().get(tag.getString(key)) : null;
}
public @Nullable CompoundTag getUpgradeData(ItemStack stack, TurtleSide side) {
var tag = stack.getTag();
if (tag == null) return null;
var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE_DATA : NBT_RIGHT_UPGRADE_DATA;
return tag.contains(key) ? tag.getCompound(key) : null;
if (!tag.contains(key)) return null;
var upgrade = TurtleUpgrades.instance().get(tag.getString(key));
if (upgrade == null) return null;
var dataKey = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE_DATA : NBT_RIGHT_UPGRADE_DATA;
return new UpgradeData<>(
upgrade, tag.getCompound(dataKey)
);
}
public @Nullable ResourceLocation getOverlay(ItemStack stack) {

View File

@@ -41,9 +41,7 @@ public class TurtleOverlayRecipe extends ShapelessRecipe {
turtle.getUpgrade(stack, TurtleSide.LEFT),
turtle.getUpgrade(stack, TurtleSide.RIGHT),
turtle.getFuelLevel(stack),
overlay,
turtle.getUpgradeData(stack, TurtleSide.LEFT),
turtle.getUpgradeData(stack, TurtleSide.RIGHT)
overlay
);
}

View File

@@ -31,7 +31,7 @@ public final class TurtleRecipe extends ComputerFamilyRecipe {
var computerID = item.getComputerID(stack);
var label = item.getLabel(stack);
return TurtleItem.create(computerID, label, -1, getFamily(), null, null, 0, null, null, null);
return TurtleItem.create(computerID, label, -1, getFamily(), null, null, 0, null);
}
public static class Serializer extends ComputerFamilyRecipe.Serializer<TurtleRecipe> {

View File

@@ -4,8 +4,8 @@
package dan200.computercraft.shared.turtle.recipes;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.impl.TurtleUpgrades;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.turtle.items.TurtleItem;
@@ -30,7 +30,7 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
@Override
public ItemStack getResultItem(RegistryAccess registryAccess) {
return ModRegistry.Items.TURTLE_NORMAL.get().create(-1, null, -1, null, null, 0, null, null, null);
return ModRegistry.Items.TURTLE_NORMAL.get().create(-1, null, -1, null, null, 0, null);
}
@Override
@@ -104,7 +104,7 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
// At this point we have a turtle + 1 or 2 items
// Get the turtle we already have
var itemTurtle = (TurtleItem) turtle.getItem();
var upgrades = new ITurtleUpgrade[]{
var upgrades = new UpgradeData[]{
itemTurtle.getUpgrade(turtle, TurtleSide.LEFT),
itemTurtle.getUpgrade(turtle, TurtleSide.RIGHT),
};
@@ -126,8 +126,7 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
var colour = itemTurtle.getColour(turtle);
var overlay = itemTurtle.getOverlay(turtle);
return itemTurtle.create(
computerID, label, colour, upgrades[0], upgrades[1], fuelLevel, overlay,
itemTurtle.getUpgradeData(turtle, TurtleSide.LEFT), itemTurtle.getUpgradeData(turtle, TurtleSide.RIGHT)
computerID, label, colour, upgrades[0], upgrades[1], fuelLevel, overlay
);
}

View File

@@ -9,11 +9,13 @@ import dan200.computercraft.api.turtle.*;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class TurtleModem extends AbstractTurtleUpgrade {
@@ -77,4 +79,10 @@ public class TurtleModem extends AbstractTurtleUpgrade {
}
}
}
@Nonnull
@Override
public CompoundTag getPersistedData(CompoundTag upgradeData) {
return new CompoundTag();
}
}