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 00000000..ebd6d9d2 Binary files /dev/null and b/src/main/resources/assets/oc2/textures/items/block_operations_module.png differ diff --git a/src/main/resources/assets/oc2/textures/items/inventory_automation_module.png b/src/main/resources/assets/oc2/textures/items/inventory_automation_module.png deleted file mode 100644 index 80e27dcb..00000000 Binary files a/src/main/resources/assets/oc2/textures/items/inventory_automation_module.png and /dev/null differ 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 00000000..9d62fa12 Binary files /dev/null and b/src/main/resources/assets/oc2/textures/items/inventory_operations_module.png differ 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