Make robots drop self and show configuration in tooltip.

This commit is contained in:
Florian Nücke
2021-01-15 15:46:19 +01:00
parent af0bd5fc60
commit 2e8cca3b0e
7 changed files with 145 additions and 77 deletions

View File

@@ -8,8 +8,8 @@ import li.cil.oc2.common.integration.Wrenches;
import li.cil.oc2.common.item.Items;
import li.cil.oc2.common.tileentity.ComputerTileEntity;
import li.cil.oc2.common.tileentity.TileEntities;
import li.cil.oc2.common.util.TooltipUtils;
import li.cil.oc2.common.util.VoxelShapeUtils;
import li.cil.oc2.common.vm.AbstractVirtualMachineItemStackHandlers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HorizontalBlock;
@@ -76,7 +76,7 @@ public final class ComputerBlock extends HorizontalBlock {
@Override
public void addInformation(final ItemStack stack, @Nullable final IBlockReader world, final List<ITextComponent> tooltip, final ITooltipFlag advanced) {
super.addInformation(stack, world, tooltip, advanced);
AbstractVirtualMachineItemStackHandlers.addInformation(stack, tooltip);
TooltipUtils.addTileEntityInventoryInformation(stack, tooltip);
}
@Override

View File

@@ -15,9 +15,11 @@ import li.cil.oc2.common.bus.device.util.ItemDeviceInfo;
import li.cil.oc2.common.container.RobotContainer;
import li.cil.oc2.common.entity.robot.*;
import li.cil.oc2.common.integration.Wrenches;
import li.cil.oc2.common.item.Items;
import li.cil.oc2.common.network.Network;
import li.cil.oc2.common.network.message.*;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.ItemStackUtils;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.oc2.common.util.NBTUtils;
import li.cil.oc2.common.util.WorldUtils;
@@ -154,6 +156,19 @@ public final class RobotEntity extends Entity {
state.stop();
}
public void dropSelf() {
if (!isAlive()) {
return;
}
final ItemStack stack = new ItemStack(Items.ROBOT_ITEM.get());
exportToItemStack(stack);
entityDropItem(stack);
remove();
WorldUtils.playSound(world, getPosition(), SoundType.METAL, SoundType::getBreakSound);
}
@Override
public void tick() {
final World world = getEntityWorld();
@@ -199,10 +214,11 @@ public final class RobotEntity extends Entity {
final TileEntity tileEntity = blockState.hasTileEntity() ? world.getTileEntity(mutablePosition) : null;
final LootContext.Builder builder = new LootContext.Builder((ServerWorld) world)
.withRandom(world.rand)
.withParameter(LootParameters.field_237457_g_, Vector3d.copyCentered(mutablePosition))
.withParameter(LootParameters.THIS_ENTITY, this)
.withParameter(LootParameters.field_237457_g_, getPositionVec())
.withParameter(LootParameters.TOOL, ItemStack.EMPTY)
.withNullableParameter(LootParameters.BLOCK_ENTITY, tileEntity)
.withNullableParameter(LootParameters.THIS_ENTITY, this);
.withParameter(LootParameters.BLOCK_STATE, blockState)
.withNullableParameter(LootParameters.BLOCK_ENTITY, tileEntity);
final List<ItemStack> drops = blockState.getDrops(builder);
world.setBlockState(mutablePosition, Blocks.AIR.getDefaultState(), 3);
for (final ItemStack drop : drops) {
@@ -213,22 +229,13 @@ public final class RobotEntity extends Entity {
}
}
private CubeCoordinateIterator getBlockPosIterator() {
final AxisAlignedBB bounds = getBoundingBox();
return new CubeCoordinateIterator(
MathHelper.floor(bounds.minX), MathHelper.floor(bounds.minY), MathHelper.floor(bounds.minZ),
MathHelper.floor(bounds.maxX), MathHelper.floor(bounds.maxY), MathHelper.floor(bounds.maxZ)
);
}
@Override
public ActionResultType processInitialInteract(final PlayerEntity player, final Hand hand) {
final ItemStack stack = player.getHeldItem(hand);
if (Wrenches.isWrench(stack)) {
if (!world.isRemote() && player instanceof ServerPlayerEntity) {
if (player.isSneaking()) {
remove();
WorldUtils.playSound(world, getPosition(), SoundType.METAL, SoundType::getBreakSound);
dropSelf();
} else {
openContainerScreen(player);
}
@@ -285,6 +292,17 @@ public final class RobotEntity extends Entity {
return false;
}
public void exportToItemStack(final ItemStack stack) {
items.serialize(ItemStackUtils.getOrCreateEntityInventoryTag(stack));
}
public void importFromItemStack(final ItemStack stack) {
final CompoundNBT inventoryTag = ItemStackUtils.getEntityInventoryTag(stack);
if (inventoryTag != null) {
items.deserialize(inventoryTag);
}
}
///////////////////////////////////////////////////////////////////
@Override
@@ -393,6 +411,14 @@ public final class RobotEntity extends Entity {
}, b -> b.writeVarInt(getEntityId()));
}
private CubeCoordinateIterator getBlockPosIterator() {
final AxisAlignedBB bounds = getBoundingBox();
return new CubeCoordinateIterator(
MathHelper.floor(bounds.minX), MathHelper.floor(bounds.minY), MathHelper.floor(bounds.minZ),
MathHelper.floor(bounds.maxX), MathHelper.floor(bounds.maxY), MathHelper.floor(bounds.maxZ)
);
}
private static float lerpClamped(final float from, final float to, final float delta) {
if (from < to) {
return Math.min(from + delta, to);

View File

@@ -3,23 +3,36 @@ package li.cil.oc2.common.item;
import li.cil.oc2.common.entity.Entities;
import li.cil.oc2.common.entity.RobotEntity;
import li.cil.oc2.common.entity.robot.RobotActions;
import li.cil.oc2.common.util.TooltipUtils;
import li.cil.oc2.common.util.WorldUtils;
import net.minecraft.block.SoundType;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.stats.Stats;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public final class RobotItem extends Item {
public RobotItem(final Properties properties) {
super(properties);
}
@Override
public void addInformation(final ItemStack stack, @Nullable final World world, final List<ITextComponent> tooltip, final ITooltipFlag flags) {
super.addInformation(stack, world, tooltip, flags);
TooltipUtils.addEntityInventoryInformation(stack, tooltip);
}
@Override
public ActionResultType onItemUse(final ItemUseContext context) {
final World world = context.getWorld();
@@ -39,11 +52,13 @@ public final class RobotItem extends Item {
return super.onItemUse(context);
}
RobotActions.initializeData(robot);
if (!world.isRemote()) {
WorldUtils.playSound(world, new BlockPos(position), SoundType.METAL, SoundType::getPlaceSound);
RobotActions.initializeData(robot);
robot.importFromItemStack(context.getItem());
world.addEntity(robot);
WorldUtils.playSound(world, new BlockPos(position), SoundType.METAL, SoundType::getPlaceSound);
if (!context.getPlayer().isCreative()) {
context.getItem().shrink(1);
}

View File

@@ -20,6 +20,7 @@ import li.cil.oc2.common.network.message.ComputerRunStateMessage;
import li.cil.oc2.common.network.message.ComputerTerminalOutputMessage;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.HorizontalBlockUtils;
import li.cil.oc2.common.util.ItemStackUtils;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.oc2.common.vm.*;
import net.minecraft.block.BlockState;
@@ -219,7 +220,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
}
public void exportToItemStack(final ItemStack stack) {
items.exportToItemStack(stack);
items.serialize(ItemStackUtils.getOrCreateTileEntityInventoryTag(stack));
}
///////////////////////////////////////////////////////////////////

View File

@@ -13,8 +13,8 @@ import javax.annotation.Nullable;
import java.util.Optional;
import java.util.Random;
import static li.cil.oc2.common.Constants.INVENTORY_TAG_NAME;
import static li.cil.oc2.common.Constants.BLOCK_ENTITY_TAG_NAME_IN_ITEM;
import static li.cil.oc2.common.Constants.INVENTORY_TAG_NAME;
public final class ItemStackUtils {
private static final String MOD_TAG_NAME = API.MOD_ID;
@@ -36,6 +36,22 @@ public final class ItemStackUtils {
return stack.getOrCreateChildTag(MOD_TAG_NAME);
}
@Nullable
public static CompoundNBT getInventoryTag(@Nullable final CompoundNBT tag) {
return tag != null && tag.contains(INVENTORY_TAG_NAME, NBTTagIds.TAG_COMPOUND)
? tag.getCompound(INVENTORY_TAG_NAME) : null;
}
public static CompoundNBT getOrCreateInventoryTag(final CompoundNBT tag) {
if (tag.contains(INVENTORY_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
return tag.getCompound(INVENTORY_TAG_NAME);
}
final CompoundNBT inventoryTag = new CompoundNBT();
tag.put(INVENTORY_TAG_NAME, inventoryTag);
return inventoryTag;
}
@Nullable
public static CompoundNBT getTileEntityTag(final ItemStack stack) {
return stack.getChildTag(BLOCK_ENTITY_TAG_NAME_IN_ITEM);
@@ -47,22 +63,22 @@ public final class ItemStackUtils {
@Nullable
public static CompoundNBT getTileEntityInventoryTag(final ItemStack stack) {
final CompoundNBT tag = getTileEntityTag(stack);
return tag != null && tag.contains(INVENTORY_TAG_NAME, NBTTagIds.TAG_COMPOUND)
? tag.getCompound(INVENTORY_TAG_NAME) : null;
return getInventoryTag(getTileEntityTag(stack));
}
@Nullable
public static CompoundNBT getOrCreateTileEntityInventoryTag(final ItemStack stack) {
final CompoundNBT tag = getOrCreateTileEntityTag(stack);
if (tag.contains(INVENTORY_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
return tag.getCompound(INVENTORY_TAG_NAME);
}
return getOrCreateInventoryTag(getOrCreateTileEntityTag(stack));
}
final CompoundNBT inventoryNbt = new CompoundNBT();
tag.put(INVENTORY_TAG_NAME, inventoryNbt);
@Nullable
public static CompoundNBT getEntityInventoryTag(final ItemStack stack) {
return getInventoryTag(getModDataTag(stack));
}
return inventoryNbt;
@Nullable
public static CompoundNBT getOrCreateEntityInventoryTag(final ItemStack stack) {
return getOrCreateInventoryTag(getOrCreateModDataTag(stack));
}
public static Optional<ItemEntity> spawnAsEntity(final World world, final BlockPos pos, final ItemStack stack) {

View File

@@ -2,6 +2,7 @@ package li.cil.oc2.common.util;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import li.cil.oc2.api.bus.device.DeviceType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
@@ -9,7 +10,10 @@ import net.minecraft.util.text.Color;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -17,36 +21,63 @@ public final class TooltipUtils {
private static final ThreadLocal<List<ItemStack>> ITEM_STACKS = ThreadLocal.withInitial(ArrayList::new);
private static final ThreadLocal<IntList> ITEM_STACKS_SIZES = ThreadLocal.withInitial(IntArrayList::new);
public static void addInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip) {
addInventoryInformation(stack, tooltip, new String[0]);
public static void addTileEntityInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip) {
addInventoryInformation(ItemStackUtils.getTileEntityInventoryTag(stack), tooltip);
}
public static void addInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip, final String... itemHandlerTags) {
final CompoundNBT itemHandlerNbt = ItemStackUtils.getTileEntityInventoryTag(stack);
if (itemHandlerNbt != null) {
final List<ItemStack> itemStacks = ITEM_STACKS.get();
itemStacks.clear();
final IntList itemStackSizes = ITEM_STACKS_SIZES.get();
itemStackSizes.clear();
public static void addTileEntityInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip, final String... subInventoryNames) {
addInventoryInformation(ItemStackUtils.getTileEntityInventoryTag(stack), tooltip, subInventoryNames);
}
collectItemStacks(itemHandlerNbt, itemStacks, itemStackSizes);
public static void addEntityInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip) {
addInventoryInformation(ItemStackUtils.getEntityInventoryTag(stack), tooltip);
}
for (final String itemHandlerTagName : itemHandlerTags) {
if (itemHandlerNbt.contains(itemHandlerTagName, NBTTagIds.TAG_COMPOUND)) {
collectItemStacks(itemHandlerNbt.getCompound(itemHandlerTagName), itemStacks, itemStackSizes);
}
public static void addEntityInventoryInformation(final ItemStack stack, final List<ITextComponent> tooltip, final String... subInventoryNames) {
addInventoryInformation(ItemStackUtils.getEntityInventoryTag(stack), tooltip, subInventoryNames);
}
public static void addInventoryInformation(@Nullable final CompoundNBT inventoryTag, final List<ITextComponent> tooltip) {
addInventoryInformation(inventoryTag, tooltip, getDeviceTypeNames());
}
public static void addInventoryInformation(@Nullable final CompoundNBT inventoryTag, final List<ITextComponent> tooltip, final String... subInventoryNames) {
if (inventoryTag == null) {
return;
}
final List<ItemStack> itemStacks = ITEM_STACKS.get();
itemStacks.clear();
final IntList itemStackSizes = ITEM_STACKS_SIZES.get();
itemStackSizes.clear();
collectItemStacks(inventoryTag, itemStacks, itemStackSizes);
for (final String subInventoryName : subInventoryNames) {
if (inventoryTag.contains(subInventoryName, NBTTagIds.TAG_COMPOUND)) {
collectItemStacks(inventoryTag.getCompound(subInventoryName), itemStacks, itemStackSizes);
}
}
for (int i = 0; i < itemStacks.size(); i++) {
final ItemStack itemStack = itemStacks.get(i);
tooltip.add(new StringTextComponent("")
.append(itemStack.getDisplayName())
.modifyStyle(style -> style.setColor(Color.fromTextFormatting(TextFormatting.GRAY)))
.append(new StringTextComponent(" x")
.appendString(String.valueOf(itemStackSizes.getInt(i)))
.modifyStyle(style -> style.setColor(Color.fromTextFormatting(TextFormatting.DARK_GRAY))))
);
}
for (int i = 0; i < itemStacks.size(); i++) {
final ItemStack itemStack = itemStacks.get(i);
tooltip.add(new StringTextComponent("")
.append(itemStack.getDisplayName())
.modifyStyle(style -> style.setColor(Color.fromTextFormatting(TextFormatting.GRAY)))
.append(new StringTextComponent(" x")
.appendString(String.valueOf(itemStackSizes.getInt(i)))
.modifyStyle(style -> style.setColor(Color.fromTextFormatting(TextFormatting.DARK_GRAY))))
);
}
}
private static String[] getDeviceTypeNames() {
final ForgeRegistry<DeviceType> registry = RegistryManager.ACTIVE.getRegistry(DeviceType.REGISTRY);
if (registry != null) {
return registry.getValues().stream().map(deviceType ->
deviceType.getRegistryName().toString()).toArray(String[]::new);
} else {
return new String[0];
}
}

View File

@@ -8,17 +8,12 @@ import li.cil.oc2.common.bus.AbstractDeviceBusElement;
import li.cil.oc2.common.bus.device.util.ItemDeviceInfo;
import li.cil.oc2.common.container.DeviceItemStackHandler;
import li.cil.oc2.common.container.TypedDeviceItemStackHandler;
import li.cil.oc2.common.util.ItemStackUtils;
import li.cil.oc2.common.util.TooltipUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
import java.util.*;
import java.util.function.Function;
@@ -46,17 +41,6 @@ public abstract class AbstractVirtualMachineItemStackHandlers implements Virtual
///////////////////////////////////////////////////////////////////
public static void addInformation(final ItemStack stack, final List<ITextComponent> tooltip) {
final ForgeRegistry<DeviceType> registry = RegistryManager.ACTIVE.getRegistry(DeviceType.REGISTRY);
if (registry != null) {
TooltipUtils.addInventoryInformation(stack, tooltip,
registry.getValues().stream().map(deviceType ->
deviceType.getRegistryName().toString()).toArray(String[]::new));
}
}
///////////////////////////////////////////////////////////////////
public final DeviceBusElement busElement = new BusElement();
// NB: linked hash map such that order of parameters in constructor is retained.
@@ -128,19 +112,14 @@ public abstract class AbstractVirtualMachineItemStackHandlers implements Virtual
}
}
public void exportToItemStack(final ItemStack stack) {
final CompoundNBT tag = ItemStackUtils.getOrCreateTileEntityInventoryTag(stack);
public void serialize(final CompoundNBT tag) {
itemHandlers.forEach((deviceType, handler) ->
tag.put(deviceType.getRegistryName().toString(), handler.serializeNBT()));
}
public CompoundNBT serialize() {
final CompoundNBT tag = new CompoundNBT();
itemHandlers.forEach((deviceType, handler) ->
tag.put(deviceType.getRegistryName().toString(), handler.serializeNBT()));
serialize(tag);
return tag;
}