From 2a055646eec734244bc98dd874fa8168bc516f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 18 Jan 2021 17:26:32 +0100 Subject: [PATCH] Added block operations module for breaking and placing blocks. --- src/main/java/li/cil/oc2/common/Config.java | 33 +++ .../java/li/cil/oc2/common/Constants.java | 13 +- .../item/BlockOperationsModuleDevice.java | 212 ++++++++++++++++++ .../item/InventoryOperationsModuleDevice.java | 6 +- .../common/bus/device/provider/Providers.java | 14 +- ... BlockOperationsModuleDeviceProvider.java} | 10 +- ...ventoryOperationsModuleDeviceProvider.java | 32 +++ .../java/li/cil/oc2/common/item/Items.java | 3 +- .../cil/oc2/common/util/FakePlayerUtils.java | 57 +++++ .../li/cil/oc2/common/util/WorldUtils.java | 3 + .../li/cil/oc2/data/ModItemModelProvider.java | 3 +- .../li/cil/oc2/data/ModItemTagsProvider.java | 3 +- src/main/resources/assets/oc2/lang/en_us.json | 15 +- ...dule.json => block_operations_module.json} | 2 +- .../item/inventory_operations_module.json | 6 + .../items/block_operations_module.png | Bin 0 -> 2262 bytes .../items/inventory_automation_module.png | Bin 1996 -> 0 bytes .../items/inventory_operations_module.png | Bin 0 -> 2346 bytes .../oc2/tags/items/devices/robot_module.json | 3 +- 19 files changed, 386 insertions(+), 29 deletions(-) create mode 100644 src/main/java/li/cil/oc2/common/bus/device/item/BlockOperationsModuleDevice.java rename src/main/java/li/cil/oc2/common/bus/device/provider/item/{InventoryAutomationRobotModuleDeviceProvider.java => BlockOperationsModuleDeviceProvider.java} (69%) create mode 100644 src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryOperationsModuleDeviceProvider.java create mode 100644 src/main/java/li/cil/oc2/common/util/FakePlayerUtils.java rename src/main/resources/assets/oc2/models/item/{inventory_automation_module.json => block_operations_module.json} (53%) create mode 100644 src/main/resources/assets/oc2/models/item/inventory_operations_module.json create mode 100644 src/main/resources/assets/oc2/textures/items/block_operations_module.png delete mode 100644 src/main/resources/assets/oc2/textures/items/inventory_automation_module.png create mode 100644 src/main/resources/assets/oc2/textures/items/inventory_operations_module.png diff --git a/src/main/java/li/cil/oc2/common/Config.java b/src/main/java/li/cil/oc2/common/Config.java index ce97475f..a78b9635 100644 --- a/src/main/java/li/cil/oc2/common/Config.java +++ b/src/main/java/li/cil/oc2/common/Config.java @@ -1,13 +1,18 @@ package li.cil.oc2.common; import li.cil.oc2.api.API; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.common.ToolType; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; import org.apache.commons.lang3.tuple.Pair; +import java.util.UUID; + @Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public final class Config { private static final CommonSettings COMMON_INSTANCE; @@ -20,6 +25,10 @@ public final class Config { public static int maxHardDriveSize = 8 * Constants.MEGABYTE; public static int maxFlashMemorySize = 4 * Constants.KILOBYTE; + public static int blockOperationsModuleToolLevel = Items.DIAMOND_PICKAXE.getHarvestLevel(new ItemStack(Items.DIAMOND_PICKAXE), ToolType.PICKAXE, null, null); + + public static UUID fakePlayerUUID = UUID.fromString("e39dd9a7-514f-4a2d-aa5e-b6030621416d"); + /////////////////////////////////////////////////////////////////// static { @@ -43,6 +52,8 @@ public final class Config { maxMemorySize = COMMON_INSTANCE.maxMemorySize.get(); maxHardDriveSize = COMMON_INSTANCE.maxHardDriveSize.get(); maxFlashMemorySize = COMMON_INSTANCE.maxFlashMemorySize.get(); + + fakePlayerUUID = UUID.fromString(COMMON_INSTANCE.fakePlayerUUID.get()); } } @@ -54,6 +65,10 @@ public final class Config { public ForgeConfigSpec.IntValue maxHardDriveSize; public ForgeConfigSpec.IntValue maxFlashMemorySize; + public ForgeConfigSpec.IntValue blockOperationsModuleToolLevel; + + public ForgeConfigSpec.ConfigValue fakePlayerUUID; + public CommonSettings(final ForgeConfigSpec.Builder builder) { builder.push("vm"); @@ -78,6 +93,24 @@ public final class Config { .defineInRange("maxFlashMemorySize", Config.maxFlashMemorySize, 0, 128 * Constants.MEGABYTE); builder.pop(); + + builder.push("gameplay"); + + blockOperationsModuleToolLevel = builder + .translation(Constants.CONFIG_BLOCK_OPERATIONS_MODULE_TOOL_LEVEL) + .comment("Tool level the block operations module operates at.") + .defineInRange("modules.block_operations.toolLevel", Config.blockOperationsModuleToolLevel, 0, Integer.MAX_VALUE); + + builder.pop(); + + builder.push("admin"); + + fakePlayerUUID = builder + .translation(Constants.CONFIG_FAKE_PLAYER_UUID) + .comment("The UUID used for the ForgeFakePlayer used by robots.") + .define("fakePlayerUUID", Config.fakePlayerUUID.toString()); + + builder.pop(); } } } diff --git a/src/main/java/li/cil/oc2/common/Constants.java b/src/main/java/li/cil/oc2/common/Constants.java index 962711e6..82da19b3 100644 --- a/src/main/java/li/cil/oc2/common/Constants.java +++ b/src/main/java/li/cil/oc2/common/Constants.java @@ -39,7 +39,8 @@ public final class Constants { public static final String REDSTONE_INTERFACE_CARD_ITEM_NAME = "redstone_interface_card"; public static final String NETWORK_INTERFACE_CARD_ITEM_NAME = "network_interface_card"; - public static final String INVENTORY_AUTOMATION_MODULE_ITEM_NAME = "inventory_automation_module"; + public static final String INVENTORY_OPERATIONS_MODULE_ITEM_NAME = "inventory_operations_module"; + public static final String BLOCK_OPERATIONS_MODULE_ITEM_NAME = "block_operations_module"; /////////////////////////////////////////////////////////////////// @@ -51,10 +52,12 @@ public final class Constants { /////////////////////////////////////////////////////////////////// - public static final String CONFIG_MAX_ALLOCATED_MEMORY = "config.oc2.maxAllocatedMemory"; - public static final String CONFIG_MAX_MEMORY_SIZE = "config.oc2.maxMemorySize"; - public static final String CONFIG_MAX_HARD_DRIVE_SIZE = "config.oc2.maxHardDriveSize"; - public static final String CONFIG_MAX_FLASH_MEMORY_SIZE = "config.oc2.maxFlashMemorySize"; + public static final String CONFIG_MAX_ALLOCATED_MEMORY = "config.oc2.vm.maxAllocatedMemory"; + public static final String CONFIG_MAX_MEMORY_SIZE = "config.oc2.vm.maxMemorySize"; + public static final String CONFIG_MAX_HARD_DRIVE_SIZE = "config.oc2.vm.maxHardDriveSize"; + public static final String CONFIG_MAX_FLASH_MEMORY_SIZE = "config.oc2.vm.maxFlashMemorySize"; + public static final String CONFIG_BLOCK_OPERATIONS_MODULE_TOOL_LEVEL = "config.oc2.modules.block_operations.toolLevel"; + public static final String CONFIG_FAKE_PLAYER_UUID = "config.oc2.admin.fakePlayerUUID"; /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/bus/device/item/BlockOperationsModuleDevice.java b/src/main/java/li/cil/oc2/common/bus/device/item/BlockOperationsModuleDevice.java new file mode 100644 index 00000000..0858445e --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/device/item/BlockOperationsModuleDevice.java @@ -0,0 +1,212 @@ +package li.cil.oc2.common.bus.device.item; + +import li.cil.oc2.api.bus.device.ItemDevice; +import li.cil.oc2.api.bus.device.object.Callback; +import li.cil.oc2.api.bus.device.object.ObjectDevice; +import li.cil.oc2.api.bus.device.object.Parameter; +import li.cil.oc2.api.bus.device.rpc.RPCDevice; +import li.cil.oc2.api.bus.device.rpc.RPCMethod; +import li.cil.oc2.api.capabilities.Robot; +import li.cil.oc2.common.Config; +import li.cil.oc2.common.bus.device.util.IdentityProxy; +import li.cil.oc2.common.util.FakePlayerUtils; +import net.minecraft.block.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.GameType; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemStackHandler; + +import javax.annotation.Nullable; +import java.util.List; + +public final class BlockOperationsModuleDevice extends IdentityProxy implements RPCDevice, ItemDevice { + public enum PlacementDirection { + FRONT, + UP, + DOWN, + } + + private final Entity entity; + private final Robot robot; + private final ObjectDevice device; + + /////////////////////////////////////////////////////////////////// + + public BlockOperationsModuleDevice(final ItemStack identity, final Entity entity, final Robot robot) { + super(identity); + this.entity = entity; + this.robot = robot; + this.device = new ObjectDevice(this, "block_operations"); + } + + /////////////////////////////////////////////////////////////////// + + @Override + public List getTypeNames() { + return device.getTypeNames(); + } + + @Override + public List getMethods() { + return device.getMethods(); + } + + @Callback + public boolean excavate(@Parameter("direction") @Nullable final PlacementDirection direction) { + final World world = entity.getEntityWorld(); + if (!(world instanceof ServerWorld)) { + return false; + } + + final int selectedSlot = robot.getSelectedSlot(); // Get once to avoid change due to threading. + final ItemStackHandler inventory = robot.getInventory(); + + final List oldItems = getItemsInRange(); + + if (!tryHarvestBlock(world, entity.getPosition().offset(getAdjustedDirection(direction)))) { + return false; + } + + final List droppedItems = getItemsInRange(); + droppedItems.removeAll(oldItems); + + for (final ItemEntity itemEntity : droppedItems) { + ItemStack stack = itemEntity.getItem(); + stack = insertStartingAt(inventory, stack, selectedSlot, false); + itemEntity.setItem(stack); + } + + return true; + } + + @Callback + public boolean place(@Parameter("direction") @Nullable final PlacementDirection direction) { + final World world = entity.getEntityWorld(); + if (!(world instanceof ServerWorld)) { + return false; + } + + final int selectedSlot = robot.getSelectedSlot(); // Get once to avoid change due to threading. + final ItemStackHandler inventory = robot.getInventory(); + + final ItemStack extracted = inventory.extractItem(selectedSlot, 1, true); + if (extracted.isEmpty() || !(extracted.getItem() instanceof BlockItem)) { + return false; + } + + final BlockPos blockPos = entity.getPosition().offset(getAdjustedDirection(direction)); + final Direction side = getAdjustedDirection(direction).getOpposite(); + final BlockRayTraceResult hit = new BlockRayTraceResult( + Vector3d.copyCentered(blockPos).add(Vector3d.copy(side.getDirectionVec()).scale(0.5)), + side, + blockPos, + false); + + final ItemStack itemStack = extracted.copy(); + final BlockItem blockItem = (BlockItem) itemStack.getItem(); + final ServerPlayerEntity player = FakePlayerUtils.getFakePlayer((ServerWorld) world, entity); + final BlockItemUseContext context = new BlockItemUseContext(player, Hand.MAIN_HAND, itemStack, hit); + + final ActionResultType result = blockItem.tryPlace(context); + if (!result.isSuccessOrConsume()) { + return false; + } + + if (itemStack.isEmpty()) { + inventory.extractItem(selectedSlot, 1, false); + } + + return true; + } + + /////////////////////////////////////////////////////////////////// + + private Direction getAdjustedDirection(@Nullable final PlacementDirection placementDirection) { + if (placementDirection == PlacementDirection.UP) { + return Direction.UP; + } else if (placementDirection == PlacementDirection.DOWN) { + return Direction.DOWN; + } else { + Direction direction = Direction.SOUTH; + final int horizontalIndex = entity.getHorizontalFacing().getHorizontalIndex(); + for (int i = 0; i < horizontalIndex; i++) { + direction = direction.rotateY(); + } + return direction; + } + } + + private List getItemsInRange() { + return entity.getEntityWorld().getEntitiesWithinAABB(ItemEntity.class, entity.getBoundingBox().grow(2)); + } + + private boolean tryHarvestBlock(final World world, final BlockPos blockPos) { + // This method is based on PlayerInteractionManager::tryHarvestBlock. Simplified for our needs. + final BlockState blockState = world.getBlockState(blockPos); + if (blockState.isAir(world, blockPos)) { + return false; + } + + final ServerPlayerEntity player = FakePlayerUtils.getFakePlayer((ServerWorld) world, entity); + final int experience = net.minecraftforge.common.ForgeHooks.onBlockBreakEvent(world, GameType.NOT_SET, player, blockPos); + if (experience == -1) { + return false; + } + + final TileEntity tileEntity = world.getTileEntity(blockPos); + final Block block = blockState.getBlock(); + final boolean isCommandBlock = block instanceof CommandBlockBlock || block instanceof StructureBlock || block instanceof JigsawBlock; + if (isCommandBlock && !player.canUseCommandBlock()) { + return false; + } + + if (player.blockActionRestricted(world, blockPos, GameType.NOT_SET)) { + return false; + } + + final boolean canHarvest = Config.blockOperationsModuleToolLevel >= blockState.getHarvestLevel(); + if (!canHarvest) { + return false; + } + + if (!ForgeEventFactory.doPlayerHarvestCheck(player, blockState, canHarvest)) { + return false; + } + + if (!blockState.removedByPlayer(world, blockPos, player, true, world.getFluidState(blockPos))) { + return false; + } + + block.onPlayerDestroy(world, blockPos, blockState); + block.harvestBlock(world, player, blockPos, blockState, tileEntity, ItemStack.EMPTY); + + return true; + } + + private ItemStack insertStartingAt(final IItemHandler handler, ItemStack stack, final int startSlot, final boolean simulate) { + for (int i = 0; i < handler.getSlots(); i++) { + final int slot = (startSlot + i) % handler.getSlots(); + stack = handler.insertItem(slot, stack, simulate); + if (stack.isEmpty()) { + return ItemStack.EMPTY; + } + } + + return stack; + } +} diff --git a/src/main/java/li/cil/oc2/common/bus/device/item/InventoryOperationsModuleDevice.java b/src/main/java/li/cil/oc2/common/bus/device/item/InventoryOperationsModuleDevice.java index d5640da8..43161817 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/item/InventoryOperationsModuleDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/item/InventoryOperationsModuleDevice.java @@ -29,18 +29,18 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class InventoryAutomationRobotModuleDevice extends IdentityProxy implements RPCDevice, ItemDevice { +public final class InventoryOperationsModuleDevice extends IdentityProxy implements RPCDevice, ItemDevice { private final Entity entity; private final Robot robot; private final ObjectDevice device; /////////////////////////////////////////////////////////////////// - public InventoryAutomationRobotModuleDevice(final ItemStack identity, final Entity entity, final Robot robot) { + public InventoryOperationsModuleDevice(final ItemStack identity, final Entity entity, final Robot robot) { super(identity); this.entity = entity; this.robot = robot; - this.device = new ObjectDevice(this, "inventory_automation"); + this.device = new ObjectDevice(this, "inventory_operations"); } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/bus/device/provider/Providers.java b/src/main/java/li/cil/oc2/common/bus/device/provider/Providers.java index e83cf22b..361da512 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/provider/Providers.java +++ b/src/main/java/li/cil/oc2/common/bus/device/provider/Providers.java @@ -3,6 +3,7 @@ package li.cil.oc2.common.bus.device.provider; import li.cil.oc2.api.API; import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider; import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider; +import li.cil.oc2.common.Constants; import li.cil.oc2.common.bus.device.provider.block.*; import li.cil.oc2.common.bus.device.provider.item.*; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -31,13 +32,14 @@ public final class Providers { BLOCK_DEVICE_PROVIDERS.register("fluid_handler", FluidHandlerBlockDeviceProvider::new); BLOCK_DEVICE_PROVIDERS.register("item_handler", ItemHandlerBlockDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("item_memory", MemoryItemDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("item_hard_drive", HardDriveItemDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("item_flash_memory", FlashMemoryItemDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("item_redstone_interface_card", RedstoneInterfaceCardItemDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("item_network_interface_card", NetworkInterfaceCardItemDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.MEMORY_ITEM_NAME, MemoryItemDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.HARD_DRIVE_ITEM_NAME, HardDriveItemDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.FLASH_MEMORY_ITEM_NAME, FlashMemoryItemDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.REDSTONE_INTERFACE_CARD_ITEM_NAME, RedstoneInterfaceCardItemDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.NETWORK_INTERFACE_CARD_ITEM_NAME, NetworkInterfaceCardItemDeviceProvider::new); - ITEM_DEVICE_PROVIDERS.register("inventory_automation_module", InventoryAutomationRobotModuleDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.INVENTORY_OPERATIONS_MODULE_ITEM_NAME, InventoryOperationsModuleDeviceProvider::new); + ITEM_DEVICE_PROVIDERS.register(Constants.BLOCK_OPERATIONS_MODULE_ITEM_NAME, BlockOperationsModuleDeviceProvider::new); BLOCK_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); ITEM_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); diff --git a/src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryAutomationRobotModuleDeviceProvider.java b/src/main/java/li/cil/oc2/common/bus/device/provider/item/BlockOperationsModuleDeviceProvider.java similarity index 69% rename from src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryAutomationRobotModuleDeviceProvider.java rename to src/main/java/li/cil/oc2/common/bus/device/provider/item/BlockOperationsModuleDeviceProvider.java index 22176e64..df97f2ad 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryAutomationRobotModuleDeviceProvider.java +++ b/src/main/java/li/cil/oc2/common/bus/device/provider/item/BlockOperationsModuleDeviceProvider.java @@ -4,16 +4,16 @@ import li.cil.oc2.api.bus.device.DeviceType; import li.cil.oc2.api.bus.device.DeviceTypes; import li.cil.oc2.api.bus.device.ItemDevice; import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery; -import li.cil.oc2.common.bus.device.item.InventoryAutomationRobotModuleDevice; +import li.cil.oc2.common.bus.device.item.BlockOperationsModuleDevice; import li.cil.oc2.common.bus.device.provider.util.AbstractItemDeviceProvider; import li.cil.oc2.common.capabilities.Capabilities; import li.cil.oc2.common.item.Items; import java.util.Optional; -public final class InventoryAutomationRobotModuleDeviceProvider extends AbstractItemDeviceProvider { - public InventoryAutomationRobotModuleDeviceProvider() { - super(Items.INVENTORY_AUTOMATION_MODULE); +public final class BlockOperationsModuleDeviceProvider extends AbstractItemDeviceProvider { + public BlockOperationsModuleDeviceProvider() { + super(Items.BLOCK_OPERATIONS_MODULE); } /////////////////////////////////////////////////////////////////// @@ -27,6 +27,6 @@ public final class InventoryAutomationRobotModuleDeviceProvider extends Abstract protected Optional getItemDevice(final ItemDeviceQuery query) { return query.getContainerEntity().flatMap(entity -> entity.getCapability(Capabilities.ROBOT).map(robot -> - new InventoryAutomationRobotModuleDevice(query.getItemStack(), entity, robot))); + new BlockOperationsModuleDevice(query.getItemStack(), entity, robot))); } } diff --git a/src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryOperationsModuleDeviceProvider.java b/src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryOperationsModuleDeviceProvider.java new file mode 100644 index 00000000..dcf02809 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/device/provider/item/InventoryOperationsModuleDeviceProvider.java @@ -0,0 +1,32 @@ +package li.cil.oc2.common.bus.device.provider.item; + +import li.cil.oc2.api.bus.device.DeviceType; +import li.cil.oc2.api.bus.device.DeviceTypes; +import li.cil.oc2.api.bus.device.ItemDevice; +import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery; +import li.cil.oc2.common.bus.device.item.InventoryOperationsModuleDevice; +import li.cil.oc2.common.bus.device.provider.util.AbstractItemDeviceProvider; +import li.cil.oc2.common.capabilities.Capabilities; +import li.cil.oc2.common.item.Items; + +import java.util.Optional; + +public final class InventoryOperationsModuleDeviceProvider extends AbstractItemDeviceProvider { + public InventoryOperationsModuleDeviceProvider() { + super(Items.INVENTORY_OPERATIONS_MODULE); + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected Optional getItemDeviceType(final ItemDeviceQuery query) { + return Optional.of(DeviceTypes.ROBOT_MODULE); + } + + @Override + protected Optional getItemDevice(final ItemDeviceQuery query) { + return query.getContainerEntity().flatMap(entity -> + entity.getCapability(Capabilities.ROBOT).map(robot -> + new InventoryOperationsModuleDevice(query.getItemStack(), entity, robot))); + } +} diff --git a/src/main/java/li/cil/oc2/common/item/Items.java b/src/main/java/li/cil/oc2/common/item/Items.java index b733f3cf..96124c44 100644 --- a/src/main/java/li/cil/oc2/common/item/Items.java +++ b/src/main/java/li/cil/oc2/common/item/Items.java @@ -39,7 +39,8 @@ public final class Items { public static final RegistryObject REDSTONE_INTERFACE_CARD_ITEM = register(Constants.REDSTONE_INTERFACE_CARD_ITEM_NAME); public static final RegistryObject NETWORK_INTERFACE_CARD_ITEM = register(Constants.NETWORK_INTERFACE_CARD_ITEM_NAME); - public static final RegistryObject INVENTORY_AUTOMATION_MODULE = register(Constants.INVENTORY_AUTOMATION_MODULE_ITEM_NAME); + public static final RegistryObject INVENTORY_OPERATIONS_MODULE = register(Constants.INVENTORY_OPERATIONS_MODULE_ITEM_NAME); + public static final RegistryObject BLOCK_OPERATIONS_MODULE = register(Constants.BLOCK_OPERATIONS_MODULE_ITEM_NAME); /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/util/FakePlayerUtils.java b/src/main/java/li/cil/oc2/common/util/FakePlayerUtils.java new file mode 100644 index 00000000..649f4c33 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/util/FakePlayerUtils.java @@ -0,0 +1,57 @@ +package li.cil.oc2.common.util; + +import com.mojang.authlib.GameProfile; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import li.cil.oc2.api.API; +import li.cil.oc2.common.Config; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.IPacket; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.PacketDirection; +import net.minecraft.network.play.ServerPlayNetHandler; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.FakePlayerFactory; +import org.jetbrains.annotations.Nullable; + +public final class FakePlayerUtils { + private static final String FAKE_PLAYER_NAME = "[" + API.MOD_ID + "]"; + + /////////////////////////////////////////////////////////////////// + + public static ServerPlayerEntity getFakePlayer(final ServerWorld world, final Entity entity) { + final ServerPlayerEntity player = getFakePlayer(world); + player.copyLocationAndAnglesFrom(entity); + player.prevRotationPitch = player.rotationPitch; + player.prevRotationYaw = player.rotationYaw; + player.rotationYawHead = player.rotationYaw; + player.prevRotationYawHead = player.rotationYawHead; + return player; + } + + public static ServerPlayerEntity getFakePlayer(final ServerWorld world) { + final FakePlayer player = FakePlayerFactory.get(world, new GameProfile(Config.fakePlayerUUID, FAKE_PLAYER_NAME)); + + // We need to give our fake player a fake network handler because some events we want + // to use the fake player with will unconditionally access this field. + if (player.connection == null) { + player.connection = new FakeServerPlayNetHandler(player); + } + + return player; + } + + /////////////////////////////////////////////////////////////////// + + private static class FakeServerPlayNetHandler extends ServerPlayNetHandler { + public FakeServerPlayNetHandler(final FakePlayer fakePlayer) { + super(fakePlayer.server, new NetworkManager(PacketDirection.CLIENTBOUND), fakePlayer); + } + + @Override + public void sendPacket(final IPacket packetIn, @Nullable final GenericFutureListener> futureListeners) { + } + } +} diff --git a/src/main/java/li/cil/oc2/common/util/WorldUtils.java b/src/main/java/li/cil/oc2/common/util/WorldUtils.java index 6d662a3b..5496cfa6 100644 --- a/src/main/java/li/cil/oc2/common/util/WorldUtils.java +++ b/src/main/java/li/cil/oc2/common/util/WorldUtils.java @@ -2,6 +2,8 @@ package li.cil.oc2.common.util; import net.minecraft.block.Block; import net.minecraft.block.SoundType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; @@ -11,6 +13,7 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.IWorld; import javax.annotation.Nullable; +import java.util.List; import java.util.function.Function; public final class WorldUtils { diff --git a/src/main/java/li/cil/oc2/data/ModItemModelProvider.java b/src/main/java/li/cil/oc2/data/ModItemModelProvider.java index 1ea8b048..03dae8a3 100644 --- a/src/main/java/li/cil/oc2/data/ModItemModelProvider.java +++ b/src/main/java/li/cil/oc2/data/ModItemModelProvider.java @@ -45,7 +45,8 @@ public final class ModItemModelProvider extends ItemModelProvider { simple(Items.REDSTONE_INTERFACE_CARD_ITEM, "items/redstone_interface_card"); simple(Items.NETWORK_INTERFACE_CARD_ITEM, "items/network_interface_card"); - simple(Items.INVENTORY_AUTOMATION_MODULE, "items/inventory_automation_module"); + simple(Items.INVENTORY_OPERATIONS_MODULE, "items/inventory_operations_module"); + simple(Items.BLOCK_OPERATIONS_MODULE, "items/block_operations_module"); withExistingParent(Constants.ROBOT_ENTITY_NAME, "template_shulker_box"); } diff --git a/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java b/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java index 790b7ed2..82379fa1 100644 --- a/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java +++ b/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java @@ -42,7 +42,8 @@ public final class ModItemTagsProvider extends ItemTagsProvider { Items.NETWORK_INTERFACE_CARD_ITEM.get() ); getOrCreateBuilder(DEVICES_ROBOT_MODULE).add( - Items.INVENTORY_AUTOMATION_MODULE.get() + Items.INVENTORY_OPERATIONS_MODULE.get(), + Items.BLOCK_OPERATIONS_MODULE.get() ); getOrCreateBuilder(WRENCHES).add(Items.WRENCH_ITEM.get()); } diff --git a/src/main/resources/assets/oc2/lang/en_us.json b/src/main/resources/assets/oc2/lang/en_us.json index 102147bb..59389268 100644 --- a/src/main/resources/assets/oc2/lang/en_us.json +++ b/src/main/resources/assets/oc2/lang/en_us.json @@ -21,15 +21,20 @@ "item.oc2.network_interface_card": "Network Interface Card", "item.oc2.robot": "Robot", "item.oc2.robot.desc": "Use a Scrench or compatible wrench to add and remove components.", - "item.oc2.inventory_automation_module": "Inventory Automation Module", + "item.oc2.inventory_operations_module": "Inventory Operations Module", + "item.oc2.inventory_operations_module.desc": "Enables robots to move items in their inventory, including to and from adjacent inventories.", + "item.oc2.block_operations_module": "Block Operations Module", + "item.oc2.block_operations_module.desc": "Enables robots to break and place blocks.", "entity.oc2.robot": "Robot", - "config.oc2.maxAllocatedMemory": "Maximum allocated memory", - "config.oc2.maxMemorySize:": "Maximum memory device size", - "config.oc2.maxHardDriveSize": "Maximum hard drive device size", - "config.oc2.maxFlashMemorySize:": "Maximum flash memory device size", + "config.oc2.vm.maxAllocatedMemory": "Maximum allocated memory", + "config.oc2.vm.maxMemorySize:": "Maximum memory device size", + "config.oc2.vm.maxHardDriveSize": "Maximum hard drive device size", + "config.oc2.vm.maxFlashMemorySize:": "Maximum flash memory device size", "config.oc2.computerEnergyPerTick": "Energy/tick used by computers", + "config.oc2.modules.block_operations.toolLevel": "Block operations module tool level", + "config.oc2.admin.fakePlayerUUID": "Fake Player UUID", "gui.oc2.computer.boot_error.unknown": "Unknown Error", "gui.oc2.computer.boot_error.no_memory": "Insufficient Memory", diff --git a/src/main/resources/assets/oc2/models/item/inventory_automation_module.json b/src/main/resources/assets/oc2/models/item/block_operations_module.json similarity index 53% rename from src/main/resources/assets/oc2/models/item/inventory_automation_module.json rename to src/main/resources/assets/oc2/models/item/block_operations_module.json index 6f68c9a0..372625c5 100644 --- a/src/main/resources/assets/oc2/models/item/inventory_automation_module.json +++ b/src/main/resources/assets/oc2/models/item/block_operations_module.json @@ -1,6 +1,6 @@ { "parent": "minecraft:item/handheld", "textures": { - "layer0": "oc2:items/inventory_automation_module" + "layer0": "oc2:items/block_operations_module" } } \ No newline at end of file diff --git a/src/main/resources/assets/oc2/models/item/inventory_operations_module.json b/src/main/resources/assets/oc2/models/item/inventory_operations_module.json new file mode 100644 index 00000000..1a452801 --- /dev/null +++ b/src/main/resources/assets/oc2/models/item/inventory_operations_module.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "oc2:items/inventory_operations_module" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/oc2/textures/items/block_operations_module.png b/src/main/resources/assets/oc2/textures/items/block_operations_module.png new file mode 100644 index 0000000000000000000000000000000000000000..ebd6d9d2b26e57468eb2acdddc03c9d93f9c46cc GIT binary patch literal 2262 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 Idez2%0l9DFivR!s diff --git a/src/main/resources/assets/oc2/textures/items/inventory_operations_module.png b/src/main/resources/assets/oc2/textures/items/inventory_operations_module.png new file mode 100644 index 0000000000000000000000000000000000000000..9d62fa12edb5d6202280c44de3e51a2edf35de37 GIT binary patch literal 2346 zcmai0dsGu=79YBb0$N2a#nppxpwtz}E3_zh9GFVE&IG5)wD1sCf6^V=FVusB@q)Md{k;o94EDUIbam8jHvxb?uK!L)|p(Qz-r7S$f zm_-67mdzCKY8VE%XpEevjQ7~h+}QO&A`k&Vq+$tjzdC`BhhiyUX;&Zwj*v8IBF#Jp z^raK@Nh|djdI5Qe-jd7k442DT#=T4kX&ipY5TyIjCRWVyC}q9=_tj0N3D@BGxI&P) zu_8=}>8=AVz1Tt`29je6Se%S21nCHLWlqQ=sxx6ZWD;r4;d9lnH2eWz1w}k~E)dZL zLgkj5Dd1Xm&m`j>riLSApl5`7y4bojAZc9>qOy_ct*cwKVMy!D5;V2VB6woB6LWHTIsWAeVbeBPeOrTeR@br2#f#P_E zExylV8u^!r9$mvH61iFm#c-j-YS_X8k2p!VatLB~qa0)8i!hdq$pPJ@hGUFI3N%Bp zC`A|(kyIQhR!lS~$|V8W;Ia%;_7@8>n%o)uQu7oNYo_RhI0C#9=B zp8x#X`&;vr-Co^0_c!GA*H}JXUmfbx=yf}fjp<&RR_iy|-lMf0)OWvvVGSQ(G6oup%LR5=&7<4wonYELBWG2a?xUcNc-?msgwb-&S-bHsYJ+-X|W zGyR9Ye@ncNXO)(nOj1UdPSq^fdikWi53)ye4}Y*buBbcP2MuVi@EhDn%Rc-y^0Q5` zxPO=VU2MGNl&`mb$VD%S;5UG>3ju`@%{9ZyY)iCFFQyYWJc-)pb0THP|O zVj$w;du2Ypd@AgpxMhjH>y=YSPxs)#Z+{{`7k9R;ZAVD!f7tH%r@735_{x*VM@law zCVF`j^8=4m?A!nmXM>&Z`EIMjDyHGdtzF+Q{%)|jYfwBm@Y9oT7ea@A?X2JSwJ%g! zd-aK#&ei{VmFjPn#fAhq@|z{%dDT-E4wY2C@xpS?&D%Sh&KD2am+d`#X9k(rr-O!V zK{a!_E*_X#vAyTZUFa=ja_=-xs;X2yG!k{^t+ERT%-QzfO`GGQ=COwSiXD)gy4HW9 zu5jt(L$#U(ugMNK(*fqWs?r{hfXnN=eq;i^ytLIB+v_~Kcnv;f{<)>l?(KZdVlp&h zd!52k9;IGkFj@WU_vKys(bFE>lA5%KdIs_z@}1EvldJHjdg|6S9Deb|BaNBNwd3kj z^yW3s>OOo+tQIJ1*0Ci+3p@E5<9}a*{w968DfAy%SI*F#-1V>Z0terMJN z{c?Uw%c}I}r;6%I0(w0hHo38V&Cbi;PnKp{*2r(12-?f%b@Y3t&foj;pl<&!9*)0v z)GrG}lPjv{*li7?eGQS@4n|o1P+Qda%$_RW#D#A@_oubh@P;QAe$i>LmnUXU8U6U? Zym$7EUQjF=IU)ST(ZwZeKZ?yN`ya$*Z65#t literal 0 HcmV?d00001 diff --git a/src/main/resources/data/oc2/tags/items/devices/robot_module.json b/src/main/resources/data/oc2/tags/items/devices/robot_module.json index 6d9dd4d2..c7a51a93 100644 --- a/src/main/resources/data/oc2/tags/items/devices/robot_module.json +++ b/src/main/resources/data/oc2/tags/items/devices/robot_module.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "oc2:inventory_automation_module" + "oc2:inventory_operations_module", + "oc2:block_operations_module" ] } \ No newline at end of file