Add the digitizer block #56
1
assets/digitizer.bbmodel
Normal file
1
assets/digitizer.bbmodel
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/digitizer_peripheral.afdesign
Normal file
BIN
assets/digitizer_peripheral.afdesign
Normal file
Binary file not shown.
BIN
assets/gui/digitizer_gui.afdesign
Normal file
BIN
assets/gui/digitizer_gui.afdesign
Normal file
Binary file not shown.
BIN
assets/textures/digitizer.png
Normal file
BIN
assets/textures/digitizer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 711 B |
@ -3,9 +3,11 @@ package net.banutama.utamacraft;
|
||||
import dan200.computercraft.api.ForgeComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
import net.banutama.utamacraft.block.entity.AwarenessBlockEntity;
|
||||
import net.banutama.utamacraft.block.entity.DigitizerBlockEntity;
|
||||
import net.banutama.utamacraft.block.entity.InsolatorBlockEntity;
|
||||
import net.banutama.utamacraft.integrations.computercraft.PeripheralProvider;
|
||||
import net.banutama.utamacraft.integrations.computercraft.peripheral.AwarenessBlockPeripheral;
|
||||
import net.banutama.utamacraft.integrations.computercraft.peripheral.DigitizerPeripheral;
|
||||
import net.banutama.utamacraft.integrations.computercraft.peripheral.InsolatorPeripheral;
|
||||
import net.banutama.utamacraft.integrations.computercraft.turtles.TurtlePlayerUpgrade;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@ -17,7 +19,6 @@ import net.minecraftforge.registries.RegistryObject;
|
||||
* CC:Tweaked registration
|
||||
*/
|
||||
public class CCRegistration {
|
||||
|
||||
public static final DeferredRegister<TurtleUpgradeSerialiser<?>> TURTLE_SERIALIZERS = DeferredRegister
|
||||
.create(TurtleUpgradeSerialiser.REGISTRY_ID, Utamacraft.MOD_ID);
|
||||
|
||||
@ -33,6 +34,7 @@ public class CCRegistration {
|
||||
peripheralProvider.registerBlockPeripheral(InsolatorPeripheral::new, InsolatorBlockEntity.class::isInstance);
|
||||
peripheralProvider.registerBlockPeripheral(AwarenessBlockPeripheral::new,
|
||||
AwarenessBlockEntity.class::isInstance);
|
||||
peripheralProvider.registerBlockPeripheral(DigitizerPeripheral::new, DigitizerBlockEntity.class::isInstance);
|
||||
|
||||
ForgeComputerCraftAPI.registerPeripheralProvider(peripheralProvider);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import net.banutama.utamacraft.item.ModItems;
|
||||
|
||||
import net.banutama.utamacraft.networking.ModMessages;
|
||||
import net.banutama.utamacraft.recipe.ModRecipes;
|
||||
import net.banutama.utamacraft.screen.DigitizerScreen;
|
||||
import net.banutama.utamacraft.screen.InsolatorScreen;
|
||||
import net.banutama.utamacraft.screen.ModMenuTypes;
|
||||
import net.banutama.utamacraft.sound.ModSounds;
|
||||
@ -69,6 +70,7 @@ public class Utamacraft {
|
||||
@SubscribeEvent
|
||||
public static void onClientSetup(FMLClientSetupEvent event) {
|
||||
MenuScreens.register(ModMenuTypes.INSOLATOR_MENU.get(), InsolatorScreen::new);
|
||||
MenuScreens.register(ModMenuTypes.DIGITIZER_MENU.get(), DigitizerScreen::new);
|
||||
CuriosRenderers.register();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,140 @@
|
||||
package net.banutama.utamacraft.block.custom;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.banutama.utamacraft.block.entity.DigitizerBlockEntity;
|
||||
import net.banutama.utamacraft.block.entity.ModBlockEntities;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.RenderShape;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
|
||||
public class DigitizerBlock extends BaseEntityBlock {
|
||||
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
public static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 16, 16);
|
||||
|
||||
public DigitizerBlock() {
|
||||
super(getProperties());
|
||||
registerDefaultState(this.getStateDefinition().any().setValue(FACING, Direction.NORTH));
|
||||
}
|
||||
|
||||
private static Block.Properties getProperties() {
|
||||
return Block.Properties.of(Material.STONE).strength(3.0f).requiresCorrectToolForDrops().noOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter getter, @NotNull BlockPos pos,
|
||||
@NotNull CollisionContext context) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState rotate(BlockState state, Rotation rotation) {
|
||||
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public @NotNull BlockState mirror(BlockState state, Mirror mirror) {
|
||||
return state.rotate(mirror.getRotation(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
builder.add(FACING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull RenderShape getRenderShape(@NotNull BlockState state) {
|
||||
return RenderShape.MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnalogOutputSignal(BlockState pState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) {
|
||||
if (!(level.getBlockEntity(pos) instanceof DigitizerBlockEntity entity)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var stack = entity.getInventory().getStackInSlot(0);
|
||||
return (int) (1 + (float) stack.getCount() / stack.getMaxStackSize() * 14);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onRemove(BlockState state, @NotNull Level level, @NotNull BlockPos pos, BlockState newState,
|
||||
boolean isMoving) {
|
||||
if (!state.is(newState.getBlock())) {
|
||||
if (level.getBlockEntity(pos) instanceof DigitizerBlockEntity digitizer) {
|
||||
if (level instanceof ServerLevel) {
|
||||
digitizer.getInventoryOptional().ifPresent(handler -> {
|
||||
for (int slot = 0; slot < handler.getSlots(); ++slot) {
|
||||
Block.popResource(level, pos, handler.getStackInSlot(slot));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
level.updateNeighbourForOutputSignal(pos, this);
|
||||
}
|
||||
}
|
||||
|
||||
super.onRemove(state, level, pos, newState, isMoving);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InteractionResult use(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos,
|
||||
@NotNull Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hit) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (!(blockEntity instanceof DigitizerBlockEntity digitizerEntity)) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
if (level.isClientSide()) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
NetworkHooks.openScreen(serverPlayer, digitizerEntity, pos);
|
||||
}
|
||||
|
||||
return InteractionResult.CONSUME;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) {
|
||||
return ModBlockEntities.DIGITIZER.get().create(pos, state);
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ public class ModBlocks {
|
||||
.requiresCorrectToolForDrops()));
|
||||
public static final RegistryObject<Block> INSOLATOR = registerBlock("insolator", InsolatorBlock::new);
|
||||
public static final RegistryObject<Block> AWARENESS_BLOCK = registerBlock("awareness_block", AwarenessBlock::new);
|
||||
public static final RegistryObject<Block> DIGITIZER = registerBlock("digitizer", DigitizerBlock::new);
|
||||
|
||||
private static <T extends Block> RegistryObject<T> registerBlock(String name, Supplier<T> block) {
|
||||
RegistryObject<T> registered_block = BLOCKS.register(name, block);
|
||||
|
@ -0,0 +1,144 @@
|
||||
package net.banutama.utamacraft.block.entity;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.banutama.utamacraft.screen.DigitizerMenu;
|
||||
import net.banutama.utamacraft.util.ModEnergyStorage;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
|
||||
public class DigitizerBlockEntity extends BlockEntity implements MenuProvider {
|
||||
public static final int MATERIALZE_ENERGY_REQUIRED = 1024;
|
||||
public static final int REFRESH_ENERGY_REQUIRED = 64;
|
||||
public static final int ENERGY_MAX = MATERIALZE_ENERGY_REQUIRED * 64;
|
||||
public static final int ENERGY_DRAW = ENERGY_MAX / (20 * 10);
|
||||
|
||||
private final ItemStackHandler inventory = new ItemStackHandler(1) {
|
||||
@Override
|
||||
protected void onContentsChanged(int slot) {
|
||||
super.onContentsChanged(slot);
|
||||
DigitizerBlockEntity.this.sendUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
|
||||
return switch (slot) {
|
||||
case 0 -> true;
|
||||
default -> super.isItemValid(slot, stack);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
private final ModEnergyStorage energy = new ModEnergyStorage(ENERGY_MAX, ENERGY_DRAW) {
|
||||
@Override
|
||||
public void onEnergyChanged() {
|
||||
setChanged();
|
||||
DigitizerBlockEntity.this.sendUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
private final LazyOptional<ItemStackHandler> inventoryOptional = LazyOptional.of(() -> inventory);
|
||||
private final LazyOptional<ModEnergyStorage> energyOptional = LazyOptional.of(() -> energy);
|
||||
|
||||
public DigitizerBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(ModBlockEntities.DIGITIZER.get(), pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component getDisplayName() {
|
||||
return Component.translatable("block_entity.utamacraft.digitizer");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AbstractContainerMenu createMenu(int containerId, @NotNull Inventory playerInventory,
|
||||
@NotNull Player player) {
|
||||
return new DigitizerMenu(containerId, playerInventory, this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == ForgeCapabilities.ITEM_HANDLER) {
|
||||
return inventoryOptional.cast();
|
||||
}
|
||||
|
||||
if (cap == ForgeCapabilities.ENERGY) {
|
||||
return energyOptional.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
inventoryOptional.invalidate();
|
||||
energyOptional.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(@NotNull CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
nbt.put("inventory", inventory.serializeNBT());
|
||||
nbt.put("energy", energy.serializeNBT());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
inventory.deserializeNBT(nbt.getCompound("inventory"));
|
||||
energy.deserializeNBT(nbt.get("energy"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundTag getUpdateTag() {
|
||||
CompoundTag nbt = super.getUpdateTag();
|
||||
saveAdditional(nbt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Packet<ClientGamePacketListener> getUpdatePacket() {
|
||||
return ClientboundBlockEntityDataPacket.create(this);
|
||||
}
|
||||
|
||||
protected void sendUpdate() {
|
||||
setChanged();
|
||||
|
||||
if (this.level != null) {
|
||||
this.level.sendBlockUpdated(this.worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStackHandler getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public ModEnergyStorage getEnergy() {
|
||||
return energy;
|
||||
}
|
||||
|
||||
public LazyOptional<ItemStackHandler> getInventoryOptional() {
|
||||
return inventoryOptional;
|
||||
}
|
||||
}
|
@ -20,6 +20,10 @@ public class ModBlockEntities {
|
||||
"awareness_block",
|
||||
() -> BlockEntityType.Builder.of(AwarenessBlockEntity::new, ModBlocks.AWARENESS_BLOCK.get()).build(null));
|
||||
|
||||
public static final RegistryObject<BlockEntityType<DigitizerBlockEntity>> DIGITIZER = BLOCK_ENTITIES.register(
|
||||
"digitizer_block",
|
||||
() -> BlockEntityType.Builder.of(DigitizerBlockEntity::new, ModBlocks.DIGITIZER.get()).build(null));
|
||||
|
||||
public static void register(IEventBus bus) {
|
||||
BLOCK_ENTITIES.register(bus);
|
||||
}
|
||||
|
@ -0,0 +1,323 @@
|
||||
package net.banutama.utamacraft.integrations.computercraft.peripheral;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import dan200.computercraft.api.lua.IArguments;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.lua.MethodResult;
|
||||
import net.banutama.utamacraft.block.entity.DigitizerBlockEntity;
|
||||
import net.banutama.utamacraft.integrations.computercraft.peripheral.digitizer.DigitizedCache;
|
||||
import net.banutama.utamacraft.integrations.computercraft.peripheral.digitizer.DigitizedItem;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class DigitizerPeripheral extends BasePeripheral {
|
||||
public static final String PERIPHERAL_TYPE = "digitizier";
|
||||
|
||||
protected DigitizerPeripheral(BasePeripheralOwner owner) {
|
||||
super(PERIPHERAL_TYPE, owner);
|
||||
}
|
||||
|
||||
public DigitizerPeripheral(BlockEntity blockEntity) {
|
||||
this(new BlockEntityPeripheralOwner(blockEntity));
|
||||
}
|
||||
|
||||
private DigitizerBlockEntity getDigitizer() throws LuaException {
|
||||
if (!(owner instanceof BlockEntityPeripheralOwner blockOwner)) {
|
||||
throw new LuaException("Owner of this DigitizerPeripheral is not a BlockEntityPeripheralOwner");
|
||||
}
|
||||
|
||||
if (!(blockOwner.getBlockEntity() instanceof DigitizerBlockEntity digitizer)) {
|
||||
throw new LuaException("Owner of this DigitizerPeripheral is not a DigitizerBlockEntity");
|
||||
}
|
||||
|
||||
return digitizer;
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int getEnergy() throws LuaException {
|
||||
return getDigitizer().getEnergy().getEnergyStored();
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int getEnergyCapacity() throws LuaException {
|
||||
return getDigitizer().getEnergy().getMaxEnergyStored();
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int size() throws LuaException {
|
||||
return getDigitizer().getInventory().getSlots();
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int getDigitizationCost() {
|
||||
return DigitizerBlockEntity.MATERIALZE_ENERGY_REQUIRED;
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int getRefreshCost() {
|
||||
return DigitizerBlockEntity.REFRESH_ENERGY_REQUIRED;
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final int getItemLimit(int slot) throws LuaException {
|
||||
var inventory = getDigitizer().getInventory();
|
||||
if (slot < 1 || slot > inventory.getSlots()) {
|
||||
throw new LuaException(
|
||||
String.format("Slot %d is out of range (%d slots available)", slot, inventory.getSlots()));
|
||||
}
|
||||
|
||||
return inventory.getSlotLimit(slot - 1);
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult getItemDetail(int slot) throws LuaException {
|
||||
var inventory = getDigitizer().getInventory();
|
||||
if (slot < 1 || slot > inventory.getSlots()) {
|
||||
throw new LuaException(
|
||||
String.format("Slot %d is out of range (%d slots available)", slot, inventory.getSlots()));
|
||||
}
|
||||
|
||||
var stack = inventory.getStackInSlot(slot - 1);
|
||||
if (stack.getCount() == 0) {
|
||||
return MethodResult.of();
|
||||
}
|
||||
|
||||
ResourceLocation itemName = ForgeRegistries.ITEMS.getKey(stack.getItem());
|
||||
var dict = new HashMap<String, Object>();
|
||||
dict.put("displayName", stack.getDisplayName().getString());
|
||||
dict.put("name", itemName == null ? "unknown" : itemName.toString());
|
||||
dict.put("count", stack.getCount());
|
||||
dict.put("maxCount", stack.getMaxStackSize());
|
||||
|
||||
List<Map<String, Object>> items = new ArrayList<>();
|
||||
items.add(dict);
|
||||
|
||||
return MethodResult.of(items);
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult digitize(@NotNull IArguments arguments) throws LuaException {
|
||||
var digitizer = getDigitizer();
|
||||
var gameTime = digitizer.getLevel().getGameTime();
|
||||
var inventory = digitizer.getInventory();
|
||||
var requested = arguments.optInt(0, inventory.getStackInSlot(0).getCount());
|
||||
var simulate = arguments.optBoolean(1, false);
|
||||
|
||||
// Figure out how many items we're going to digitize (based on the requested
|
||||
// number of items and the number of items available in the inventory slot of
|
||||
// the digitizer block). We can use this to compute the cost of the
|
||||
// digitization.
|
||||
var available = inventory.getStackInSlot(0).getCount();
|
||||
var amount = Math.min(requested, available);
|
||||
var cost = DigitizerBlockEntity.MATERIALZE_ENERGY_REQUIRED * amount;
|
||||
|
||||
DigitizedItem digitized = null;
|
||||
if (!simulate && amount > 0) {
|
||||
// As we're not simulating, and there are actually some items that we can
|
||||
// digitize, we can deduct the required energy from the digitizer blocks' energy
|
||||
// store.
|
||||
var energy = digitizer.getEnergy();
|
||||
if (!energy.subtractEnergy(cost)) {
|
||||
return MethodResult.of(null,
|
||||
String.format("Not enough energy to digitize %d items (require %d, available %d)",
|
||||
amount, cost, energy.getEnergyStored()));
|
||||
}
|
||||
|
||||
// Get the extracted item stack from the digitizer and store it as a new
|
||||
// digitized item in the cache. We then keep the item for the result structure.
|
||||
var extracted = digitizer.getInventory().extractItem(0, amount, false);
|
||||
digitized = new DigitizedItem(extracted, gameTime);
|
||||
DigitizedCache.getInstance(digitizer.getLevel()).put(digitized);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("simulation", simulate);
|
||||
result.put("requested", requested);
|
||||
result.put("available", available);
|
||||
result.put("count", amount);
|
||||
result.put("cost", cost);
|
||||
|
||||
if (digitized != null) {
|
||||
result.put("item", digitized.describeItem(gameTime));
|
||||
}
|
||||
|
||||
return MethodResult.of(result);
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult materialize(@NotNull IArguments arguments) throws LuaException {
|
||||
var id = UUID.fromString(arguments.getString(0));
|
||||
var simulate = arguments.optBoolean(2, false);
|
||||
var digitizer = getDigitizer();
|
||||
var inventory = digitizer.getInventory();
|
||||
var level = digitizer.getLevel();
|
||||
var cache = DigitizedCache.getInstance(level);
|
||||
var gameTime = level.getGameTime();
|
||||
|
||||
// See if we can find the digitised item, and make sure that it has not expired.
|
||||
var digitizedItem = cache.take(id);
|
||||
if (digitizedItem == null || digitizedItem.isExpired(gameTime)) {
|
||||
return MethodResult.of(null, "No digitized item with ID " + id.toString());
|
||||
}
|
||||
|
||||
// This is the number of items available in the digitized item stack.
|
||||
var available = digitizedItem.itemStack.getCount();
|
||||
|
||||
// The requested number of items to materialize defaults to the number
|
||||
// available.
|
||||
var requested = arguments.optInt(1, available);
|
||||
requested = Math.min(requested, available);
|
||||
|
||||
// Build an ItemStack that contains the number of items that we request to
|
||||
// materialize. We're just going to use a copy for now. When we actually do the
|
||||
// materialization we'll adjust the digitized item stack.
|
||||
var remaining = available - requested;
|
||||
var materializing = digitizedItem.itemStack.copy();
|
||||
materializing.setCount(requested);
|
||||
|
||||
// Simulate the insertion of the `materializing` stack into the inventory slot.
|
||||
// This gives us back an ItemStack that describes the items that were not
|
||||
// materialized.
|
||||
var unmaterialized = inventory.insertItem(0, materializing, true);
|
||||
|
||||
// Expand the number of items in the unmaterialized stack by those remaining in
|
||||
// the digitized item stack.
|
||||
unmaterialized.grow(remaining);
|
||||
|
||||
// The actual number of items that would be materialized is the requested amount
|
||||
// minus the number of items that were unmaterialized.
|
||||
var actual = requested - unmaterialized.getCount();
|
||||
|
||||
// The materialized cost is the number of items that were actually materialized
|
||||
// times the cost per item.
|
||||
var materializeCost = DigitizerBlockEntity.MATERIALZE_ENERGY_REQUIRED * actual;
|
||||
|
||||
// The refresh cost is the number of items that were not materialized times the
|
||||
// refresh cost per item.
|
||||
var refreshCost = DigitizerBlockEntity.REFRESH_ENERGY_REQUIRED * unmaterialized.getCount();
|
||||
|
||||
// The final cost is the sum of the materialized cost and the refresh cost.
|
||||
var cost = materializeCost + refreshCost;
|
||||
|
||||
if (!simulate) {
|
||||
// The user doesn't want to simulate the materialization, so actually deduct the
|
||||
// energy needed from the digitizer blocks' energy store and then insert the
|
||||
// items into the digitizer's inventory. Any remaining items remain digitized.
|
||||
var energy = digitizer.getEnergy();
|
||||
if (!energy.subtractEnergy(cost)) {
|
||||
return MethodResult.of(null,
|
||||
String.format("Not enough energy to materialize %d items (require %d, available %d)",
|
||||
requested, cost, energy.getEnergyStored()));
|
||||
}
|
||||
|
||||
// Now we do the actual materialization: insert the items in the `materializing`
|
||||
// stack into the inventory slot. The result is the unmaterialized items.
|
||||
unmaterialized = inventory.insertItem(0, materializing, false);
|
||||
|
||||
// Expand the number of items in the unmaterialized stack by those remaining in
|
||||
// the digitized item stack.
|
||||
unmaterialized.grow(remaining);
|
||||
|
||||
if (unmaterialized.getCount() > 0) {
|
||||
// There's still some remainder, so put it back in the cache. Before we do that,
|
||||
// we need to update the count to reflect the remainder and refresh the expiry
|
||||
// time.
|
||||
digitizedItem.itemStack = unmaterialized;
|
||||
digitizedItem.refresh(gameTime);
|
||||
cache.put(digitizedItem);
|
||||
} else {
|
||||
// The digitized item stack was depleted: no items remain unmaterialized.
|
||||
digitizedItem.itemStack.setCount(0);
|
||||
}
|
||||
} else {
|
||||
// We're simulating, so put the digitized item back in the cache.
|
||||
cache.put(digitizedItem);
|
||||
}
|
||||
|
||||
// Build up information for the result.
|
||||
var result = new HashMap<String, Object>();
|
||||
result.put("simulation", simulate);
|
||||
result.put("requested", requested);
|
||||
result.put("available", available);
|
||||
result.put("materialized", actual);
|
||||
result.put("remainder", unmaterialized.getCount());
|
||||
result.put("cost", cost);
|
||||
result.put("materializeCost", materializeCost);
|
||||
result.put("refreshCost", refreshCost);
|
||||
result.put("item", digitizedItem.describeItem(gameTime));
|
||||
|
||||
return MethodResult.of(result);
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult query(@NotNull IArguments arguments) throws LuaException {
|
||||
var id = UUID.fromString(arguments.getString(0));
|
||||
var level = getDigitizer().getLevel();
|
||||
var cache = DigitizedCache.getInstance(level);
|
||||
var gameTime = level.getGameTime();
|
||||
|
||||
var digitizedItem = cache.get(id);
|
||||
if (digitizedItem != null && !digitizedItem.isExpired(gameTime)) {
|
||||
return MethodResult.of(digitizedItem.describeItem(gameTime));
|
||||
} else {
|
||||
return MethodResult.of(null, "No digitized item with ID " + id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult refresh(@NotNull IArguments arguments) throws LuaException {
|
||||
var id = UUID.fromString(arguments.getString(0));
|
||||
var simulate = arguments.optBoolean(1, false);
|
||||
var level = getDigitizer().getLevel();
|
||||
var cache = DigitizedCache.getInstance(level);
|
||||
var gameTime = level.getGameTime();
|
||||
|
||||
var digitizedItem = cache.get(id);
|
||||
if (digitizedItem != null && !digitizedItem.isExpired(gameTime)) {
|
||||
var cost = DigitizerBlockEntity.REFRESH_ENERGY_REQUIRED * digitizedItem.itemStack.getCount();
|
||||
if (!simulate) {
|
||||
var energy = getDigitizer().getEnergy();
|
||||
if (!energy.subtractEnergy(cost)) {
|
||||
return MethodResult.of(null,
|
||||
String.format("Not enough energy to refresh %d items (require %d, available %d)",
|
||||
digitizedItem.itemStack.getCount(), cost, energy.getEnergyStored()));
|
||||
}
|
||||
|
||||
digitizedItem.refresh(gameTime);
|
||||
}
|
||||
|
||||
var result = new HashMap<String, Object>();
|
||||
result.put("simulation", simulate);
|
||||
result.put("cost", cost);
|
||||
result.put("item", digitizedItem.describeItem(gameTime));
|
||||
|
||||
return MethodResult.of(result);
|
||||
} else {
|
||||
return MethodResult.of(null, "No digitized item with ID " + id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final @NotNull MethodResult list() throws LuaException {
|
||||
var level = getDigitizer().getLevel();
|
||||
var cache = DigitizedCache.getInstance(level);
|
||||
var gameTime = level.getGameTime();
|
||||
|
||||
var result = new ArrayList<Map<String, Object>>();
|
||||
cache.forEach(item -> {
|
||||
result.add(item.describeItem(gameTime));
|
||||
});
|
||||
|
||||
return MethodResult.of(result);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package net.banutama.utamacraft.integrations.computercraft.peripheral.digitizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
|
||||
import net.banutama.utamacraft.Utamacraft;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
|
||||
public class DigitizedCache extends SavedData {
|
||||
private final HashMap<UUID, DigitizedItem> cache = new HashMap<>();
|
||||
|
||||
private static DigitizedCache instance;
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@NotNull
|
||||
public static DigitizedCache getInstance(Level level) {
|
||||
if (!(level instanceof ServerLevel serverLevel)) {
|
||||
throw new RuntimeException("Cannot get DigitizedCache for non-server level");
|
||||
}
|
||||
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
var storage = serverLevel.getServer().overworld().getDataStorage();
|
||||
instance = storage.computeIfAbsent(DigitizedCache::load, DigitizedCache::create,
|
||||
String.format("%s_DigitizedCache", Utamacraft.MOD_ID));
|
||||
instance.collect(serverLevel);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DigitizedCache create() {
|
||||
return new DigitizedCache();
|
||||
}
|
||||
|
||||
public void put(@NotNull DigitizedItem item) {
|
||||
cache.put(item.id, item);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
public DigitizedItem get(UUID id) {
|
||||
return cache.get(id);
|
||||
}
|
||||
|
||||
public DigitizedItem take(UUID id) {
|
||||
var item = cache.remove(id);
|
||||
|
||||
if (item != null) {
|
||||
setDirty();
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void forEach(Consumer<DigitizedItem> consumer) {
|
||||
cache.values().forEach(consumer::accept);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DigitizedCache load(CompoundTag tag) {
|
||||
DigitizedCache cache = new DigitizedCache();
|
||||
if (tag.contains("items") && tag.get("items") instanceof ListTag) {
|
||||
((ListTag) tag.get("items")).forEach(item -> {
|
||||
var digitizedItem = new DigitizedItem((CompoundTag) item);
|
||||
cache.cache.put(digitizedItem.id, digitizedItem);
|
||||
});
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CompoundTag save(CompoundTag tag) {
|
||||
ListTag items = new ListTag();
|
||||
cache.values().forEach(digitizedItem -> {
|
||||
CompoundTag item = new CompoundTag();
|
||||
digitizedItem.serialize(item);
|
||||
items.add(item);
|
||||
});
|
||||
|
||||
tag.put("items", items);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void collect(Level level) {
|
||||
var gameTime = level.getGameTime();
|
||||
var count = cache.size();
|
||||
var iterator = cache.entrySet().iterator();
|
||||
|
||||
iterator.forEachRemaining(item -> {
|
||||
if (item.getValue().isExpired(gameTime)) {
|
||||
iterator.remove();
|
||||
}
|
||||
});
|
||||
|
||||
var remaining = cache.size();
|
||||
if (count != remaining) {
|
||||
LOGGER.info(
|
||||
String.format("Collected %d expired digitized items, %d remaining", count - remaining, remaining));
|
||||
}
|
||||
|
||||
setDirty();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package net.banutama.utamacraft.integrations.computercraft.peripheral.digitizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class DigitizedItem {
|
||||
// Lifetime of a digitized item (in ticks): 20 TPS, 60 minutes, 20
|
||||
// minutes-per-day, 5 days
|
||||
public final static long LIFETIME = 20 * 60 * 20 * 5;
|
||||
|
||||
public UUID id;
|
||||
public ItemStack itemStack;
|
||||
public long createdAt;
|
||||
public long expiresAt;
|
||||
|
||||
public DigitizedItem(ItemStack itemStack, long gameTime) {
|
||||
this.id = UUID.randomUUID();
|
||||
this.itemStack = itemStack;
|
||||
this.createdAt = gameTime;
|
||||
this.expiresAt = gameTime + LIFETIME;
|
||||
}
|
||||
|
||||
public DigitizedItem(CompoundTag tag) {
|
||||
id = tag.getUUID("id");
|
||||
itemStack = ItemStack.of((CompoundTag) tag.get("itemStack"));
|
||||
createdAt = tag.getLong("createdAt");
|
||||
expiresAt = tag.getLong("expiresAt");
|
||||
}
|
||||
|
||||
public void serialize(CompoundTag tag) {
|
||||
tag.putUUID("id", id);
|
||||
tag.put("itemStack", itemStack.serializeNBT());
|
||||
tag.putLong("createdAt", createdAt);
|
||||
tag.putLong("expiresAt", expiresAt);
|
||||
}
|
||||
|
||||
public long age(long gameTime) {
|
||||
return gameTime - createdAt;
|
||||
}
|
||||
|
||||
public long remaining(long gameTime) {
|
||||
return Math.max(0, expiresAt - gameTime);
|
||||
}
|
||||
|
||||
public boolean isExpired(long gameTime) {
|
||||
return expiresAt <= gameTime;
|
||||
}
|
||||
|
||||
public void refresh(long gameTime) {
|
||||
expiresAt = gameTime + LIFETIME;
|
||||
}
|
||||
|
||||
public void describeItem(Map<String, Object> map, long gameTime) {
|
||||
var itemName = ForgeRegistries.ITEMS.getKey(itemStack.getItem());
|
||||
|
||||
map.put("id", id.toString());
|
||||
map.put("name", itemName == null ? "unknown" : itemName.toString());
|
||||
map.put("count", itemStack.getCount());
|
||||
map.put("maxCount", itemStack.getMaxStackSize());
|
||||
map.put("createdAt", createdAt);
|
||||
map.put("expiresAt", expiresAt);
|
||||
map.put("age", age(gameTime));
|
||||
map.put("isExpired", isExpired(gameTime));
|
||||
map.put("remainingTime", remaining(gameTime));
|
||||
}
|
||||
|
||||
public Map<String, Object> describeItem(long gameTime) {
|
||||
var map = new HashMap<String, Object>();
|
||||
describeItem(map, gameTime);
|
||||
return map;
|
||||
}
|
||||
}
|
@ -1,10 +1,26 @@
|
||||
package net.banutama.utamacraft.item;
|
||||
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import dan200.computercraft.shared.Registry;
|
||||
|
||||
public abstract class BaseItem extends Item {
|
||||
public BaseItem(@NotNull Properties properties) {
|
||||
super(properties.tab(ModCreativeModeTab.TAB));
|
||||
}
|
||||
|
||||
public static void createTurtleStacks(@NotNull NonNullList<ItemStack> stack, @NotNull ResourceLocation peripheral) {
|
||||
ItemStack turtleStack = new ItemStack(Registry.ModItems.TURTLE_NORMAL.get());
|
||||
turtleStack.getOrCreateTag().putString("RightUpgrade", peripheral.toString());
|
||||
stack.add(turtleStack);
|
||||
|
||||
ItemStack advancedTurtleStack = new ItemStack(Registry.ModItems.TURTLE_ADVANCED.get());
|
||||
advancedTurtleStack.getOrCreateTag().putString("RightUpgrade", peripheral.toString());
|
||||
stack.add(advancedTurtleStack);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.banutama.utamacraft.item;
|
||||
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import net.banutama.utamacraft.CCRegistration;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
@ -18,13 +17,7 @@ public class PlayerPeripheralItem extends BaseItem {
|
||||
super.fillItemCategory(group, items);
|
||||
|
||||
if (allowedIn(group)) {
|
||||
ItemStack turtle_stack = new ItemStack(Registry.ModItems.TURTLE_NORMAL.get());
|
||||
turtle_stack.getOrCreateTag().putString("RightUpgrade", CCRegistration.ID.PLAYER_TURTLE.toString());
|
||||
items.add(turtle_stack);
|
||||
|
||||
ItemStack advanced_turtle_stack = new ItemStack(Registry.ModItems.TURTLE_ADVANCED.get());
|
||||
advanced_turtle_stack.getOrCreateTag().putString("RightUpgrade", CCRegistration.ID.PLAYER_TURTLE.toString());
|
||||
items.add(advanced_turtle_stack);
|
||||
createTurtleStacks(items, CCRegistration.ID.PLAYER_TURTLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
package net.banutama.utamacraft.screen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public abstract class BaseAbstractContainerMenu extends AbstractContainerMenu {
|
||||
private static final int HOTBAR_SLOT_COUNT = 9;
|
||||
|
||||
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
|
||||
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
|
||||
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_ROW_COUNT * PLAYER_INVENTORY_COLUMN_COUNT;
|
||||
|
||||
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
|
||||
private static final int TILE_ENTITY_START_SLOT = VANILLA_SLOT_COUNT;
|
||||
|
||||
protected BaseAbstractContainerMenu(MenuType<?> type, int id) {
|
||||
super(type, id);
|
||||
}
|
||||
|
||||
protected abstract int getTileEntitySlotCount();
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack quickMoveStack(@NotNull Player player, int index) {
|
||||
Slot source = slots.get(index);
|
||||
if (!source.hasItem()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
ItemStack sourceStack = source.getItem();
|
||||
ItemStack sourceCopy = sourceStack.copy();
|
||||
|
||||
if (index < VANILLA_SLOT_COUNT) {
|
||||
// This is a vanilla container slot, so merge the stack into the tile inventory.
|
||||
if (!moveItemStackTo(sourceStack, TILE_ENTITY_START_SLOT, TILE_ENTITY_START_SLOT + getTileEntitySlotCount(),
|
||||
false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (index < TILE_ENTITY_START_SLOT + getTileEntitySlotCount()) {
|
||||
// This is a tile-entity slot, so merge the stack into the players inventory.
|
||||
if (!moveItemStackTo(sourceStack, 0, VANILLA_SLOT_COUNT, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
// If the stack size is zero, the entire stack was moved, so set the slot
|
||||
// contents to null.
|
||||
if (sourceStack.getCount() == 0) {
|
||||
source.set(ItemStack.EMPTY);
|
||||
} else {
|
||||
source.setChanged();
|
||||
}
|
||||
|
||||
source.onTake(player, sourceStack);
|
||||
return sourceCopy;
|
||||
}
|
||||
|
||||
protected void addPlayerInventory(Inventory inventory) {
|
||||
for (int row = 0; row < PLAYER_INVENTORY_ROW_COUNT; ++row) {
|
||||
for (int col = 0; col < PLAYER_INVENTORY_COLUMN_COUNT; ++col) {
|
||||
this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 82 + row * 18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addPlayerHotbar(Inventory inventory) {
|
||||
for (int slot = 0; slot < HOTBAR_SLOT_COUNT; ++slot) {
|
||||
this.addSlot(new Slot(inventory, slot, 8 + slot * 18, 140));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package net.banutama.utamacraft.screen;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.banutama.utamacraft.block.custom.ModBlocks;
|
||||
import net.banutama.utamacraft.block.entity.DigitizerBlockEntity;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.ContainerLevelAccess;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
public class DigitizerMenu extends BaseAbstractContainerMenu {
|
||||
public final DigitizerBlockEntity blockEntity;
|
||||
private final ContainerLevelAccess levelAccess;
|
||||
|
||||
// Client constructor
|
||||
public DigitizerMenu(int id, Inventory inventory, FriendlyByteBuf extraData) {
|
||||
this(id, inventory, inventory.player.level.getBlockEntity(extraData.readBlockPos()));
|
||||
}
|
||||
|
||||
// Server constructor
|
||||
public DigitizerMenu(int id, Inventory inventory, BlockEntity entity) {
|
||||
super(ModMenuTypes.DIGITIZER_MENU.get(), id);
|
||||
|
||||
if (entity instanceof DigitizerBlockEntity digitizer) {
|
||||
checkContainerSize(inventory, 1);
|
||||
this.levelAccess = ContainerLevelAccess.create(Objects.requireNonNull(entity.getLevel()),
|
||||
entity.getBlockPos());
|
||||
this.blockEntity = digitizer;
|
||||
|
||||
addPlayerHotbar(inventory);
|
||||
addPlayerInventory(inventory);
|
||||
|
||||
this.blockEntity.getCapability(ForgeCapabilities.ITEM_HANDLER).ifPresent(handler -> {
|
||||
this.addSlot(new SlotItemHandler(handler, 0, 26, 8));
|
||||
});
|
||||
} else {
|
||||
throw new IllegalArgumentException("Block entity must be a DigitizerBlockEntity");
|
||||
}
|
||||
}
|
||||
|
||||
public DigitizerBlockEntity getBlockEntity() {
|
||||
return blockEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
return stillValid(levelAccess, player, ModBlocks.DIGITIZER.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTileEntitySlotCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package net.banutama.utamacraft.screen;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.banutama.utamacraft.Utamacraft;
|
||||
import net.banutama.utamacraft.screen.utils.MouseUtils;
|
||||
import net.banutama.utamacraft.screen.utils.TooltipUtils;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraftforge.energy.EnergyStorage;
|
||||
|
||||
public class DigitizerScreen extends AbstractContainerScreen<DigitizerMenu> {
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Utamacraft.MOD_ID,
|
||||
"textures/gui/digitizer_gui.png");
|
||||
|
||||
public DigitizerScreen(DigitizerMenu menu, Inventory inventory, Component component) {
|
||||
super(menu, inventory, component);
|
||||
inventoryLabelY += 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
leftPos = (width - imageWidth) / 2;
|
||||
topPos = (height - imageHeight) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderBg(@NotNull PoseStack stack, float partialTick, int mouseX, int mouseY) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
RenderSystem.setShaderTexture(0, TEXTURE);
|
||||
|
||||
blit(stack, leftPos, topPos, 0, 0, imageWidth, imageHeight);
|
||||
renderEnergy(stack, leftPos + 8, topPos + 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderLabels(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY) {
|
||||
int x = (width - imageWidth) / 2;
|
||||
int y = (height - imageHeight) / 2;
|
||||
|
||||
if (MouseUtils.isMouseOver(pMouseX, pMouseY, x + 7, y + 7, 11, 62)) {
|
||||
EnergyStorage energy = menu.getBlockEntity().getEnergy();
|
||||
List<Component> components = TooltipUtils.getEnergyTooltip(energy.getEnergyStored(),
|
||||
energy.getMaxEnergyStored());
|
||||
renderTooltip(pPoseStack, components, Optional.empty(), pMouseX - x, pMouseY - y);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderEnergy(@NotNull PoseStack stack, int x, int y) {
|
||||
EnergyStorage energy = menu.getBlockEntity().getEnergy();
|
||||
if (energy.getEnergyStored() <= 0 || energy.getMaxEnergyStored() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int ENERGY_HEIGHT = 60;
|
||||
int stored = (int) (ENERGY_HEIGHT * ((float) energy.getEnergyStored() / (float) energy.getMaxEnergyStored()));
|
||||
fillGradient(stack, x, y + (ENERGY_HEIGHT - stored), x + 9, y + 60, 0xffb51500, 0xff600b00);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(@NotNull PoseStack stack, int mouseX, int mouseY, float delta) {
|
||||
renderBackground(stack);
|
||||
super.render(stack, mouseX, mouseY, delta);
|
||||
renderTooltip(stack, mouseX, mouseY);
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.*;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
@ -14,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class InsolatorMenu extends AbstractContainerMenu {
|
||||
public class InsolatorMenu extends BaseAbstractContainerMenu {
|
||||
public final InsolatorBlockEntity blockEntity;
|
||||
private final ContainerLevelAccess levelAccess;
|
||||
|
||||
@ -29,7 +28,8 @@ public class InsolatorMenu extends AbstractContainerMenu {
|
||||
|
||||
if (entity instanceof InsolatorBlockEntity insolator) {
|
||||
checkContainerSize(inventory, 3);
|
||||
this.levelAccess = ContainerLevelAccess.create(Objects.requireNonNull(entity.getLevel()), entity.getBlockPos());
|
||||
this.levelAccess = ContainerLevelAccess.create(Objects.requireNonNull(entity.getLevel()),
|
||||
entity.getBlockPos());
|
||||
this.blockEntity = insolator;
|
||||
|
||||
addPlayerHotbar(inventory);
|
||||
@ -54,62 +54,8 @@ public class InsolatorMenu extends AbstractContainerMenu {
|
||||
return stillValid(levelAccess, player, ModBlocks.INSOLATOR.get());
|
||||
}
|
||||
|
||||
private static final int HOTBAR_SLOT_COUNT = 9;
|
||||
|
||||
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
|
||||
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
|
||||
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_ROW_COUNT * PLAYER_INVENTORY_COLUMN_COUNT;
|
||||
|
||||
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
|
||||
private static final int TILE_ENTITY_START_SLOT = VANILLA_SLOT_COUNT;
|
||||
private static final int TILE_ENTITY_SLOT_COUNT = 3;
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack quickMoveStack(@NotNull Player player, int index) {
|
||||
Slot source = slots.get(index);
|
||||
if (!source.hasItem()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
ItemStack sourceStack = source.getItem();
|
||||
ItemStack sourceCopy = sourceStack.copy();
|
||||
|
||||
if (index < VANILLA_SLOT_COUNT) {
|
||||
// This is a vanilla container slot, so merge the stack into the tile inventory.
|
||||
if (!moveItemStackTo(sourceStack, TILE_ENTITY_START_SLOT, TILE_ENTITY_START_SLOT + TILE_ENTITY_SLOT_COUNT, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (index < TILE_ENTITY_START_SLOT + TILE_ENTITY_SLOT_COUNT) {
|
||||
// This is a tile-entity slot, so merge the stack into the players inventory.
|
||||
if (!moveItemStackTo(sourceStack, 0, VANILLA_SLOT_COUNT, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
// If the stack size is zero, the entire stack was moved, so set the slot contents to null.
|
||||
if (sourceStack.getCount() == 0) {
|
||||
source.set(ItemStack.EMPTY);
|
||||
} else {
|
||||
source.setChanged();
|
||||
}
|
||||
|
||||
source.onTake(player, sourceStack);
|
||||
return sourceCopy;
|
||||
}
|
||||
|
||||
private void addPlayerInventory(Inventory inventory) {
|
||||
for (int row = 0; row < PLAYER_INVENTORY_ROW_COUNT; ++row) {
|
||||
for (int col = 0; col < PLAYER_INVENTORY_COLUMN_COUNT; ++col) {
|
||||
this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 82 + row * 18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPlayerHotbar(Inventory inventory) {
|
||||
for (int slot = 0; slot < HOTBAR_SLOT_COUNT; ++slot) {
|
||||
this.addSlot(new Slot(inventory, slot, 8 + slot * 18, 140));
|
||||
}
|
||||
protected int getTileEntitySlotCount() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,16 @@ import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
public class ModMenuTypes {
|
||||
public static final DeferredRegister<MenuType<?>> MENUS =
|
||||
DeferredRegister.create(ForgeRegistries.MENU_TYPES, Utamacraft.MOD_ID);
|
||||
public static final DeferredRegister<MenuType<?>> MENUS = DeferredRegister.create(ForgeRegistries.MENU_TYPES,
|
||||
Utamacraft.MOD_ID);
|
||||
|
||||
public static final RegistryObject<MenuType<InsolatorMenu>> INSOLATOR_MENU =
|
||||
registerMenuType("insolator_menu", InsolatorMenu::new);
|
||||
public static final RegistryObject<MenuType<InsolatorMenu>> INSOLATOR_MENU = registerMenuType("insolator_menu",
|
||||
InsolatorMenu::new);
|
||||
public static final RegistryObject<MenuType<DigitizerMenu>> DIGITIZER_MENU = registerMenuType("digitizer_menu",
|
||||
DigitizerMenu::new);
|
||||
|
||||
private static <T extends AbstractContainerMenu> RegistryObject<MenuType<T>> registerMenuType(String name, IContainerFactory<T> factory) {
|
||||
private static <T extends AbstractContainerMenu> RegistryObject<MenuType<T>> registerMenuType(String name,
|
||||
IContainerFactory<T> factory) {
|
||||
return MENUS.register(name, () -> IForgeMenuType.create(factory));
|
||||
}
|
||||
|
||||
|
@ -36,5 +36,15 @@ public abstract class ModEnergyStorage extends EnergyStorage {
|
||||
return energy;
|
||||
}
|
||||
|
||||
public boolean subtractEnergy(int energy) {
|
||||
if (this.energy >= energy) {
|
||||
this.energy -= energy;
|
||||
this.onEnergyChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void onEnergyChanged();
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=north": {
|
||||
"model": "utamacraft:block/digitizer"
|
||||
},
|
||||
"facing=east": {
|
||||
"model": "utamacraft:block/digitizer",
|
||||
"y": 90
|
||||
},
|
||||
"facing=south": {
|
||||
"model": "utamacraft:block/digitizer",
|
||||
"y": 180
|
||||
},
|
||||
"facing=west": {
|
||||
"model": "utamacraft:block/digitizer",
|
||||
"y": 270
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,21 @@
|
||||
{
|
||||
"block.utamacraft.awareness_block": "Awareness Block",
|
||||
"block.utamacraft.deepslate_tungsten_ore": "Deepslate Tungsten Ore",
|
||||
"block.utamacraft.digitizer": "Digitizer",
|
||||
"block.utamacraft.ethereal_glass": "Ethereal Glass",
|
||||
"block.utamacraft.ethereal_glass_tinted": "Tinted Ethereal Glass",
|
||||
"block.utamacraft.insolator": "Insolator",
|
||||
"block.utamacraft.tungsten_block": "Tungsten Block",
|
||||
"block.utamacraft.tungsten_ore": "Tungsten Ore",
|
||||
"block_entity.utamacraft.awareness_block": "Awareness Block",
|
||||
"block_entity.utamacraft.digitizer": "Digitizer",
|
||||
"block_entity.utamacraft.insolator": "Insolator",
|
||||
"gui.utamacraft.insolator.dump": "Dump",
|
||||
"gui.utamacraft.insolator.dump.tooltip": "Dump the fluid contents of the Insolator",
|
||||
"gui.utamacraft.insolator.dump.tooltip.empty": "No fluid contents to dump from Insolator",
|
||||
"item.utamacraft.awareness_block": "Awareness Block",
|
||||
"item.utamacraft.bulb": "Bulb",
|
||||
"item.utamacraft.digitizer": "Digitizer",
|
||||
"item.utamacraft.fiber_glass": "Fiberglass",
|
||||
"item.utamacraft.fire_ward": "Fire Ward Necklace",
|
||||
"item.utamacraft.insolator": "Insolator",
|
||||
|
283
src/main/resources/assets/utamacraft/models/block/digitizer.json
Normal file
283
src/main/resources/assets/utamacraft/models/block/digitizer.json
Normal file
@ -0,0 +1,283 @@
|
||||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"texture_size": [64, 64],
|
||||
"textures": {
|
||||
"0": "utamacraft:block/digitizer",
|
||||
"particle": "utamacraft:block/digitizer"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "tray_right",
|
||||
"from": [2, 3, 12],
|
||||
"to": [3, 13, 13],
|
||||
"rotation": { "angle": 22.5, "axis": "x", "origin": [6, 8, 10] },
|
||||
"faces": {
|
||||
"north": { "uv": [3.25, 9, 3.5, 11.5], "texture": "#0" },
|
||||
"east": { "uv": [3.5, 9, 3.75, 11.5], "texture": "#0" },
|
||||
"south": { "uv": [3.75, 9, 4, 11.5], "texture": "#0" },
|
||||
"west": { "uv": [4, 9, 4.25, 11.5], "texture": "#0" },
|
||||
"up": { "uv": [10, 10, 9.75, 9.75], "texture": "#0" },
|
||||
"down": { "uv": [0.25, 10, 0, 10.25], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tray_bottom",
|
||||
"from": [2, 3, 13],
|
||||
"to": [10, 13, 14],
|
||||
"rotation": { "angle": 22.5, "axis": "x", "origin": [6, 8, 10] },
|
||||
"faces": {
|
||||
"north": { "uv": [0, 7, 2, 9.5], "texture": "#0" },
|
||||
"east": { "uv": [9, 0, 9.25, 2.5], "texture": "#0" },
|
||||
"south": { "uv": [7, 0, 9, 2.5], "texture": "#0" },
|
||||
"west": { "uv": [2, 9, 2.25, 11.5], "texture": "#0" },
|
||||
"up": { "uv": [8.75, 9.25, 6.75, 9], "texture": "#0" },
|
||||
"down": { "uv": [10.75, 9, 8.75, 9.25], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tray_left",
|
||||
"from": [9, 3, 12],
|
||||
"to": [10, 13, 13],
|
||||
"rotation": { "angle": 22.5, "axis": "x", "origin": [6, 8, 10] },
|
||||
"faces": {
|
||||
"north": { "uv": [2.25, 9, 2.5, 11.5], "texture": "#0" },
|
||||
"east": { "uv": [2.5, 9, 2.75, 11.5], "texture": "#0" },
|
||||
"south": { "uv": [2.75, 9, 3, 11.5], "texture": "#0" },
|
||||
"west": { "uv": [3, 9, 3.25, 11.5], "texture": "#0" },
|
||||
"up": { "uv": [9.75, 10, 9.5, 9.75], "texture": "#0" },
|
||||
"down": { "uv": [10, 9.5, 9.75, 9.75], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lower",
|
||||
"from": [1, 0, 1],
|
||||
"to": [15, 1, 15],
|
||||
"rotation": { "angle": 0, "axis": "z", "origin": [14, 1, 1] },
|
||||
"faces": {
|
||||
"north": { "uv": [7.75, 7.5, 11.25, 7.75], "texture": "#0" },
|
||||
"east": { "uv": [6.75, 8, 10.25, 8.25], "texture": "#0" },
|
||||
"south": { "uv": [6.75, 8.25, 10.25, 8.5], "texture": "#0" },
|
||||
"west": { "uv": [6.75, 8.5, 10.25, 8.75], "texture": "#0" },
|
||||
"up": { "uv": [7, 3.5, 3.5, 0], "texture": "#0" },
|
||||
"down": { "uv": [7, 3.5, 3.5, 7], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left",
|
||||
"from": [14, 1, 1],
|
||||
"to": [15, 2, 15],
|
||||
"rotation": { "angle": 0, "axis": "z", "origin": [14, 1, 1] },
|
||||
"faces": {
|
||||
"north": { "uv": [1.75, 9.5, 2, 9.75], "texture": "#0" },
|
||||
"east": { "uv": [6.25, 7.75, 9.75, 8], "texture": "#0" },
|
||||
"south": { "uv": [4.75, 9.5, 5, 9.75], "texture": "#0" },
|
||||
"west": { "uv": [7.75, 6.75, 11.25, 7], "texture": "#0" },
|
||||
"up": { "uv": [5.25, 11.25, 5, 7.75], "texture": "#0" },
|
||||
"down": { "uv": [5.5, 7.75, 5.25, 11.25], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upper",
|
||||
"from": [1, 2, 1],
|
||||
"to": [15, 5, 15],
|
||||
"rotation": { "angle": 0, "axis": "z", "origin": [14, 1, 1] },
|
||||
"faces": {
|
||||
"north": { "uv": [2, 7, 5.5, 7.75], "texture": "#0" },
|
||||
"east": { "uv": [7, 2.5, 10.5, 3.25], "texture": "#0" },
|
||||
"south": { "uv": [7, 3.25, 10.5, 4], "texture": "#0" },
|
||||
"west": { "uv": [7, 4, 10.5, 4.75], "texture": "#0" },
|
||||
"up": { "uv": [3.5, 3.5, 0, 0], "texture": "#0" },
|
||||
"down": { "uv": [3.5, 3.5, 0, 7], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right",
|
||||
"from": [1, 1, 1],
|
||||
"to": [2, 2, 15],
|
||||
"rotation": { "angle": 0, "axis": "z", "origin": [14, 1, 1] },
|
||||
"faces": {
|
||||
"north": { "uv": [4.75, 9.75, 5, 10], "texture": "#0" },
|
||||
"east": { "uv": [7.75, 7, 11.25, 7.25], "texture": "#0" },
|
||||
"south": { "uv": [9.75, 8.75, 10, 9], "texture": "#0" },
|
||||
"west": { "uv": [7.75, 7.25, 11.25, 7.5], "texture": "#0" },
|
||||
"up": { "uv": [6.5, 11.5, 6.25, 8], "texture": "#0" },
|
||||
"down": { "uv": [6.75, 8, 6.5, 11.5], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "back",
|
||||
"from": [2, 1, 14],
|
||||
"to": [14, 2, 15],
|
||||
"rotation": { "angle": 0, "axis": "z", "origin": [14, 1, 1] },
|
||||
"faces": {
|
||||
"north": { "uv": [2, 8.25, 5, 8.5], "texture": "#0" },
|
||||
"east": { "uv": [9.25, 9.75, 9.5, 10], "texture": "#0" },
|
||||
"south": { "uv": [2, 8.5, 5, 8.75], "texture": "#0" },
|
||||
"west": { "uv": [9.75, 9.25, 10, 9.5], "texture": "#0" },
|
||||
"up": { "uv": [5, 9, 2, 8.75], "texture": "#0" },
|
||||
"down": { "uv": [9.75, 8.75, 6.75, 9], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_6",
|
||||
"from": [2, 5, 2],
|
||||
"to": [4, 6, 4],
|
||||
"faces": {
|
||||
"north": { "uv": [4.25, 9.5, 4.75, 9.75], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 0.5, 10.25, 0.75], "texture": "#0" },
|
||||
"south": { "uv": [9.75, 0.75, 10.25, 1], "texture": "#0" },
|
||||
"west": { "uv": [1, 9.75, 1.5, 10], "texture": "#0" },
|
||||
"up": { "uv": [9.75, 1, 9.25, 0.5], "texture": "#0" },
|
||||
"down": { "uv": [9.75, 1, 9.25, 1.5], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_5",
|
||||
"from": [5, 5, 2],
|
||||
"to": [7, 6, 4],
|
||||
"faces": {
|
||||
"north": { "uv": [9.75, 1, 10.25, 1.25], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 1.25, 10.25, 1.5], "texture": "#0" },
|
||||
"south": { "uv": [1.5, 9.75, 2, 10], "texture": "#0" },
|
||||
"west": { "uv": [9.75, 1.5, 10.25, 1.75], "texture": "#0" },
|
||||
"up": { "uv": [9.75, 2, 9.25, 1.5], "texture": "#0" },
|
||||
"down": { "uv": [9.75, 2, 9.25, 2.5], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_4",
|
||||
"from": [8, 5, 2],
|
||||
"to": [10, 6, 4],
|
||||
"faces": {
|
||||
"north": { "uv": [9.75, 1.75, 10.25, 2], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 2, 10.25, 2.25], "texture": "#0" },
|
||||
"south": { "uv": [9.75, 2.25, 10.25, 2.5], "texture": "#0" },
|
||||
"west": { "uv": [4.25, 9.75, 4.75, 10], "texture": "#0" },
|
||||
"up": { "uv": [7.25, 9.75, 6.75, 9.25], "texture": "#0" },
|
||||
"down": { "uv": [7.75, 9.25, 7.25, 9.75], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_1",
|
||||
"from": [8, 5, 5],
|
||||
"to": [10, 6, 7],
|
||||
"faces": {
|
||||
"north": { "uv": [7.75, 9.75, 8.25, 10], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 7.75, 10.25, 8], "texture": "#0" },
|
||||
"south": { "uv": [8.25, 9.75, 8.75, 10], "texture": "#0" },
|
||||
"west": { "uv": [8.75, 9.75, 9.25, 10], "texture": "#0" },
|
||||
"up": { "uv": [0.5, 10, 0, 9.5], "texture": "#0" },
|
||||
"down": { "uv": [1, 9.5, 0.5, 10], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_2",
|
||||
"from": [2, 5, 8],
|
||||
"to": [10, 6, 11],
|
||||
"faces": {
|
||||
"north": { "uv": [9.25, 0, 11.25, 0.25], "texture": "#0" },
|
||||
"east": { "uv": [6.25, 7.5, 7, 7.75], "texture": "#0" },
|
||||
"south": { "uv": [9.25, 0.25, 11.25, 0.5], "texture": "#0" },
|
||||
"west": { "uv": [1, 9.5, 1.75, 9.75], "texture": "#0" },
|
||||
"up": { "uv": [9.75, 6, 7.75, 5.25], "texture": "#0" },
|
||||
"down": { "uv": [9.75, 6, 7.75, 6.75], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_2",
|
||||
"from": [5, 5, 5],
|
||||
"to": [7, 6, 7],
|
||||
"faces": {
|
||||
"north": { "uv": [9.75, 6.25, 10.25, 6.5], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 6.5, 10.25, 6.75], "texture": "#0" },
|
||||
"south": { "uv": [6.75, 9.75, 7.25, 10], "texture": "#0" },
|
||||
"west": { "uv": [7.25, 9.75, 7.75, 10], "texture": "#0" },
|
||||
"up": { "uv": [9.25, 9.75, 8.75, 9.25], "texture": "#0" },
|
||||
"down": { "uv": [9.75, 9.25, 9.25, 9.75], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "button_3",
|
||||
"from": [2, 5, 5],
|
||||
"to": [4, 6, 7],
|
||||
"faces": {
|
||||
"north": { "uv": [9.75, 5.25, 10.25, 5.5], "texture": "#0" },
|
||||
"east": { "uv": [9.75, 5.5, 10.25, 5.75], "texture": "#0" },
|
||||
"south": { "uv": [9.75, 5.75, 10.25, 6], "texture": "#0" },
|
||||
"west": { "uv": [9.75, 6, 10.25, 6.25], "texture": "#0" },
|
||||
"up": { "uv": [8.25, 9.75, 7.75, 9.25], "texture": "#0" },
|
||||
"down": { "uv": [8.75, 9.25, 8.25, 9.75], "texture": "#0" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "receiver",
|
||||
"from": [11, 5, 2],
|
||||
"to": [14, 7, 14],
|
||||
"faces": {
|
||||
"north": { "uv": [6.25, 7, 7, 7.5], "texture": "#0" },
|
||||
"east": { "uv": [2, 7.75, 5, 8.25], "texture": "#0" },
|
||||
"south": { "uv": [4.25, 9, 5, 9.5], "texture": "#0" },
|
||||
"west": { "uv": [7.75, 4.75, 10.75, 5.25], "texture": "#0" },
|
||||
"up": { "uv": [7.75, 7.75, 7, 4.75], "texture": "#0" },
|
||||
"down": { "uv": [6.25, 7, 5.5, 10], "texture": "#0" }
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [0, -180, 0],
|
||||
"translation": [0, 2.75, -2],
|
||||
"scale": [0.65, 0.65, 0.65]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"translation": [0, 2.75, -2],
|
||||
"scale": [0.65, 0.65, 0.65]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [5, -180, 0],
|
||||
"translation": [0, 3.75, 0],
|
||||
"scale": [0.65, 0.65, 0.65]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [5, 0, 0],
|
||||
"translation": [0, 3.75, 0],
|
||||
"scale": [0.65, 0.65, 0.65]
|
||||
},
|
||||
"ground": {
|
||||
"scale": [0.61, 0.61, 0.61]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [39, -145, 9],
|
||||
"translation": [0.5, 1.25, 0],
|
||||
"scale": [0.72, 0.69, 0.71]
|
||||
},
|
||||
"head": {
|
||||
"translation": [0, 11, 0]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [-90, 0, 0],
|
||||
"translation": [0, 0, -4.25]
|
||||
}
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"name": "paper_tray",
|
||||
"origin": [14, 1, 1],
|
||||
"color": 0,
|
||||
"children": [0, 1, 2]
|
||||
},
|
||||
{
|
||||
"name": "base",
|
||||
"origin": [14, 1, 1],
|
||||
"color": 0,
|
||||
"children": [3, 4, 5, 6, 7]
|
||||
},
|
||||
{
|
||||
"name": "buttons",
|
||||
"origin": [0, 0, 0],
|
||||
"color": 0,
|
||||
"children": [8, 9, 10, 11, 12, 13, 14]
|
||||
},
|
||||
15
|
||||
]
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "utamacraft:block/digitizer"
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 711 B |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
22
src/main/resources/data/utamacraft/recipes/digitizer.json
Normal file
22
src/main/resources/data/utamacraft/recipes/digitizer.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [" p ", "TRT", "TPT"],
|
||||
"key": {
|
||||
"p": {
|
||||
"item": "minecraft:paper"
|
||||
},
|
||||
"T": {
|
||||
"item": "utamacraft:tungsten_ingot"
|
||||
},
|
||||
"R": {
|
||||
"item": "minecraft:redstone"
|
||||
},
|
||||
"P": {
|
||||
"item": "utamacraft:pcb"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "utamacraft:digitizer",
|
||||
"count": 1
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user