mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-04-27 05:03:16 +00:00
Allow upgrades to read/write upgrade data from ItemStacks (#1465)
This commit is contained in:
parent
94f5ede75a
commit
f54cb8a432
@ -11,6 +11,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -28,12 +29,27 @@ public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> {
|
|||||||
* When the current turtle is {@literal null}, this function should be constant for a given upgrade and side.
|
* When the current turtle is {@literal null}, this function should be constant for a given upgrade and side.
|
||||||
*
|
*
|
||||||
* @param upgrade The upgrade that you're getting the model for.
|
* @param upgrade The upgrade that you're getting the model for.
|
||||||
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models!
|
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models, unless
|
||||||
|
* {@link #getModel(ITurtleUpgrade, CompoundTag, TurtleSide)} is overriden.
|
||||||
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
||||||
* @return The model that you wish to be used to render your upgrade.
|
* @return The model that you wish to be used to render your upgrade.
|
||||||
*/
|
*/
|
||||||
TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side);
|
TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the model to be used when rendering a turtle peripheral.
|
||||||
|
* <p>
|
||||||
|
* This is used when rendering the turtle's item model, and so no {@link ITurtleAccess} is available.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade that you're getting the model for.
|
||||||
|
* @param data Upgrade data instance for current turtle side.
|
||||||
|
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
||||||
|
* @return The model that you wish to be used to render your upgrade.
|
||||||
|
*/
|
||||||
|
default TransformedModel getModel(T upgrade, CompoundTag data, TurtleSide side) {
|
||||||
|
return getModel(upgrade, (ITurtleAccess) null, side);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getCraftingItem()
|
* A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getCraftingItem()
|
||||||
* crafting item}.
|
* crafting item}.
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
package dan200.computercraft.api.pocket;
|
package dan200.computercraft.api.pocket;
|
||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -69,6 +71,8 @@ public interface IPocketAccess {
|
|||||||
*
|
*
|
||||||
* @return The upgrade's NBT.
|
* @return The upgrade's NBT.
|
||||||
* @see #updateUpgradeNBTData()
|
* @see #updateUpgradeNBTData()
|
||||||
|
* @see UpgradeBase#getUpgradeItem(CompoundTag)
|
||||||
|
* @see UpgradeBase#getUpgradeData(ItemStack)
|
||||||
*/
|
*/
|
||||||
CompoundTag getUpgradeNBTData();
|
CompoundTag getUpgradeNBTData();
|
||||||
|
|
||||||
|
@ -8,10 +8,13 @@ import com.mojang.authlib.GameProfile;
|
|||||||
import dan200.computercraft.api.lua.ILuaCallback;
|
import dan200.computercraft.api.lua.ILuaCallback;
|
||||||
import dan200.computercraft.api.lua.MethodResult;
|
import dan200.computercraft.api.lua.MethodResult;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@ -245,23 +248,51 @@ public interface ITurtleAccess {
|
|||||||
void playAnimation(TurtleAnimation animation);
|
void playAnimation(TurtleAnimation animation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the turtle on the specified side of the turtle, if there is one.
|
* Returns the upgrade on the specified side of the turtle, if there is one.
|
||||||
*
|
*
|
||||||
* @param side The side to get the upgrade from.
|
* @param side The side to get the upgrade from.
|
||||||
* @return The upgrade on the specified side of the turtle, if there is one.
|
* @return The upgrade on the specified side of the turtle, if there is one.
|
||||||
* @see #setUpgrade(TurtleSide, ITurtleUpgrade)
|
* @see #getUpgradeWithData(TurtleSide)
|
||||||
|
* @see #setUpgradeWithData(TurtleSide, UpgradeData)
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
ITurtleUpgrade getUpgrade(TurtleSide side);
|
ITurtleUpgrade getUpgrade(TurtleSide side);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the upgrade on the specified side of the turtle, along with its {@linkplain #getUpgradeNBTData(TurtleSide)
|
||||||
|
* update data}.
|
||||||
|
*
|
||||||
|
* @param side The side to get the upgrade from.
|
||||||
|
* @return The upgrade on the specified side of the turtle, along with its upgrade data, if there is one.
|
||||||
|
* @see #getUpgradeWithData(TurtleSide)
|
||||||
|
* @see #setUpgradeWithData(TurtleSide, UpgradeData)
|
||||||
|
*/
|
||||||
|
default @Nullable UpgradeData<ITurtleUpgrade> getUpgradeWithData(TurtleSide side) {
|
||||||
|
var upgrade = getUpgrade(side);
|
||||||
|
return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeNBTData(side));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data.
|
* Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data.
|
||||||
*
|
*
|
||||||
* @param side The side to set the upgrade on.
|
* @param side The side to set the upgrade on.
|
||||||
* @param upgrade The upgrade to set, may be {@code null} to clear.
|
* @param upgrade The upgrade to set, may be {@code null} to clear.
|
||||||
* @see #getUpgrade(TurtleSide)
|
* @see #getUpgrade(TurtleSide)
|
||||||
|
* @deprecated Use {@link #setUpgradeWithData(TurtleSide, UpgradeData)}
|
||||||
*/
|
*/
|
||||||
void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade);
|
@Deprecated
|
||||||
|
default void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) {
|
||||||
|
setUpgradeWithData(side, upgrade == null ? null : UpgradeData.ofDefault(upgrade));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the upgrade for a given side and its upgrade data.
|
||||||
|
*
|
||||||
|
* @param side The side to set the upgrade on.
|
||||||
|
* @param upgrade The upgrade to set, may be {@code null} to clear.
|
||||||
|
* @see #getUpgradeWithData(TurtleSide)
|
||||||
|
*/
|
||||||
|
void setUpgradeWithData(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
|
* Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
|
||||||
@ -281,6 +312,8 @@ public interface ITurtleAccess {
|
|||||||
* @param side The side to get the upgrade data for.
|
* @param side The side to get the upgrade data for.
|
||||||
* @return The upgrade-specific data.
|
* @return The upgrade-specific data.
|
||||||
* @see #updateUpgradeNBTData(TurtleSide)
|
* @see #updateUpgradeNBTData(TurtleSide)
|
||||||
|
* @see UpgradeBase#getUpgradeItem(CompoundTag)
|
||||||
|
* @see UpgradeBase#getUpgradeData(ItemStack)
|
||||||
*/
|
*/
|
||||||
CompoundTag getUpgradeNBTData(TurtleSide side);
|
CompoundTag getUpgradeNBTData(TurtleSide side);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.api.turtle;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -79,4 +80,17 @@ public interface ITurtleUpgrade extends UpgradeBase {
|
|||||||
*/
|
*/
|
||||||
default void update(ITurtleAccess turtle, TurtleSide side) {
|
default void update(ITurtleAccess turtle, TurtleSide side) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get upgrade data that should be persisted when the turtle was broken.
|
||||||
|
* <p>
|
||||||
|
* This method should be overridden when you don't need to store all upgrade data by default. For instance, if you
|
||||||
|
* store peripheral state in the upgrade data, which should be lost when the turtle is broken.
|
||||||
|
*
|
||||||
|
* @param upgradeData Data that currently stored for this upgrade
|
||||||
|
* @return Filtered version of this data.
|
||||||
|
*/
|
||||||
|
default CompoundTag getPersistedData(CompoundTag upgradeData) {
|
||||||
|
return upgradeData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,14 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.upgrades;
|
package dan200.computercraft.api.upgrades;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.impl.PlatformHelper;
|
import dan200.computercraft.impl.PlatformHelper;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
@ -50,6 +54,42 @@ public interface UpgradeBase {
|
|||||||
*/
|
*/
|
||||||
ItemStack getCraftingItem();
|
ItemStack getCraftingItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item stack representing a currently equipped turtle upgrade.
|
||||||
|
* <p>
|
||||||
|
* While upgrades can store upgrade data ({@link ITurtleAccess#getUpgradeNBTData(TurtleSide)} and
|
||||||
|
* {@link IPocketAccess#getUpgradeNBTData()}}, by default this data is discarded when an upgrade is unequipped,
|
||||||
|
* and the original item stack is returned.
|
||||||
|
* <p>
|
||||||
|
* By overriding this method, you can create a new {@link ItemStack} which contains enough data to
|
||||||
|
* {@linkplain #getUpgradeData(ItemStack) re-create the upgrade data} if the item is re-equipped.
|
||||||
|
* <p>
|
||||||
|
* When overriding this, you should override {@link #getUpgradeData(ItemStack)} and {@link #isItemSuitable(ItemStack)}
|
||||||
|
* at the same time,
|
||||||
|
*
|
||||||
|
* @param upgradeData The current upgrade data. This should <strong>NOT</strong> be mutated.
|
||||||
|
* @return The item stack returned when unequipping.
|
||||||
|
*/
|
||||||
|
default ItemStack getUpgradeItem(CompoundTag upgradeData) {
|
||||||
|
return getCraftingItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract upgrade data from an {@link ItemStack}.
|
||||||
|
* <p>
|
||||||
|
* This upgrade data will be available with {@link ITurtleAccess#getUpgradeNBTData(TurtleSide)} or
|
||||||
|
* {@link IPocketAccess#getUpgradeNBTData()}.
|
||||||
|
* <p>
|
||||||
|
* This should be an inverse to {@link #getUpgradeItem(CompoundTag)}.
|
||||||
|
*
|
||||||
|
* @param stack The stack that was equipped by the turtle or pocket computer. This will have the same item as
|
||||||
|
* {@link #getCraftingItem()}.
|
||||||
|
* @return The upgrade data that should be set on the turtle or pocket computer.
|
||||||
|
*/
|
||||||
|
default CompoundTag getUpgradeData(ItemStack stack) {
|
||||||
|
return new CompoundTag();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if an item is suitable for being used for this upgrade.
|
* Determine if an item is suitable for being used for this upgrade.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.upgrades;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
|
||||||
|
* <p>
|
||||||
|
* <strong>IMPORTANT:</strong> The {@link #data()} in an upgrade data is often a reference to the original upgrade data.
|
||||||
|
* Be careful to take a {@linkplain #copy() defensive copy} if you plan to use the data in this upgrade.
|
||||||
|
*
|
||||||
|
* @param upgrade The current upgrade.
|
||||||
|
* @param data The upgrade's data.
|
||||||
|
* @param <T> The type of upgrade, either {@link ITurtleUpgrade} or {@link IPocketUpgrade}.
|
||||||
|
*/
|
||||||
|
public record UpgradeData<T extends UpgradeBase>(T upgrade, CompoundTag data) {
|
||||||
|
/**
|
||||||
|
* A utility method to construct a new {@link UpgradeData} instance.
|
||||||
|
*
|
||||||
|
* @param upgrade An upgrade.
|
||||||
|
* @param data The upgrade's data.
|
||||||
|
* @param <T> The type of upgrade.
|
||||||
|
* @return The new {@link UpgradeData} instance.
|
||||||
|
*/
|
||||||
|
public static <T extends UpgradeBase> UpgradeData<T> of(T upgrade, CompoundTag data) {
|
||||||
|
return new UpgradeData<>(upgrade, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an {@link UpgradeData} containing the default {@linkplain #data() data} for an upgrade.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade instance.
|
||||||
|
* @param <T> The type of upgrade.
|
||||||
|
* @return The default upgrade data.
|
||||||
|
*/
|
||||||
|
public static <T extends UpgradeBase> UpgradeData<T> ofDefault(T upgrade) {
|
||||||
|
return of(upgrade, upgrade.getUpgradeData(upgrade.getCraftingItem()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a copy of a (possibly {@code null}) {@link UpgradeData} instance.
|
||||||
|
*
|
||||||
|
* @param upgrade The copied upgrade data.
|
||||||
|
* @param <T> The type of upgrade.
|
||||||
|
* @return The newly created upgrade data.
|
||||||
|
*/
|
||||||
|
@Contract("!null -> !null; null -> null")
|
||||||
|
public static <T extends UpgradeBase> @Nullable UpgradeData<T> copyOf(@Nullable UpgradeData<T> upgrade) {
|
||||||
|
return upgrade == null ? null : upgrade.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@linkplain UpgradeBase#getUpgradeItem(CompoundTag) upgrade item} for this upgrade.
|
||||||
|
* <p>
|
||||||
|
* This returns a defensive copy of the item, to prevent accidental mutation of the upgrade data or original
|
||||||
|
* {@linkplain UpgradeBase#getCraftingItem() upgrade stack}.
|
||||||
|
*
|
||||||
|
* @return This upgrade's item.
|
||||||
|
*/
|
||||||
|
public ItemStack getUpgradeItem() {
|
||||||
|
return upgrade.getUpgradeItem(data).copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a copy of this {@link UpgradeData}. This returns a new instance with the same upgrade and a fresh copy of
|
||||||
|
* the upgrade data.
|
||||||
|
*
|
||||||
|
* @return A copy of the current instance.
|
||||||
|
*/
|
||||||
|
public UpgradeData<T> copy() {
|
||||||
|
return new UpgradeData<>(upgrade(), data().copy());
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.model.turtle;
|
package dan200.computercraft.client.model.turtle;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Transformation;
|
import com.mojang.math.Transformation;
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
import dan200.computercraft.api.client.TransformedModel;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||||
@ -21,9 +23,9 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,12 +48,19 @@ public final class TurtleModelParts<T> {
|
|||||||
|
|
||||||
private record Combination(
|
private record Combination(
|
||||||
boolean colour,
|
boolean colour,
|
||||||
@Nullable ITurtleUpgrade leftUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade,
|
||||||
@Nullable ITurtleUpgrade rightUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
||||||
@Nullable ResourceLocation overlay,
|
@Nullable ResourceLocation overlay,
|
||||||
boolean christmas,
|
boolean christmas,
|
||||||
boolean flip
|
boolean flip
|
||||||
) {
|
) {
|
||||||
|
Combination copy() {
|
||||||
|
if (leftUpgrade == null && rightUpgrade == null) return this;
|
||||||
|
return new Combination(
|
||||||
|
colour, UpgradeData.copyOf(leftUpgrade), UpgradeData.copyOf(rightUpgrade),
|
||||||
|
overlay, christmas, flip
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BakedModel familyModel;
|
private final BakedModel familyModel;
|
||||||
@ -63,12 +72,20 @@ public final class TurtleModelParts<T> {
|
|||||||
* A cache of {@link TransformedModel} to the transformed {@link BakedModel}. This helps us pool the transformed
|
* A cache of {@link TransformedModel} to the transformed {@link BakedModel}. This helps us pool the transformed
|
||||||
* instances, reducing memory usage and hopefully ensuring their caches are hit more often!
|
* instances, reducing memory usage and hopefully ensuring their caches are hit more often!
|
||||||
*/
|
*/
|
||||||
private final Map<TransformedModel, BakedModel> transformCache = new HashMap<>();
|
private final Map<TransformedModel, BakedModel> transformCache = CacheBuilder.newBuilder()
|
||||||
|
.concurrencyLevel(1)
|
||||||
|
.expireAfterAccess(30, TimeUnit.SECONDS)
|
||||||
|
.<TransformedModel, BakedModel>build()
|
||||||
|
.asMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of {@link Combination}s to the combined model.
|
* A cache of {@link Combination}s to the combined model.
|
||||||
*/
|
*/
|
||||||
private final Map<Combination, T> modelCache = new HashMap<>();
|
private final Map<Combination, T> modelCache = CacheBuilder.newBuilder()
|
||||||
|
.concurrencyLevel(1)
|
||||||
|
.expireAfterAccess(30, TimeUnit.SECONDS)
|
||||||
|
.<Combination, T>build()
|
||||||
|
.asMap();
|
||||||
|
|
||||||
public TurtleModelParts(BakedModel familyModel, BakedModel colourModel, ModelTransformer transformer, Function<List<BakedModel>, T> combineModel) {
|
public TurtleModelParts(BakedModel familyModel, BakedModel colourModel, ModelTransformer transformer, Function<List<BakedModel>, T> combineModel) {
|
||||||
this.familyModel = familyModel;
|
this.familyModel = familyModel;
|
||||||
@ -78,7 +95,15 @@ public final class TurtleModelParts<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T getModel(ItemStack stack) {
|
public T getModel(ItemStack stack) {
|
||||||
return modelCache.computeIfAbsent(getCombination(stack), buildModel);
|
var combination = getCombination(stack);
|
||||||
|
var existing = modelCache.get(combination);
|
||||||
|
if (existing != null) return existing;
|
||||||
|
|
||||||
|
// Take a defensive copy of the upgrade data, and add it to the cache.
|
||||||
|
var newCombination = combination.copy();
|
||||||
|
var newModel = buildModel.apply(newCombination);
|
||||||
|
modelCache.put(newCombination, newModel);
|
||||||
|
return newModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Combination getCombination(ItemStack stack) {
|
private Combination getCombination(ItemStack stack) {
|
||||||
@ -89,8 +114,8 @@ public final class TurtleModelParts<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var colour = turtle.getColour(stack);
|
var colour = turtle.getColour(stack);
|
||||||
var leftUpgrade = turtle.getUpgrade(stack, TurtleSide.LEFT);
|
var leftUpgrade = turtle.getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
var rightUpgrade = turtle.getUpgrade(stack, TurtleSide.RIGHT);
|
var rightUpgrade = turtle.getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
var overlay = turtle.getOverlay(stack);
|
var overlay = turtle.getOverlay(stack);
|
||||||
var label = turtle.getLabel(stack);
|
var label = turtle.getLabel(stack);
|
||||||
var flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
|
var flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
|
||||||
@ -110,18 +135,19 @@ public final class TurtleModelParts<T> {
|
|||||||
if (overlayModelLocation != null) {
|
if (overlayModelLocation != null) {
|
||||||
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, overlayModelLocation), transformation));
|
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, overlayModelLocation), transformation));
|
||||||
}
|
}
|
||||||
if (combo.leftUpgrade() != null) {
|
|
||||||
var model = TurtleUpgradeModellers.getModel(combo.leftUpgrade(), null, TurtleSide.LEFT);
|
addUpgrade(parts, transformation, TurtleSide.LEFT, combo.leftUpgrade());
|
||||||
parts.add(transform(model.getModel(), transformation.compose(model.getMatrix())));
|
addUpgrade(parts, transformation, TurtleSide.RIGHT, combo.rightUpgrade());
|
||||||
}
|
|
||||||
if (combo.rightUpgrade() != null) {
|
|
||||||
var model = TurtleUpgradeModellers.getModel(combo.rightUpgrade(), null, TurtleSide.RIGHT);
|
|
||||||
parts.add(transform(model.getModel(), transformation.compose(model.getMatrix())));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addUpgrade(List<BakedModel> parts, Transformation transformation, TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
|
if (upgrade == null) return;
|
||||||
|
var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side);
|
||||||
|
parts.add(transform(model.getModel(), transformation.compose(model.getMatrix())));
|
||||||
|
}
|
||||||
|
|
||||||
private BakedModel transform(BakedModel model, Transformation transformation) {
|
private BakedModel transform(BakedModel model, Transformation transformation) {
|
||||||
if (transformation.equals(Transformation.identity())) return model;
|
if (transformation.equals(Transformation.identity())) return model;
|
||||||
return transformCache.computeIfAbsent(new TransformedModel(model, transformation), transformer);
|
return transformCache.computeIfAbsent(new TransformedModel(model, transformation), transformer);
|
||||||
|
@ -14,8 +14,8 @@ import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
|||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.impl.UpgradeManager;
|
import dan200.computercraft.impl.UpgradeManager;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -52,12 +52,18 @@ public final class TurtleUpgradeModellers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess access, TurtleSide side) {
|
public static TransformedModel getModel(ITurtleUpgrade upgrade, ITurtleAccess access, TurtleSide side) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller);
|
var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller);
|
||||||
return modeller.getModel(upgrade, access, side);
|
return modeller.getModel(upgrade, access, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TransformedModel getModel(ITurtleUpgrade upgrade, CompoundTag data, TurtleSide side) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller);
|
||||||
|
return modeller.getModel(upgrade, data, side);
|
||||||
|
}
|
||||||
|
|
||||||
private static TurtleUpgradeModeller<?> getModeller(ITurtleUpgrade upgradeA) {
|
private static TurtleUpgradeModeller<?> getModeller(ITurtleUpgrade upgradeA) {
|
||||||
var wrapper = TurtleUpgrades.instance().getWrapper(upgradeA);
|
var wrapper = TurtleUpgrades.instance().getWrapper(upgradeA);
|
||||||
if (wrapper == null) return NULL_TURTLE_MODELLER;
|
if (wrapper == null) return NULL_TURTLE_MODELLER;
|
||||||
|
@ -8,6 +8,7 @@ import com.google.gson.JsonObject;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
import dan200.computercraft.api.pocket.PocketUpgradeDataProvider;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.IColouredItem;
|
import dan200.computercraft.shared.common.IColouredItem;
|
||||||
@ -110,7 +111,7 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
var nameId = turtleItem.getFamily().name().toLowerCase(Locale.ROOT);
|
var nameId = turtleItem.getFamily().name().toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
|
for (var upgrade : turtleUpgrades.getGeneratedUpgrades()) {
|
||||||
var result = turtleItem.create(-1, null, -1, null, upgrade, -1, null);
|
var result = turtleItem.create(-1, null, -1, null, UpgradeData.ofDefault(upgrade), -1, null);
|
||||||
ShapedRecipeBuilder
|
ShapedRecipeBuilder
|
||||||
.shaped(RecipeCategory.REDSTONE, result.getItem())
|
.shaped(RecipeCategory.REDSTONE, result.getItem())
|
||||||
.group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId))
|
.group(String.format("%s:turtle_%s", ComputerCraftAPI.MOD_ID, nameId))
|
||||||
@ -146,7 +147,7 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
var nameId = pocket.getFamily().name().toLowerCase(Locale.ROOT);
|
var nameId = pocket.getFamily().name().toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
|
for (var upgrade : pocketUpgrades.getGeneratedUpgrades()) {
|
||||||
var result = pocket.create(-1, null, -1, upgrade);
|
var result = pocket.create(-1, null, -1, UpgradeData.ofDefault(upgrade));
|
||||||
ShapedRecipeBuilder
|
ShapedRecipeBuilder
|
||||||
.shaped(RecipeCategory.REDSTONE, result.getItem())
|
.shaped(RecipeCategory.REDSTONE, result.getItem())
|
||||||
.group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId))
|
.group(String.format("%s:pocket_%s", ComputerCraftAPI.MOD_ID, nameId))
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.impl;
|
|||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
@ -74,13 +75,13 @@ public class UpgradeManager<R extends UpgradeSerialiser<? extends T>, T extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public T get(ItemStack stack) {
|
public UpgradeData<T> get(ItemStack stack) {
|
||||||
if (stack.isEmpty()) return null;
|
if (stack.isEmpty()) return null;
|
||||||
|
|
||||||
for (var wrapper : current.values()) {
|
for (var wrapper : current.values()) {
|
||||||
var craftingStack = wrapper.upgrade().getCraftingItem();
|
var craftingStack = wrapper.upgrade().getCraftingItem();
|
||||||
if (!craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade().isItemSuitable(stack)) {
|
if (!craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade().isItemSuitable(stack)) {
|
||||||
return wrapper.upgrade();
|
return UpgradeData.of(wrapper.upgrade, wrapper.upgrade.getUpgradeData(stack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import dan200.computercraft.api.detail.VanillaDetailRegistries;
|
|||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
|
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
@ -446,12 +447,12 @@ public final class ModRegistry {
|
|||||||
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
|
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
|
||||||
out.accept(turtle.create(-1, null, -1, null, null, 0, null));
|
out.accept(turtle.create(-1, null, -1, null, null, 0, null));
|
||||||
TurtleUpgrades.getVanillaUpgrades()
|
TurtleUpgrades.getVanillaUpgrades()
|
||||||
.map(x -> turtle.create(-1, null, -1, null, x, 0, null))
|
.map(x -> turtle.create(-1, null, -1, null, UpgradeData.ofDefault(x), 0, null))
|
||||||
.forEach(out::accept);
|
.forEach(out::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket) {
|
private static void addPocket(CreativeModeTab.Output out, PocketComputerItem pocket) {
|
||||||
out.accept(pocket.create(-1, null, -1, null));
|
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.ofDefault(x))).forEach(out::accept);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package dan200.computercraft.shared.integration;
|
package dan200.computercraft.shared.integration;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
@ -56,14 +57,14 @@ public final class RecipeModHelpers {
|
|||||||
for (var turtleSupplier : TURTLES) {
|
for (var turtleSupplier : TURTLES) {
|
||||||
var turtle = turtleSupplier.get();
|
var turtle = turtleSupplier.get();
|
||||||
for (var upgrade : TurtleUpgrades.instance().getUpgrades()) {
|
for (var upgrade : TurtleUpgrades.instance().getUpgrades()) {
|
||||||
upgradeItems.add(turtle.create(-1, null, -1, null, upgrade, 0, null));
|
upgradeItems.add(turtle.create(-1, null, -1, null, UpgradeData.ofDefault(upgrade), 0, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var pocketSupplier : POCKET_COMPUTERS) {
|
for (var pocketSupplier : POCKET_COMPUTERS) {
|
||||||
var pocket = pocketSupplier.get();
|
var pocket = pocketSupplier.get();
|
||||||
for (var upgrade : PocketUpgrades.instance().getUpgrades()) {
|
for (var upgrade : PocketUpgrades.instance().getUpgrades()) {
|
||||||
upgradeItems.add(pocket.create(-1, null, -1, upgrade));
|
upgradeItems.add(pocket.create(-1, null, -1, UpgradeData.ofDefault(upgrade)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
@ -111,20 +112,22 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
|
|
||||||
if (stack.getItem() instanceof TurtleItem item) {
|
if (stack.getItem() instanceof TurtleItem item) {
|
||||||
// Suggest possible upgrades which can be applied to this turtle
|
// Suggest possible upgrades which can be applied to this turtle
|
||||||
var left = item.getUpgrade(stack, TurtleSide.LEFT);
|
var left = item.getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
var right = item.getUpgrade(stack, TurtleSide.RIGHT);
|
var right = item.getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
if (left != null && right != null) return Collections.emptyList();
|
if (left != null && right != null) return Collections.emptyList();
|
||||||
|
|
||||||
List<T> recipes = new ArrayList<>();
|
List<T> recipes = new ArrayList<>();
|
||||||
var ingredient = Ingredient.of(stack);
|
var ingredient = Ingredient.of(stack);
|
||||||
for (var upgrade : turtleUpgrades) {
|
for (var upgrade : turtleUpgrades) {
|
||||||
|
if (upgrade.turtle == null) throw new NullPointerException();
|
||||||
|
|
||||||
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
|
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
|
||||||
if (left == null) {
|
if (left == null) {
|
||||||
recipes.add(turtle(ingredient, upgrade.ingredient, turtleWith(stack, upgrade.turtle, right)));
|
recipes.add(turtle(ingredient, upgrade.ingredient, turtleWith(stack, UpgradeData.ofDefault(upgrade.turtle), right)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right == null) {
|
if (right == null) {
|
||||||
recipes.add(turtle(upgrade.ingredient, ingredient, turtleWith(stack, left, upgrade.turtle)));
|
recipes.add(turtle(upgrade.ingredient, ingredient, turtleWith(stack, left, UpgradeData.ofDefault(upgrade.turtle))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +140,8 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
List<T> recipes = new ArrayList<>();
|
List<T> recipes = new ArrayList<>();
|
||||||
var ingredient = Ingredient.of(stack);
|
var ingredient = Ingredient.of(stack);
|
||||||
for (var upgrade : pocketUpgrades) {
|
for (var upgrade : pocketUpgrades) {
|
||||||
recipes.add(pocket(upgrade.ingredient, ingredient, pocketWith(stack, upgrade.pocket)));
|
if (upgrade.pocket == null) throw new NullPointerException();
|
||||||
|
recipes.add(pocket(upgrade.ingredient, ingredient, pocketWith(stack, UpgradeData.ofDefault(upgrade.pocket))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableList(recipes);
|
return Collections.unmodifiableList(recipes);
|
||||||
@ -180,21 +184,21 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
if (stack.getItem() instanceof TurtleItem item) {
|
if (stack.getItem() instanceof TurtleItem item) {
|
||||||
List<T> recipes = new ArrayList<>(0);
|
List<T> recipes = new ArrayList<>(0);
|
||||||
|
|
||||||
var left = item.getUpgrade(stack, TurtleSide.LEFT);
|
var left = item.getUpgradeWithData(stack, TurtleSide.LEFT);
|
||||||
var right = item.getUpgrade(stack, TurtleSide.RIGHT);
|
var right = item.getUpgradeWithData(stack, TurtleSide.RIGHT);
|
||||||
|
|
||||||
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
|
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
|
||||||
if (left != null) {
|
if (left != null) {
|
||||||
recipes.add(turtle(
|
recipes.add(turtle(
|
||||||
Ingredient.of(turtleWith(stack, null, right)),
|
Ingredient.of(turtleWith(stack, null, right)),
|
||||||
Ingredient.of(left.getCraftingItem()),
|
Ingredient.of(left.getUpgradeItem()),
|
||||||
stack
|
stack
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
recipes.add(turtle(
|
recipes.add(turtle(
|
||||||
Ingredient.of(right.getCraftingItem()),
|
Ingredient.of(right.getUpgradeItem()),
|
||||||
Ingredient.of(turtleWith(stack, left, null)),
|
Ingredient.of(turtleWith(stack, left, null)),
|
||||||
stack
|
stack
|
||||||
));
|
));
|
||||||
@ -204,9 +208,9 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
} else if (stack.getItem() instanceof PocketComputerItem) {
|
} else if (stack.getItem() instanceof PocketComputerItem) {
|
||||||
List<T> recipes = new ArrayList<>(0);
|
List<T> recipes = new ArrayList<>(0);
|
||||||
|
|
||||||
var back = PocketComputerItem.getUpgrade(stack);
|
var back = PocketComputerItem.getUpgradeWithData(stack);
|
||||||
if (back != null) {
|
if (back != null) {
|
||||||
recipes.add(pocket(Ingredient.of(back.getCraftingItem()), Ingredient.of(pocketWith(stack, null)), stack));
|
recipes.add(pocket(Ingredient.of(back.getUpgradeItem()), Ingredient.of(pocketWith(stack, null)), stack));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableList(recipes);
|
return Collections.unmodifiableList(recipes);
|
||||||
@ -215,7 +219,7 @@ 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();
|
var item = (TurtleItem) stack.getItem();
|
||||||
return item.create(
|
return item.create(
|
||||||
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack),
|
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack),
|
||||||
@ -223,7 +227,7 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack pocketWith(ItemStack stack, @Nullable IPocketUpgrade back) {
|
private static ItemStack pocketWith(ItemStack stack, @Nullable UpgradeData<IPocketUpgrade> back) {
|
||||||
var item = (PocketComputerItem) stack.getItem();
|
var item = (PocketComputerItem) stack.getItem();
|
||||||
return item.create(
|
return item.create(
|
||||||
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack), back
|
item.getComputerID(stack), item.getLabel(stack), item.getColour(stack), back
|
||||||
@ -272,7 +276,7 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
recipes.add(turtle(
|
recipes.add(turtle(
|
||||||
ingredient, // Right upgrade, recipe on left
|
ingredient, // Right upgrade, recipe on left
|
||||||
Ingredient.of(turtleItem.create(-1, null, -1, null, null, 0, null)),
|
Ingredient.of(turtleItem.create(-1, null, -1, null, null, 0, null)),
|
||||||
turtleItem.create(-1, null, -1, null, turtle, 0, null)
|
turtleItem.create(-1, null, -1, null, UpgradeData.ofDefault(turtle), 0, null)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,7 +287,7 @@ public class UpgradeRecipeGenerator<T> {
|
|||||||
recipes.add(pocket(
|
recipes.add(pocket(
|
||||||
ingredient,
|
ingredient,
|
||||||
Ingredient.of(pocketItem.create(-1, null, -1, null)),
|
Ingredient.of(pocketItem.create(-1, null, -1, null)),
|
||||||
pocketItem.create(-1, null, -1, pocket)
|
pocketItem.create(-1, null, -1, UpgradeData.ofDefault(pocket))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,13 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper
|
|||||||
return (PlatformHelper) dan200.computercraft.impl.PlatformHelper.get();
|
return (PlatformHelper) dan200.computercraft.impl.PlatformHelper.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we're running in a development environment.
|
||||||
|
*
|
||||||
|
* @return If we're running in a development environment.
|
||||||
|
*/
|
||||||
|
boolean isDevelopmentEnvironment();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new config builder.
|
* Create a new config builder.
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.pocket.apis;
|
|||||||
import dan200.computercraft.api.lua.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.LuaFunction;
|
import dan200.computercraft.api.lua.LuaFunction;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
@ -14,6 +15,7 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Control the current pocket computer, adding or removing upgrades.
|
* Control the current pocket computer, adding or removing upgrades.
|
||||||
@ -68,7 +70,7 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
if (newUpgrade == null) return new Object[]{ false, "Cannot find a valid upgrade" };
|
if (newUpgrade == null) return new Object[]{ false, "Cannot find a valid upgrade" };
|
||||||
|
|
||||||
// Remove the current upgrade
|
// Remove the current upgrade
|
||||||
if (previousUpgrade != null) storeItem(player, previousUpgrade.getCraftingItem().copy());
|
if (previousUpgrade != null) storeItem(player, previousUpgrade.getUpgradeItem());
|
||||||
|
|
||||||
// Set the new upgrade
|
// Set the new upgrade
|
||||||
computer.setUpgrade(newUpgrade);
|
computer.setUpgrade(newUpgrade);
|
||||||
@ -93,7 +95,7 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
|
|
||||||
computer.setUpgrade(null);
|
computer.setUpgrade(null);
|
||||||
|
|
||||||
storeItem(player, previousUpgrade.getCraftingItem().copy());
|
storeItem(player, previousUpgrade.getUpgradeItem());
|
||||||
|
|
||||||
return new Object[]{ true };
|
return new Object[]{ true };
|
||||||
}
|
}
|
||||||
@ -105,13 +107,13 @@ public class PocketAPI implements ILuaAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable IPocketUpgrade findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable IPocketUpgrade previous) {
|
private static @Nullable UpgradeData<IPocketUpgrade> findUpgrade(NonNullList<ItemStack> inv, int start, @Nullable UpgradeData<IPocketUpgrade> previous) {
|
||||||
for (var i = 0; i < inv.size(); i++) {
|
for (var i = 0; i < inv.size(); i++) {
|
||||||
var invStack = inv.get((i + start) % inv.size());
|
var invStack = inv.get((i + start) % inv.size());
|
||||||
if (!invStack.isEmpty()) {
|
if (!invStack.isEmpty()) {
|
||||||
var newUpgrade = PocketUpgrades.instance().get(invStack);
|
var newUpgrade = PocketUpgrades.instance().get(invStack);
|
||||||
|
|
||||||
if (newUpgrade != null && newUpgrade != previous) {
|
if (newUpgrade != null && !Objects.equals(newUpgrade, previous)) {
|
||||||
// Consume an item from this stack and exit the loop
|
// Consume an item from this stack and exit the loop
|
||||||
invStack = invStack.copy();
|
invStack = invStack.copy();
|
||||||
invStack.shrink(1);
|
invStack.shrink(1);
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.pocket.core;
|
|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.api.pocket.IPocketAccess;
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.shared.common.IColouredItem;
|
import dan200.computercraft.shared.common.IColouredItem;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
@ -109,8 +110,8 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
return upgrade == null ? Collections.emptyMap() : Collections.singletonMap(upgrade.getUpgradeID(), getPeripheral(ComputerSide.BACK));
|
return upgrade == null ? Collections.emptyMap() : Collections.singletonMap(upgrade.getUpgradeID(), getPeripheral(ComputerSide.BACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable IPocketUpgrade getUpgrade() {
|
public @Nullable UpgradeData<IPocketUpgrade> getUpgrade() {
|
||||||
return upgrade;
|
return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeNBTData());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,13 +121,11 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
*
|
*
|
||||||
* @param upgrade The new upgrade to set it to, may be {@code null}.
|
* @param upgrade The new upgrade to set it to, may be {@code null}.
|
||||||
*/
|
*/
|
||||||
public void setUpgrade(@Nullable IPocketUpgrade upgrade) {
|
public void setUpgrade(@Nullable UpgradeData<IPocketUpgrade> upgrade) {
|
||||||
if (this.upgrade == upgrade) return;
|
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
PocketComputerItem.setUpgrade(stack, upgrade);
|
PocketComputerItem.setUpgrade(stack, upgrade);
|
||||||
updateUpgradeNBTData();
|
updateUpgradeNBTData();
|
||||||
this.upgrade = upgrade;
|
this.upgrade = upgrade == null ? null : upgrade.upgrade();
|
||||||
invalidatePeripheral();
|
invalidatePeripheral();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
|||||||
import dan200.computercraft.api.filesystem.Mount;
|
import dan200.computercraft.api.filesystem.Mount;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
@ -23,6 +24,7 @@ import dan200.computercraft.shared.pocket.apis.PocketAPI;
|
|||||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||||
import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider;
|
import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
|
import dan200.computercraft.shared.util.NBTUtil;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@ -58,7 +60,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
|||||||
this.family = family;
|
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) {
|
return switch (family) {
|
||||||
case NORMAL -> ModRegistry.Items.POCKET_COMPUTER_NORMAL.get().create(id, label, colour, upgrade);
|
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);
|
case ADVANCED -> ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get().create(id, label, colour, upgrade);
|
||||||
@ -66,11 +68,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);
|
var result = new ItemStack(this);
|
||||||
if (id >= 0) result.getOrCreateTag().putInt(NBT_ID, id);
|
if (id >= 0) result.getOrCreateTag().putInt(NBT_ID, id);
|
||||||
if (label != null) result.setHoverName(Component.literal(label));
|
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.upgrade().getUpgradeID().toString());
|
||||||
|
if (!upgrade.data().isEmpty()) result.getOrCreateTag().put(NBT_UPGRADE_INFO, upgrade.data().copy());
|
||||||
|
}
|
||||||
if (colour != -1) result.getOrCreateTag().putInt(NBT_COLOUR, colour);
|
if (colour != -1) result.getOrCreateTag().putInt(NBT_COLOUR, colour);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -207,7 +212,9 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
|||||||
setInstanceID(stack, computer.register());
|
setInstanceID(stack, computer.register());
|
||||||
setSessionID(stack, registry.getSessionID());
|
setSessionID(stack, registry.getSessionID());
|
||||||
|
|
||||||
computer.updateValues(entity, stack, getUpgrade(stack));
|
var upgrade = getUpgrade(stack);
|
||||||
|
|
||||||
|
computer.updateValues(entity, stack, upgrade);
|
||||||
computer.addAPI(new PocketAPI(computer));
|
computer.addAPI(new PocketAPI(computer));
|
||||||
|
|
||||||
// Only turn on when initially creating the computer, rather than each tick.
|
// Only turn on when initially creating the computer, rather than each tick.
|
||||||
@ -244,7 +251,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
|||||||
public ItemStack withFamily(ItemStack stack, ComputerFamily family) {
|
public ItemStack withFamily(ItemStack stack, ComputerFamily family) {
|
||||||
return create(
|
return create(
|
||||||
getComputerID(stack), getLabel(stack), getColour(stack),
|
getComputerID(stack), getLabel(stack), getColour(stack),
|
||||||
family, getUpgrade(stack)
|
family, getUpgradeWithData(stack)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,20 +301,27 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
|||||||
|
|
||||||
public static @Nullable IPocketUpgrade getUpgrade(ItemStack stack) {
|
public static @Nullable IPocketUpgrade getUpgrade(ItemStack stack) {
|
||||||
var compound = stack.getTag();
|
var compound = stack.getTag();
|
||||||
return compound != null && compound.contains(NBT_UPGRADE)
|
if (compound == null || !compound.contains(NBT_UPGRADE)) return null;
|
||||||
? PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE)) : null;
|
return PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setUpgrade(ItemStack stack, @Nullable IPocketUpgrade upgrade) {
|
public static @Nullable UpgradeData<IPocketUpgrade> getUpgradeWithData(ItemStack stack) {
|
||||||
|
var compound = stack.getTag();
|
||||||
|
if (compound == null || !compound.contains(NBT_UPGRADE)) return null;
|
||||||
|
var upgrade = PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE));
|
||||||
|
return upgrade == null ? null : UpgradeData.of(upgrade, NBTUtil.getCompoundOrEmpty(compound, NBT_UPGRADE_INFO));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUpgrade(ItemStack stack, @Nullable UpgradeData<IPocketUpgrade> upgrade) {
|
||||||
var compound = stack.getOrCreateTag();
|
var compound = stack.getOrCreateTag();
|
||||||
|
|
||||||
if (upgrade == null) {
|
if (upgrade == null) {
|
||||||
compound.remove(NBT_UPGRADE);
|
compound.remove(NBT_UPGRADE);
|
||||||
|
compound.remove(NBT_UPGRADE_INFO);
|
||||||
} else {
|
} else {
|
||||||
compound.putString(NBT_UPGRADE, upgrade.getUpgradeID().toString());
|
compound.putString(NBT_UPGRADE, upgrade.upgrade().getUpgradeID().toString());
|
||||||
|
compound.put(NBT_UPGRADE_INFO, upgrade.data().copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
compound.remove(NBT_UPGRADE_INFO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompoundTag getUpgradeInfo(ItemStack stack) {
|
public static CompoundTag getUpgradeInfo(ItemStack stack) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package dan200.computercraft.shared.pocket.recipes;
|
package dan200.computercraft.shared.pocket.recipes;
|
||||||
|
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.PocketUpgrades;
|
import dan200.computercraft.impl.PocketUpgrades;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
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;
|
if (PocketComputerItem.getUpgrade(computer) != null) return ItemStack.EMPTY;
|
||||||
|
|
||||||
// Check for upgrades around the item
|
// Check for upgrades around the item
|
||||||
IPocketUpgrade upgrade = null;
|
UpgradeData<IPocketUpgrade> upgrade = null;
|
||||||
for (var y = 0; y < inventory.getHeight(); y++) {
|
for (var y = 0; y < inventory.getHeight(); y++) {
|
||||||
for (var x = 0; x < inventory.getWidth(); x++) {
|
for (var x = 0; x < inventory.getWidth(); x++) {
|
||||||
var item = inventory.getItem(x + y * inventory.getWidth());
|
var item = inventory.getItem(x + y * inventory.getWidth());
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
package dan200.computercraft.shared.turtle.blocks;
|
package dan200.computercraft.shared.turtle.blocks;
|
||||||
|
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
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.AbstractComputerBlock;
|
||||||
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity;
|
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
@ -128,7 +130,7 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
if (stack.getItem() instanceof TurtleItem item) {
|
if (stack.getItem() instanceof TurtleItem item) {
|
||||||
// Set Upgrades
|
// Set Upgrades
|
||||||
for (var side : TurtleSide.values()) {
|
for (var side : TurtleSide.values()) {
|
||||||
turtle.getAccess().setUpgrade(side, item.getUpgrade(stack, side));
|
turtle.getAccess().setUpgradeWithData(side, item.getUpgradeWithData(stack, side));
|
||||||
}
|
}
|
||||||
|
|
||||||
turtle.getAccess().setFuelLevel(item.getFuelLevel(stack));
|
turtle.getAccess().setFuelLevel(item.getFuelLevel(stack));
|
||||||
@ -161,11 +163,16 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
var access = turtle.getAccess();
|
var access = turtle.getAccess();
|
||||||
return TurtleItem.create(
|
return TurtleItem.create(
|
||||||
turtle.getComputerID(), turtle.getLabel(), access.getColour(), turtle.getFamily(),
|
turtle.getComputerID(), turtle.getLabel(), access.getColour(), turtle.getFamily(),
|
||||||
access.getUpgrade(TurtleSide.LEFT), access.getUpgrade(TurtleSide.RIGHT),
|
withPersistedData(access.getUpgradeWithData(TurtleSide.LEFT)),
|
||||||
|
withPersistedData(access.getUpgradeWithData(TurtleSide.RIGHT)),
|
||||||
access.getFuelLevel(), turtle.getOverlay()
|
access.getFuelLevel(), turtle.getOverlay()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @Nullable UpgradeData<ITurtleUpgrade> withPersistedData(@Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
|
return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.upgrade().getPersistedData(upgrade.data()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
|
@ -13,6 +13,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.TurtleAnimation;
|
import dan200.computercraft.api.turtle.TurtleAnimation;
|
||||||
import dan200.computercraft.api.turtle.TurtleCommand;
|
import dan200.computercraft.api.turtle.TurtleCommand;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
@ -141,17 +142,16 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
overlay = nbt.contains(NBT_OVERLAY) ? new ResourceLocation(nbt.getString(NBT_OVERLAY)) : null;
|
overlay = nbt.contains(NBT_OVERLAY) ? new ResourceLocation(nbt.getString(NBT_OVERLAY)) : null;
|
||||||
|
|
||||||
// Read upgrades
|
// Read upgrades
|
||||||
setUpgradeDirect(TurtleSide.LEFT, nbt.contains(NBT_LEFT_UPGRADE) ? TurtleUpgrades.instance().get(nbt.getString(NBT_LEFT_UPGRADE)) : null);
|
setUpgradeDirect(TurtleSide.LEFT, readUpgrade(nbt, NBT_LEFT_UPGRADE, NBT_LEFT_UPGRADE_DATA));
|
||||||
setUpgradeDirect(TurtleSide.RIGHT, nbt.contains(NBT_RIGHT_UPGRADE) ? TurtleUpgrades.instance().get(nbt.getString(NBT_RIGHT_UPGRADE)) : null);
|
setUpgradeDirect(TurtleSide.RIGHT, readUpgrade(nbt, NBT_RIGHT_UPGRADE, NBT_RIGHT_UPGRADE_DATA));
|
||||||
|
}
|
||||||
|
|
||||||
// NBT
|
private @Nullable UpgradeData<ITurtleUpgrade> readUpgrade(CompoundTag tag, String upgradeKey, String dataKey) {
|
||||||
upgradeNBTData.clear();
|
if (!tag.contains(upgradeKey)) return null;
|
||||||
if (nbt.contains(NBT_LEFT_UPGRADE_DATA)) {
|
var upgrade = TurtleUpgrades.instance().get(tag.getString(upgradeKey));
|
||||||
upgradeNBTData.put(TurtleSide.LEFT, nbt.getCompound(NBT_LEFT_UPGRADE_DATA).copy());
|
if (upgrade == null) return null;
|
||||||
}
|
|
||||||
if (nbt.contains(NBT_RIGHT_UPGRADE_DATA)) {
|
return UpgradeData.of(upgrade, tag.getCompound(dataKey));
|
||||||
upgradeNBTData.put(TurtleSide.RIGHT, nbt.getCompound(NBT_RIGHT_UPGRADE_DATA).copy());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeCommon(CompoundTag nbt) {
|
private void writeCommon(CompoundTag nbt) {
|
||||||
@ -516,7 +516,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) {
|
public void setUpgradeWithData(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
if (!setUpgradeDirect(side, upgrade) || owner.getLevel() == null) return;
|
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
|
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
|
||||||
@ -529,19 +529,18 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
owner.updateInputsImmediately();
|
owner.updateInputsImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setUpgradeDirect(TurtleSide side, @Nullable ITurtleUpgrade upgrade) {
|
private boolean setUpgradeDirect(TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
// Remove old upgrade
|
// Remove old upgrade
|
||||||
if (upgrades.containsKey(side)) {
|
var oldUpgrade = upgrades.remove(side);
|
||||||
if (upgrades.get(side) == upgrade) return false;
|
if (oldUpgrade == null && upgrade == null) return false;
|
||||||
upgrades.remove(side);
|
|
||||||
} else {
|
|
||||||
if (upgrade == null) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
upgradeNBTData.remove(side);
|
|
||||||
|
|
||||||
// Set new upgrade
|
// Set new upgrade
|
||||||
if (upgrade != null) upgrades.put(side, upgrade);
|
if (upgrade == null) {
|
||||||
|
upgradeNBTData.remove(side);
|
||||||
|
} else {
|
||||||
|
upgrades.put(side, upgrade.upgrade());
|
||||||
|
upgradeNBTData.put(side, upgrade.data().copy());
|
||||||
|
}
|
||||||
|
|
||||||
// Notify clients and create peripherals
|
// Notify clients and create peripherals
|
||||||
if (owner.getLevel() != null && !owner.getLevel().isClientSide) {
|
if (owner.getLevel() != null && !owner.getLevel().isClientSide) {
|
||||||
@ -595,7 +594,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
|
|
||||||
public float getToolRenderAngle(TurtleSide side, float f) {
|
public float getToolRenderAngle(TurtleSide side, float f) {
|
||||||
return (side == TurtleSide.LEFT && animation == TurtleAnimation.SWING_LEFT_TOOL) ||
|
return (side == TurtleSide.LEFT && animation == TurtleAnimation.SWING_LEFT_TOOL) ||
|
||||||
(side == TurtleSide.RIGHT && animation == TurtleAnimation.SWING_RIGHT_TOOL)
|
(side == TurtleSide.RIGHT && animation == TurtleAnimation.SWING_RIGHT_TOOL)
|
||||||
? 45.0f * (float) Math.sin(getAnimationFraction(f) * Math.PI)
|
? 45.0f * (float) Math.sin(getAnimationFraction(f) * Math.PI)
|
||||||
: 0.0f;
|
: 0.0f;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package dan200.computercraft.shared.turtle.core;
|
package dan200.computercraft.shared.turtle.core;
|
||||||
|
|
||||||
import dan200.computercraft.api.turtle.*;
|
import dan200.computercraft.api.turtle.*;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.turtle.TurtleUtil;
|
import dan200.computercraft.shared.turtle.TurtleUtil;
|
||||||
|
|
||||||
@ -18,10 +19,10 @@ public class TurtleEquipCommand implements TurtleCommand {
|
|||||||
@Override
|
@Override
|
||||||
public TurtleCommandResult execute(ITurtleAccess turtle) {
|
public TurtleCommandResult execute(ITurtleAccess turtle) {
|
||||||
// Determine the upgrade to replace
|
// Determine the upgrade to replace
|
||||||
var oldUpgrade = turtle.getUpgrade(side);
|
var oldUpgrade = turtle.getUpgradeWithData(side);
|
||||||
|
|
||||||
// Determine the upgrade to equipLeft
|
// Determine the upgrade to equipLeft
|
||||||
ITurtleUpgrade newUpgrade;
|
UpgradeData<ITurtleUpgrade> newUpgrade;
|
||||||
var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot());
|
var selectedStack = turtle.getInventory().getItem(turtle.getSelectedSlot());
|
||||||
if (!selectedStack.isEmpty()) {
|
if (!selectedStack.isEmpty()) {
|
||||||
newUpgrade = TurtleUpgrades.instance().get(selectedStack);
|
newUpgrade = TurtleUpgrades.instance().get(selectedStack);
|
||||||
@ -32,8 +33,8 @@ public class TurtleEquipCommand implements TurtleCommand {
|
|||||||
|
|
||||||
// Do the swapping:
|
// Do the swapping:
|
||||||
if (newUpgrade != null) turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1);
|
if (newUpgrade != null) turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1);
|
||||||
if (oldUpgrade != null) TurtleUtil.storeItemOrDrop(turtle, oldUpgrade.getCraftingItem().copy());
|
if (oldUpgrade != null) TurtleUtil.storeItemOrDrop(turtle, oldUpgrade.getUpgradeItem());
|
||||||
turtle.setUpgrade(side, newUpgrade);
|
turtle.setUpgradeWithData(side, newUpgrade);
|
||||||
|
|
||||||
// Animate
|
// Animate
|
||||||
if (newUpgrade != null || oldUpgrade != null) {
|
if (newUpgrade != null || oldUpgrade != null) {
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.turtle.inventory;
|
|||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
@ -27,7 +28,7 @@ class UpgradeContainer implements Container {
|
|||||||
|
|
||||||
private final ITurtleAccess turtle;
|
private final ITurtleAccess turtle;
|
||||||
|
|
||||||
private final List<ITurtleUpgrade> lastUpgrade = Arrays.asList(null, null);
|
private final List<UpgradeData<ITurtleUpgrade>> lastUpgrade = Arrays.asList(null, null);
|
||||||
private final NonNullList<ItemStack> lastStack = NonNullList.withSize(2, ItemStack.EMPTY);
|
private final NonNullList<ItemStack> lastStack = NonNullList.withSize(2, ItemStack.EMPTY);
|
||||||
|
|
||||||
UpgradeContainer(ITurtleAccess turtle) {
|
UpgradeContainer(ITurtleAccess turtle) {
|
||||||
@ -44,22 +45,25 @@ class UpgradeContainer implements Container {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getItem(int slot) {
|
public ItemStack getItem(int slot) {
|
||||||
var upgrade = turtle.getUpgrade(getSide(slot));
|
var side = getSide(slot);
|
||||||
|
var upgrade = turtle.getUpgrade(side);
|
||||||
|
if (upgrade == null) return ItemStack.EMPTY;
|
||||||
|
|
||||||
// We don't want to return getCraftingItem directly here, as consumers may mutate the stack (they shouldn't!,
|
// 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
|
// but if they do it's a pain to track down). To avoid recreating the stack each tick, we maintain a simple
|
||||||
// cache.
|
// cache. We use an inlined getUpgradeData here to avoid the additional defensive copy.
|
||||||
if (upgrade == lastUpgrade.get(slot)) return lastStack.get(slot);
|
var upgradeData = UpgradeData.of(upgrade, turtle.getUpgradeNBTData(side));
|
||||||
|
if (upgradeData.equals(lastUpgrade.get(slot))) return lastStack.get(slot);
|
||||||
|
|
||||||
var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getCraftingItem().copy();
|
var stack = upgradeData.getUpgradeItem();
|
||||||
lastUpgrade.set(slot, upgrade);
|
lastUpgrade.set(slot, upgradeData.copy());
|
||||||
lastStack.set(slot, stack);
|
lastStack.set(slot, stack);
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setItem(int slot, ItemStack itemStack) {
|
public void setItem(int slot, ItemStack itemStack) {
|
||||||
turtle.setUpgrade(getSide(slot), TurtleUpgrades.instance().get(itemStack));
|
turtle.setUpgradeWithData(getSide(slot), TurtleUpgrades.instance().get(itemStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -8,12 +8,14 @@ import dan200.computercraft.annotations.ForgeOverride;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.IColouredItem;
|
import dan200.computercraft.shared.common.IColouredItem;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
|
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
|
||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
||||||
|
import dan200.computercraft.shared.util.NBTUtil;
|
||||||
import net.minecraft.core.cauldron.CauldronInteraction;
|
import net.minecraft.core.cauldron.CauldronInteraction;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@ -32,7 +34,7 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
|
|||||||
|
|
||||||
public static ItemStack create(
|
public static ItemStack create(
|
||||||
int id, @Nullable String label, int colour, ComputerFamily family,
|
int id, @Nullable String label, int colour, ComputerFamily family,
|
||||||
@Nullable ITurtleUpgrade leftUpgrade, @Nullable ITurtleUpgrade rightUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade, @Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
||||||
int fuelLevel, @Nullable ResourceLocation overlay
|
int fuelLevel, @Nullable ResourceLocation overlay
|
||||||
) {
|
) {
|
||||||
return switch (family) {
|
return switch (family) {
|
||||||
@ -46,7 +48,7 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
|
|||||||
|
|
||||||
public ItemStack create(
|
public ItemStack create(
|
||||||
int id, @Nullable String label, int colour,
|
int id, @Nullable String label, int colour,
|
||||||
@Nullable ITurtleUpgrade leftUpgrade, @Nullable ITurtleUpgrade rightUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade, @Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
||||||
int fuelLevel, @Nullable ResourceLocation overlay
|
int fuelLevel, @Nullable ResourceLocation overlay
|
||||||
) {
|
) {
|
||||||
// Build the stack
|
// Build the stack
|
||||||
@ -58,11 +60,15 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
|
|||||||
if (overlay != null) stack.getOrCreateTag().putString(NBT_OVERLAY, overlay.toString());
|
if (overlay != null) stack.getOrCreateTag().putString(NBT_OVERLAY, overlay.toString());
|
||||||
|
|
||||||
if (leftUpgrade != null) {
|
if (leftUpgrade != null) {
|
||||||
stack.getOrCreateTag().putString(NBT_LEFT_UPGRADE, leftUpgrade.getUpgradeID().toString());
|
var tag = stack.getOrCreateTag();
|
||||||
|
tag.putString(NBT_LEFT_UPGRADE, leftUpgrade.upgrade().getUpgradeID().toString());
|
||||||
|
if (!leftUpgrade.data().isEmpty()) tag.put(NBT_LEFT_UPGRADE_DATA, leftUpgrade.data().copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightUpgrade != null) {
|
if (rightUpgrade != null) {
|
||||||
stack.getOrCreateTag().putString(NBT_RIGHT_UPGRADE, rightUpgrade.getUpgradeID().toString());
|
var tag = stack.getOrCreateTag();
|
||||||
|
tag.putString(NBT_RIGHT_UPGRADE, rightUpgrade.upgrade().getUpgradeID().toString());
|
||||||
|
if (!rightUpgrade.data().isEmpty()) tag.put(NBT_RIGHT_UPGRADE_DATA, rightUpgrade.data().copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack;
|
return stack;
|
||||||
@ -117,7 +123,7 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
|
|||||||
return create(
|
return create(
|
||||||
getComputerID(stack), getLabel(stack),
|
getComputerID(stack), getLabel(stack),
|
||||||
getColour(stack), family,
|
getColour(stack), family,
|
||||||
getUpgrade(stack, TurtleSide.LEFT), getUpgrade(stack, TurtleSide.RIGHT),
|
getUpgradeWithData(stack, TurtleSide.LEFT), getUpgradeWithData(stack, TurtleSide.RIGHT),
|
||||||
getFuelLevel(stack), getOverlay(stack)
|
getFuelLevel(stack), getOverlay(stack)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -127,7 +133,20 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem {
|
|||||||
if (tag == null) return null;
|
if (tag == null) return null;
|
||||||
|
|
||||||
var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE;
|
var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE;
|
||||||
return tag.contains(key) ? TurtleUpgrades.instance().get(tag.getString(key)) : null;
|
if (!tag.contains(key)) return null;
|
||||||
|
return TurtleUpgrades.instance().get(tag.getString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable UpgradeData<ITurtleUpgrade> getUpgradeWithData(ItemStack stack, TurtleSide side) {
|
||||||
|
var tag = stack.getTag();
|
||||||
|
if (tag == null) return null;
|
||||||
|
|
||||||
|
var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE;
|
||||||
|
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 UpgradeData.of(upgrade, NBTUtil.getCompoundOrEmpty(tag, dataKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable ResourceLocation getOverlay(ItemStack stack) {
|
public @Nullable ResourceLocation getOverlay(ItemStack stack) {
|
||||||
|
@ -38,8 +38,8 @@ public class TurtleOverlayRecipe extends ShapelessRecipe {
|
|||||||
turtle.getComputerID(stack),
|
turtle.getComputerID(stack),
|
||||||
turtle.getLabel(stack),
|
turtle.getLabel(stack),
|
||||||
turtle.getColour(stack),
|
turtle.getColour(stack),
|
||||||
turtle.getUpgrade(stack, TurtleSide.LEFT),
|
turtle.getUpgradeWithData(stack, TurtleSide.LEFT),
|
||||||
turtle.getUpgrade(stack, TurtleSide.RIGHT),
|
turtle.getUpgradeWithData(stack, TurtleSide.RIGHT),
|
||||||
turtle.getFuelLevel(stack),
|
turtle.getFuelLevel(stack),
|
||||||
overlay
|
overlay
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,7 @@ package dan200.computercraft.shared.turtle.recipes;
|
|||||||
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
@ -104,9 +105,10 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
|
|||||||
// At this point we have a turtle + 1 or 2 items
|
// At this point we have a turtle + 1 or 2 items
|
||||||
// Get the turtle we already have
|
// Get the turtle we already have
|
||||||
var itemTurtle = (TurtleItem) turtle.getItem();
|
var itemTurtle = (TurtleItem) turtle.getItem();
|
||||||
var upgrades = new ITurtleUpgrade[]{
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
itemTurtle.getUpgrade(turtle, TurtleSide.LEFT),
|
UpgradeData<ITurtleUpgrade>[] upgrades = new UpgradeData[]{
|
||||||
itemTurtle.getUpgrade(turtle, TurtleSide.RIGHT),
|
itemTurtle.getUpgradeWithData(turtle, TurtleSide.LEFT),
|
||||||
|
itemTurtle.getUpgradeWithData(turtle, TurtleSide.RIGHT),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the upgrades for the new items
|
// Get the upgrades for the new items
|
||||||
|
@ -9,6 +9,7 @@ import dan200.computercraft.api.turtle.*;
|
|||||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
@ -77,4 +78,9 @@ public class TurtleModem extends AbstractTurtleUpgrade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getPersistedData(CompoundTag upgradeData) {
|
||||||
|
return new CompoundTag();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.util;
|
|||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
import dan200.computercraft.core.util.Nullability;
|
import dan200.computercraft.core.util.Nullability;
|
||||||
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -19,6 +20,7 @@ import java.io.OutputStream;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -27,9 +29,42 @@ public final class NBTUtil {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final BaseEncoding ENCODING = BaseEncoding.base16().lowerCase();
|
static final BaseEncoding ENCODING = BaseEncoding.base16().lowerCase();
|
||||||
|
|
||||||
|
private static final CompoundTag EMPTY_TAG;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// If in a development environment, create a magic immutable compound tag.
|
||||||
|
// We avoid doing this in prod, as I fear it might mess up the JIT inlining things.
|
||||||
|
if (PlatformHelper.get().isDevelopmentEnvironment()) {
|
||||||
|
try {
|
||||||
|
var ctor = CompoundTag.class.getDeclaredConstructor(Map.class);
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
EMPTY_TAG = ctor.newInstance(Collections.emptyMap());
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EMPTY_TAG = new CompoundTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private NBTUtil() {
|
private NBTUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a singleton empty {@link CompoundTag}. This tag should never be modified.
|
||||||
|
*
|
||||||
|
* @return The empty compound tag.
|
||||||
|
*/
|
||||||
|
public static CompoundTag emptyTag() {
|
||||||
|
if (EMPTY_TAG.size() != 0) LOG.error("The empty tag has been modified.");
|
||||||
|
return EMPTY_TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag getCompoundOrEmpty(CompoundTag tag, String key) {
|
||||||
|
var childTag = tag.get(key);
|
||||||
|
return childTag != null && childTag.getId() == Tag.TAG_COMPOUND ? (CompoundTag) childTag : emptyTag();
|
||||||
|
}
|
||||||
|
|
||||||
private static @Nullable Tag toNBTTag(@Nullable Object object) {
|
private static @Nullable Tag toNBTTag(@Nullable Object object) {
|
||||||
if (object == null) return null;
|
if (object == null) return null;
|
||||||
if (object instanceof Boolean) return ByteTag.valueOf((byte) ((boolean) (Boolean) object ? 1 : 0));
|
if (object instanceof Boolean) return ByteTag.valueOf((byte) ((boolean) (Boolean) object ? 1 : 0));
|
||||||
|
@ -58,6 +58,11 @@ import java.util.function.Predicate;
|
|||||||
|
|
||||||
@AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class })
|
@AutoService({ PlatformHelper.class, dan200.computercraft.impl.PlatformHelper.class, ComputerCraftAPIService.class })
|
||||||
public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper {
|
public class TestPlatformHelper extends AbstractComputerCraftAPI implements PlatformHelper {
|
||||||
|
@Override
|
||||||
|
public boolean isDevelopmentEnvironment() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigFile.Builder createConfigBuilder() {
|
public ConfigFile.Builder createConfigBuilder() {
|
||||||
throw new UnsupportedOperationException("Cannot create config file inside tests");
|
throw new UnsupportedOperationException("Cannot create config file inside tests");
|
||||||
|
@ -33,6 +33,7 @@ import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType;
|
|||||||
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
|
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage;
|
import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage;
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
|
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
@ -81,6 +82,11 @@ import java.util.function.*;
|
|||||||
|
|
||||||
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
||||||
public class PlatformHelperImpl implements PlatformHelper {
|
public class PlatformHelperImpl implements PlatformHelper {
|
||||||
|
@Override
|
||||||
|
public boolean isDevelopmentEnvironment() {
|
||||||
|
return FabricLoader.getInstance().isDevelopmentEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigFile.Builder createConfigBuilder() {
|
public ConfigFile.Builder createConfigBuilder() {
|
||||||
return new FabricConfigFile.Builder();
|
return new FabricConfigFile.Builder();
|
||||||
|
@ -62,6 +62,7 @@ import net.minecraftforge.common.util.NonNullConsumer;
|
|||||||
import net.minecraftforge.event.ForgeEventFactory;
|
import net.minecraftforge.event.ForgeEventFactory;
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
|
import net.minecraftforge.fml.loading.FMLLoader;
|
||||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||||
import net.minecraftforge.network.NetworkHooks;
|
import net.minecraftforge.network.NetworkHooks;
|
||||||
@ -76,6 +77,11 @@ import java.util.function.*;
|
|||||||
|
|
||||||
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
||||||
public class PlatformHelperImpl implements PlatformHelper {
|
public class PlatformHelperImpl implements PlatformHelper {
|
||||||
|
@Override
|
||||||
|
public boolean isDevelopmentEnvironment() {
|
||||||
|
return !FMLLoader.isProduction();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigFile.Builder createConfigBuilder() {
|
public ConfigFile.Builder createConfigBuilder() {
|
||||||
return new ForgeConfigFile.Builder();
|
return new ForgeConfigFile.Builder();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user