From dbbbe96df27be34584dacbd0991e96fa71d948f9 Mon Sep 17 00:00:00 2001 From: Merith Date: Fri, 26 Nov 2021 20:54:21 +0000 Subject: [PATCH 1/5] attempt to use mojmap currently does not compile --- build.gradle | 9 +- gradle.properties | 2 +- .../dan200/computercraft/ComputerCraft.java | 38 ++-- .../computercraft/ComputerCraftAPIImpl.java | 25 ++- .../computercraft/api/ComputerCraftAPI.java | 29 ++- .../computercraft/api/IUpgradeBase.java | 13 +- .../api/client/TransformedModel.java | 55 +++-- .../computercraft/api/filesystem/IMount.java | 7 +- .../api/filesystem/IWritableMount.java | 7 +- .../computercraft/api/lua/GenericSource.java | 5 +- .../computercraft/api/media/IMedia.java | 13 +- .../api/media/IMediaProvider.java | 3 +- .../api/network/IPacketReceiver.java | 9 +- .../api/network/IPacketSender.java | 9 +- .../api/peripheral/IComputerAccess.java | 11 +- .../api/peripheral/IPeripheralProvider.java | 11 +- .../api/peripheral/IPeripheralTile.java | 11 +- .../api/pocket/AbstractPocketUpgrade.java | 37 ++-- .../api/pocket/IPocketAccess.java | 11 +- .../api/pocket/IPocketUpgrade.java | 5 +- .../redstone/IBundledRedstoneProvider.java | 9 +- .../api/turtle/AbstractTurtleUpgrade.java | 37 ++-- .../computercraft/api/turtle/FakePlayer.java | 144 ++++++------- .../api/turtle/ITurtleAccess.java | 23 +-- .../api/turtle/ITurtleUpgrade.java | 3 +- .../api/turtle/event/TurtleAttackEvent.java | 3 +- .../api/turtle/event/TurtleBlockEvent.java | 23 +-- .../turtle/event/TurtleInspectItemEvent.java | 3 +- .../turtle/event/TurtleInventoryEvent.java | 21 +- .../api/turtle/event/TurtleRefuelEvent.java | 3 +- .../computercraft/client/ClientRegistry.java | 39 ++-- .../client/ClientTableFormatter.java | 38 ++-- .../computercraft/client/SoundManager.java | 39 ++-- .../client/gui/ComputerScreenBase.java | 64 +++--- .../client/gui/FixedWidthFontRenderer.java | 98 ++++----- .../computercraft/client/gui/GuiComputer.java | 28 +-- .../client/gui/GuiDiskDrive.java | 27 ++- .../computercraft/client/gui/GuiPrinter.java | 29 ++- .../computercraft/client/gui/GuiPrintout.java | 46 ++--- .../computercraft/client/gui/GuiTurtle.java | 31 ++- .../client/gui/NoTermComputerScreen.java | 46 ++--- .../client/gui/OptionScreen.java | 55 +++-- .../client/gui/widgets/ComputerSidebar.java | 37 ++-- .../gui/widgets/DynamicImageButton.java | 47 +++-- .../client/gui/widgets/WidgetTerminal.java | 27 +-- .../proxy/ComputerCraftProxyClient.java | 25 ++- .../client/render/CableHighlightRenderer.java | 55 ++--- .../client/render/ComputerBorderRenderer.java | 57 +++--- .../client/render/ItemMapLikeRenderer.java | 92 ++++----- .../client/render/ItemPocketRenderer.java | 60 +++--- .../client/render/ItemPrintoutRenderer.java | 25 +-- .../client/render/ModelTransformer.java | 31 ++- .../render/MonitorHighlightRenderer.java | 55 ++--- .../render/MonitorTextureBufferShader.java | 38 ++-- .../client/render/PrintoutRenderer.java | 15 +- .../client/render/RenderTypes.java | 106 +++++----- .../render/TileEntityMonitorRenderer.java | 72 ++++--- .../render/TileEntityTurtleRenderer.java | 135 ++++++------ .../client/render/TurtleModelLoader.java | 45 ++-- .../client/render/TurtleMultiModel.java | 49 +++-- .../client/render/TurtlePlayerRenderer.java | 19 +- .../client/render/TurtleSmartItemModel.java | 87 ++++---- .../core/computer/ComputerSide.java | 3 +- .../core/computer/MainThreadExecutor.java | 3 +- .../core/filesystem/ResourceMount.java | 39 ++-- .../computercraft/core/terminal/Terminal.java | 13 +- .../fabric/mixin/ChatHudAccess.java | 8 +- .../fabric/mixin/HeldItemRendererAccess.java | 14 +- .../fabric/mixin/MinecraftServerAccess.java | 4 +- .../fabric/mixin/MixinBlock.java | 18 +- .../fabric/mixin/MixinEntity.java | 8 +- .../fabric/mixin/MixinGameRenderer.java | 16 +- .../fabric/mixin/MixinHandledScreen.java | 18 +- .../fabric/mixin/MixinHeldItemRenderer.java | 24 +-- .../mixin/MixinItemFrameEntityRenderer.java | 22 +- .../fabric/mixin/MixinLanguage.java | 2 +- .../fabric/mixin/MixinMatrix4f.java | 2 +- .../fabric/mixin/MixinMinecraftClient.java | 10 +- .../fabric/mixin/MixinScreen.java | 2 +- .../MixinServerPlayerInteractionManager.java | 32 +-- .../fabric/mixin/MixinServerWorld.java | 8 +- .../fabric/mixin/MixinWorld.java | 14 +- .../fabric/mixin/MixinWorldRenderer.java | 16 +- .../fabric/mixin/SignBlockEntityAccess.java | 6 +- .../fabric/mixin/WorldSavePathAccess.java | 6 +- .../computercraft/shared/BundledRedstone.java | 17 +- .../shared/ComputerCraftRegistry.java | 120 +++++------ .../computercraft/shared/MediaProviders.java | 3 +- .../computercraft/shared/Peripherals.java | 13 +- .../computercraft/shared/PocketUpgrades.java | 7 +- .../shared/TurtlePermissions.java | 14 +- .../computercraft/shared/TurtleUpgrades.java | 3 +- .../shared/command/ClientCommands.java | 5 +- .../shared/command/CommandComputerCraft.java | 95 +++++---- .../shared/command/CommandUtils.java | 23 +-- .../shared/command/Exceptions.java | 8 +- .../shared/command/UserLevel.java | 21 +- .../arguments/ArgumentSerializers.java | 24 +-- .../arguments/ComputerArgumentType.java | 7 +- .../arguments/ComputersArgumentType.java | 17 +- .../command/arguments/RepeatArgumentType.java | 33 ++- .../command/builder/CommandBuilder.java | 9 +- .../builder/HelpingArgumentBuilder.java | 73 ++++--- .../shared/command/text/ChatHelpers.java | 58 +++--- .../command/text/ServerTableFormatter.java | 20 +- .../shared/command/text/TableBuilder.java | 25 ++- .../shared/command/text/TableFormatter.java | 34 ++-- .../shared/common/BlockGeneric.java | 51 +++-- .../shared/common/ClientTerminal.java | 6 +- .../shared/common/ColourableRecipe.java | 37 ++-- .../shared/common/ContainerHeldItem.java | 51 +++-- .../DefaultBundledRedstoneProvider.java | 13 +- .../shared/common/IBundledRedstoneBlock.java | 10 +- .../shared/common/IColouredItem.java | 10 +- .../shared/common/ServerTerminal.java | 7 +- .../shared/common/TileGeneric.java | 49 +++-- .../shared/computer/apis/CommandAPI.java | 55 +++-- .../shared/computer/blocks/BlockComputer.java | 45 ++-- .../computer/blocks/BlockComputerBase.java | 101 +++++---- .../computer/blocks/TileCommandComputer.java | 73 ++++--- .../shared/computer/blocks/TileComputer.java | 31 ++- .../computer/blocks/TileComputerBase.java | 139 +++++++------ .../shared/computer/core/ClientComputer.java | 8 +- .../shared/computer/core/ComputerState.java | 7 +- .../computer/core/IContainerComputer.java | 7 +- .../shared/computer/core/ServerComputer.java | 43 ++-- .../ComputerMenuWithoutInventory.java | 13 +- .../inventory/ContainerComputerBase.java | 45 ++-- .../inventory/ContainerViewComputer.java | 11 +- .../computer/items/ComputerItemFactory.java | 3 +- .../shared/computer/items/IComputerItem.java | 9 +- .../shared/computer/items/ItemComputer.java | 15 +- .../computer/items/ItemComputerBase.java | 29 ++- .../recipe/ComputerConvertRecipe.java | 29 ++- .../computer/recipe/ComputerFamilyRecipe.java | 47 +++-- .../recipe/ComputerUpgradeRecipe.java | 15 +- .../shared/computer/upload/UploadResult.java | 16 +- .../data/BlockNamedEntityLootCondition.java | 27 ++- .../data/ConstantLootConditionSerializer.java | 15 +- .../data/HasComputerIdLootCondition.java | 25 ++- .../data/PlayerCreativeLootCondition.java | 29 ++- .../integration/ModMenuIntegration.java | 12 +- .../shared/media/items/ItemDisk.java | 45 ++-- .../shared/media/items/ItemPrintout.java | 49 +++-- .../shared/media/items/ItemTreasureDisk.java | 37 ++-- .../shared/media/items/RecordMedia.java | 19 +- .../shared/media/recipes/DiskRecipe.java | 47 +++-- .../shared/media/recipes/PrintoutRecipe.java | 41 ++-- .../shared/network/NetworkHandler.java | 61 +++--- .../shared/network/NetworkMessage.java | 5 +- .../client/ChatTableClientMessage.java | 27 ++- .../network/client/ComputerClientMessage.java | 7 +- .../client/ComputerDataClientMessage.java | 15 +- .../client/ComputerDeletedClientMessage.java | 4 +- .../client/ComputerTerminalClientMessage.java | 7 +- .../network/client/MonitorClientMessage.java | 21 +- .../client/PlayRecordClientMessage.java | 31 ++- .../client/SpeakerMoveClientMessage.java | 25 ++- .../client/SpeakerPlayClientMessage.java | 33 ++- .../client/SpeakerStopClientMessage.java | 11 +- .../shared/network/client/TerminalState.java | 11 +- .../network/client/UploadResultMessage.java | 29 ++- .../container/ComputerContainerData.java | 10 +- .../network/container/ContainerData.java | 35 ++-- .../container/HeldItemContainerData.java | 19 +- .../container/ViewComputerContainerData.java | 7 +- .../server/ComputerActionServerMessage.java | 11 +- .../network/server/ComputerServerMessage.java | 7 +- .../network/server/ContinueUploadMessage.java | 11 +- .../network/server/KeyEventServerMessage.java | 7 +- .../server/MouseEventServerMessage.java | 7 +- .../server/QueueEventServerMessage.java | 15 +- .../server/RequestComputerMessage.java | 7 +- .../network/server/UploadFileMessage.java | 19 +- .../commandblock/CommandBlockPeripheral.java | 25 ++- .../peripheral/diskdrive/BlockDiskDrive.java | 83 ++++---- .../diskdrive/ContainerDiskDrive.java | 45 ++-- .../diskdrive/DiskDrivePeripheral.java | 3 +- .../peripheral/diskdrive/DiskDriveState.java | 7 +- .../peripheral/diskdrive/TileDiskDrive.java | 169 ++++++++------- .../peripheral/generic/GenericPeripheral.java | 9 +- .../generic/GenericPeripheralProvider.java | 11 +- .../peripheral/generic/data/BlockData.java | 9 +- .../peripheral/generic/data/DataHelpers.java | 21 +- .../peripheral/generic/data/ItemData.java | 65 +++--- .../generic/methods/InventoryMethods.java | 41 ++-- .../peripheral/modem/ModemPeripheral.java | 9 +- .../shared/peripheral/modem/ModemShapes.java | 21 +- .../peripheral/modem/wired/BlockCable.java | 192 +++++++++--------- .../modem/wired/BlockWiredModemFull.java | 31 ++- .../modem/wired/CableModemVariant.java | 13 +- .../peripheral/modem/wired/CableShapes.java | 41 ++-- .../modem/wired/ItemBlockCable.java | 111 +++++----- .../peripheral/modem/wired/TileCable.java | 147 +++++++------- .../modem/wired/TileWiredModemFull.java | 109 +++++----- .../wired/WiredModemLocalPeripheral.java | 21 +- .../modem/wired/WiredModemPeripheral.java | 5 +- .../modem/wireless/BlockWirelessModem.java | 83 ++++---- .../modem/wireless/TileWirelessModem.java | 47 +++-- .../wireless/WirelessModemPeripheral.java | 8 +- .../modem/wireless/WirelessNetwork.java | 2 +- .../peripheral/monitor/BlockMonitor.java | 65 +++--- .../peripheral/monitor/ClientMonitor.java | 4 +- .../peripheral/monitor/MonitorEdgeState.java | 7 +- .../peripheral/monitor/TileMonitor.java | 99 +++++---- .../shared/peripheral/monitor/XYPair.java | 2 +- .../peripheral/printer/BlockPrinter.java | 77 ++++--- .../peripheral/printer/ContainerPrinter.java | 57 +++--- .../peripheral/printer/TilePrinter.java | 145 +++++++------ .../peripheral/speaker/BlockSpeaker.java | 47 +++-- .../peripheral/speaker/SpeakerPeripheral.java | 57 +++--- .../peripheral/speaker/TileSpeaker.java | 25 ++- .../shared/pocket/apis/PocketAPI.java | 38 ++-- .../pocket/core/PocketServerComputer.java | 53 +++-- .../inventory/PocketComputerMenuProvider.java | 39 ++-- .../pocket/items/ItemPocketComputer.java | 111 +++++----- .../items/PocketComputerItemFactory.java | 3 +- .../pocket/peripherals/PocketModem.java | 9 +- .../peripherals/PocketModemPeripheral.java | 15 +- .../pocket/peripherals/PocketSpeaker.java | 9 +- .../peripherals/PocketSpeakerPeripheral.java | 14 +- .../recipes/PocketComputerUpgradeRecipe.java | 33 ++- .../proxy/ComputerCraftProxyCommon.java | 24 +-- .../shared/turtle/FurnaceRefuelHandler.java | 11 +- .../shared/turtle/SignInspectHandler.java | 7 +- .../shared/turtle/apis/TurtleAPI.java | 11 +- .../shared/turtle/blocks/BlockTurtle.java | 104 +++++----- .../shared/turtle/blocks/ITurtleTile.java | 8 +- .../shared/turtle/blocks/TileTurtle.java | 163 ++++++++------- .../shared/turtle/core/InteractDirection.java | 2 +- .../shared/turtle/core/MoveDirection.java | 2 +- .../shared/turtle/core/TurtleBrain.java | 169 ++++++++------- .../turtle/core/TurtleCompareCommand.java | 25 ++- .../turtle/core/TurtleCompareToCommand.java | 7 +- .../turtle/core/TurtleCraftCommand.java | 3 +- .../turtle/core/TurtleDetectCommand.java | 13 +- .../shared/turtle/core/TurtleDropCommand.java | 19 +- .../turtle/core/TurtleEquipCommand.java | 11 +- .../turtle/core/TurtleInspectCommand.java | 17 +- .../shared/turtle/core/TurtleMoveCommand.java | 51 +++-- .../turtle/core/TurtlePlaceCommand.java | 162 ++++++++------- .../shared/turtle/core/TurtlePlayer.java | 97 +++++---- .../turtle/core/TurtleRefuelCommand.java | 5 +- .../shared/turtle/core/TurtleSuckCommand.java | 39 ++-- .../turtle/core/TurtleTransferToCommand.java | 3 +- .../shared/turtle/core/TurtleTurnCommand.java | 4 +- .../turtle/inventory/ContainerTurtle.java | 55 +++-- .../shared/turtle/items/ITurtleItem.java | 7 +- .../shared/turtle/items/ItemTurtle.java | 63 +++--- .../turtle/items/TurtleItemFactory.java | 7 +- .../shared/turtle/recipes/TurtleRecipe.java | 15 +- .../turtle/recipes/TurtleUpgradeRecipe.java | 35 ++-- .../shared/turtle/upgrades/TurtleAxe.java | 12 +- .../turtle/upgrades/TurtleCraftingTable.java | 17 +- .../shared/turtle/upgrades/TurtleHoe.java | 27 ++- .../upgrades/TurtleInventoryCrafting.java | 89 ++++---- .../shared/turtle/upgrades/TurtleModem.java | 51 +++-- .../shared/turtle/upgrades/TurtleShovel.java | 27 ++- .../shared/turtle/upgrades/TurtleSpeaker.java | 27 ++- .../shared/turtle/upgrades/TurtleSword.java | 24 +-- .../shared/turtle/upgrades/TurtleTool.java | 99 ++++----- .../shared/util/ColourTracker.java | 2 +- .../shared/util/ColourUtils.java | 11 +- .../computercraft/shared/util/Config.java | 11 +- .../shared/util/DefaultInventory.java | 17 +- .../shared/util/DefaultSidedInventory.java | 15 +- .../shared/util/DirectionUtil.java | 6 +- .../shared/util/DropConsumer.java | 31 ++- .../shared/util/FakeNetHandler.java | 179 +++++++++------- .../computercraft/shared/util/IDAssigner.java | 7 +- .../shared/util/ImpostorRecipe.java | 55 +++-- .../shared/util/ImpostorShapelessRecipe.java | 61 +++--- .../shared/util/InventoryDelegate.java | 69 ++++--- .../shared/util/InventoryUtil.java | 68 +++---- .../shared/util/InvisibleSlot.java | 17 +- .../shared/util/ItemStorage.java | 61 +++--- .../computercraft/shared/util/NBTUtil.java | 58 +++--- .../computercraft/shared/util/Palette.java | 12 +- .../computercraft/shared/util/RecipeUtil.java | 27 ++- .../computercraft/shared/util/RecordUtil.java | 12 +- .../shared/util/RedstoneUtil.java | 16 +- .../shared/util/SingleIntArray.java | 6 +- .../shared/util/TickScheduler.java | 23 +-- .../shared/util/ValidatingSlot.java | 11 +- .../shared/util/WaterloggableHelpers.java | 40 ++-- .../computercraft/shared/util/WorldUtil.java | 102 +++++----- .../shared/wired/WiredNetwork.java | 9 +- 287 files changed, 4731 insertions(+), 4820 deletions(-) diff --git a/build.gradle b/build.gradle index 44ca32f99..de076b89b 100644 --- a/build.gradle +++ b/build.gradle @@ -29,9 +29,9 @@ repositories { } } -loom { - accessWidenerPath = file("src/main/resources/cc.accesswidener") -} +//loom { +// accessWidenerPath = file("src/main/resources/cc.accesswidener") +//} configurations { implementation.extendsFrom shade @@ -41,7 +41,8 @@ dependencies { checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1' minecraft "com.mojang:minecraft:${mc_version}" - mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2" + //mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2" + mappings(minecraft.officialMojangMappings()) modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}" diff --git a/gradle.properties b/gradle.properties index efe800f9d..92c1f2c1f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ mod_version=1.97.2 # Minecraft properties mc_version=1.17.1 -mappings_version=61 +#mappings_version=61 # Dependencies cloth_config_version=5.0.34 diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index c79489d7d..317bfd0ef 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -31,10 +31,10 @@ import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourcePackActivationType; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -111,30 +111,30 @@ public final class ComputerCraft implements ModInitializer // Logging public static final Logger log = LogManager.getLogger( MOD_ID ); - public static ItemGroup MAIN_GROUP = FabricItemGroupBuilder.build( new Identifier( MOD_ID, "main" ), () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) ); + public static CreativeModeTab MAIN_GROUP = FabricItemGroupBuilder.build( new ResourceLocation( MOD_ID, "main" ), () -> new ItemStack( ModBlocks.COMPUTER_NORMAL ) ); @Override public void onInitialize() { ComputerCraftProxyCommon.init(); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "computer_upgrade" ), ComputerUpgradeRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ), ComputerUpgradeRecipe.SERIALIZER ); Registry.register( Registry.RECIPE_SERIALIZER, - new Identifier( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ), + new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ), PocketComputerUpgradeRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "disk" ), DiskRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "printout" ), PrintoutRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "turtle_upgrade" ), TurtleUpgradeRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "impostor_shaped" ), ImpostorRecipe.SERIALIZER ); - Registry.register( Registry.RECIPE_SERIALIZER, new Identifier( ComputerCraft.MOD_ID, "impostor_shapeless" ), ImpostorShapelessRecipe.SERIALIZER ); - Registry.register( Registry.LOOT_CONDITION_TYPE, new Identifier( ComputerCraft.MOD_ID, "block_named" ), BlockNamedEntityLootCondition.TYPE ); - Registry.register( Registry.LOOT_CONDITION_TYPE, new Identifier( ComputerCraft.MOD_ID, "player_creative" ), PlayerCreativeLootCondition.TYPE ); - Registry.register( Registry.LOOT_CONDITION_TYPE, new Identifier( ComputerCraft.MOD_ID, "has_id" ), HasComputerIdLootCondition.TYPE ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "disk" ), DiskRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "printout" ), PrintoutRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade" ), TurtleUpgradeRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ), ImpostorRecipe.SERIALIZER ); + Registry.register( Registry.RECIPE_SERIALIZER, new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ), ImpostorShapelessRecipe.SERIALIZER ); + Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ), BlockNamedEntityLootCondition.TYPE ); + Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, "player_creative" ), PlayerCreativeLootCondition.TYPE ); + Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ), HasComputerIdLootCondition.TYPE ); init(); FabricLoader.getInstance().getModContainer( MOD_ID ).ifPresent( modContainer -> { - ResourceManagerHelper.registerBuiltinResourcePack( new Identifier( MOD_ID, "classic" ), modContainer, ResourcePackActivationType.NORMAL ); - ResourceManagerHelper.registerBuiltinResourcePack( new Identifier( MOD_ID, "overhaul" ), modContainer, ResourcePackActivationType.NORMAL ); + ResourceManagerHelper.registerBuiltinResourcePack( new ResourceLocation( MOD_ID, "classic" ), modContainer, ResourcePackActivationType.NORMAL ); + ResourceManagerHelper.registerBuiltinResourcePack( new ResourceLocation( MOD_ID, "overhaul" ), modContainer, ResourcePackActivationType.NORMAL ); } ); } } diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 5e8128645..5b6d83f23 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -32,15 +32,14 @@ import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.wired.WiredNode; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.resource.ReloadableResourceManager; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockView; -import net.minecraft.world.World; - +import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.File; @@ -65,7 +64,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); try { - return manager.getResource( new Identifier( domain, subPath ) ) + return manager.getResource( new ResourceLocation( domain, subPath ) ) .getInputStream(); } catch( IOException ignored ) @@ -93,13 +92,13 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI } @Override - public int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ) + public int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath ) { return IDAssigner.getNextId( parentSubPath ); } @Override - public IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ) + public IWritableMount createSaveDirMount( @Nonnull Level world, @Nonnull String subPath, long capacity ) { try { @@ -143,7 +142,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI } @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return BundledRedstone.getDefaultOutput( world, pos, side ); } @@ -188,7 +187,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI @Nullable @Override - public IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public IWiredElement getWiredElementAt( @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction side ) { BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileCable ) diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index c1f8ed540..141ebfc6d 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -21,13 +21,12 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockView; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; /** * The static entry point to the ComputerCraft API. @@ -81,9 +80,9 @@ public final class ComputerCraftAPI * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason. * * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. - * @see #createSaveDirMount(World, String, long) + * @see #createSaveDirMount(Level, String, long) */ - public static int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ) + public static int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath ) { return getInstance().createUniqueNumberedSaveDir( world, parentSubPath ); } @@ -100,14 +99,14 @@ public final class ComputerCraftAPI * @param capacity The amount of data that can be stored in the directory before it fills up, in bytes. * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() to mount this on a * Computers' file system. - * @see #createUniqueNumberedSaveDir(World, String) + * @see #createUniqueNumberedSaveDir(Level, String) * @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mountWritable(String, IWritableMount) * @see IMount * @see IWritableMount */ @Nullable - public static IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ) + public static IWritableMount createSaveDirMount( @Nonnull Level world, @Nonnull String subPath, long capacity ) { return getInstance().createSaveDirMount( world, subPath, capacity ); } @@ -192,7 +191,7 @@ public final class ComputerCraftAPI * capable of emitting bundled redstone at the location, -1 will be returned. * @see IBundledRedstoneProvider */ - public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public static int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getInstance().getBundledRedstoneOutput( world, pos, side ); } @@ -251,7 +250,7 @@ public final class ComputerCraftAPI * @see IWiredElement#getNode() */ @Nullable - public static IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public static IWiredElement getWiredElementAt( @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getInstance().getWiredElementAt( world, pos, side ); } @@ -261,10 +260,10 @@ public final class ComputerCraftAPI @Nonnull String getInstalledVersion(); - int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath ); + int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath ); @Nullable - IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity ); + IWritableMount createSaveDirMount( @Nonnull Level world, @Nonnull String subPath, long capacity ); @Nullable IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ); @@ -277,7 +276,7 @@ public final class ComputerCraftAPI void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ); - int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); + int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); void registerMediaProvider( @Nonnull IMediaProvider provider ); @@ -292,6 +291,6 @@ public final class ComputerCraftAPI IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ); @Nullable - IWiredElement getWiredElementAt( @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction side ); + IWiredElement getWiredElementAt( @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction side ); } } diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java index ee9b6e500..58b4a8b1b 100644 --- a/src/main/java/dan200/computercraft/api/IUpgradeBase.java +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -7,11 +7,10 @@ package dan200.computercraft.api; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; /** * Common functionality between {@link ITurtleUpgrade} and {@link IPocketUpgrade}. @@ -28,7 +27,7 @@ public interface IUpgradeBase * @return The unique ID for this upgrade. */ @Nonnull - Identifier getUpgradeID(); + ResourceLocation getUpgradeID(); /** * Return an unlocalised string to describe this type of computer in item names. @@ -76,8 +75,8 @@ public interface IUpgradeBase // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a // null one. - NbtCompound shareTag = stack.getNbt(); - NbtCompound craftingShareTag = crafting.getNbt(); + CompoundTag shareTag = stack.getTag(); + CompoundTag craftingShareTag = crafting.getTag(); if( shareTag == craftingShareTag ) return true; if( shareTag == null ) return craftingShareTag.isEmpty(); if( craftingShareTag == null ) return shareTag.isEmpty(); diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index 201d53333..5afe637ec 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -8,16 +8,15 @@ package dan200.computercraft.api.client; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedModelManager; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.util.math.AffineTransformation; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Vec3f; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.world.item.ItemStack; import javax.annotation.Nonnull; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; import java.util.Objects; /** @@ -27,9 +26,9 @@ import java.util.Objects; public final class TransformedModel { private final BakedModel model; - private final AffineTransformation matrix; + private final Transformation matrix; - public TransformedModel( @Nonnull BakedModel model, @Nonnull AffineTransformation matrix ) + public TransformedModel( @Nonnull BakedModel model, @Nonnull Transformation matrix ) { this.model = Objects.requireNonNull( model ); this.matrix = Objects.requireNonNull( matrix ); @@ -38,22 +37,22 @@ public final class TransformedModel public TransformedModel( @Nonnull BakedModel model ) { this.model = Objects.requireNonNull( model ); - matrix = AffineTransformation.identity(); + matrix = Transformation.identity(); } - public static TransformedModel of( @Nonnull ModelIdentifier location ) + public static TransformedModel of( @Nonnull ModelResourceLocation location ) { - BakedModelManager modelManager = MinecraftClient.getInstance() - .getBakedModelManager(); + ModelManager modelManager = Minecraft.getInstance() + .getModelManager(); return new TransformedModel( modelManager.getModel( location ) ); } - public static TransformedModel of( @Nonnull ItemStack item, @Nonnull AffineTransformation transform ) + public static TransformedModel of( @Nonnull ItemStack item, @Nonnull Transformation transform ) { - BakedModel model = MinecraftClient.getInstance() + BakedModel model = Minecraft.getInstance() .getItemRenderer() - .getModels() - .getModel( item ); + .getItemModelShaper() + .getItemModel( item ); return new TransformedModel( model, transform ); } @@ -64,23 +63,23 @@ public final class TransformedModel } @Nonnull - public AffineTransformation getMatrix() + public Transformation getMatrix() { return matrix; } - public void push( MatrixStack matrixStack ) + public void push( PoseStack matrixStack ) { - matrixStack.push(); + matrixStack.pushPose(); - Vec3f translation = matrix.getTranslation(); - matrixStack.translate( translation.getX(), translation.getY(), translation.getZ() ); + Vector3f translation = matrix.getTranslation(); + matrixStack.translate( translation.x(), translation.y(), translation.z() ); - matrixStack.multiply( matrix.getRotation2() ); + matrixStack.mulPose( matrix.getLeftRotation() ); - Vec3f scale = matrix.getScale(); - matrixStack.scale( scale.getX(), scale.getY(), scale.getZ() ); + Vector3f scale = matrix.getScale(); + matrixStack.scale( scale.x(), scale.y(), scale.z() ); - matrixStack.multiply( matrix.getRotation1() ); + matrixStack.mulPose( matrix.getRightRotation() ); } } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 9634cbb57..b8a6c8f43 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -8,9 +8,8 @@ package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IComputerAccess; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.file.attribute.BasicFileAttributes; @@ -19,10 +18,10 @@ import java.util.List; /** * Represents a read only part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or {@link + * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or {@link * ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! * - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) * @see IComputerAccess#mount(String, IMount) * @see IWritableMount diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index d39eec86c..b6cd8f688 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -8,9 +8,8 @@ package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IComputerAccess; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; @@ -20,10 +19,10 @@ import java.util.OptionalLong; * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} or {@link * IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(World, String, long)}, or you're free to + * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to * implement it yourselves! * - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mountWritable(String, IWritableMount) * @see IMount diff --git a/src/main/java/dan200/computercraft/api/lua/GenericSource.java b/src/main/java/dan200/computercraft/api/lua/GenericSource.java index f109f9d37..b04c11ce9 100644 --- a/src/main/java/dan200/computercraft/api/lua/GenericSource.java +++ b/src/main/java/dan200/computercraft/api/lua/GenericSource.java @@ -9,9 +9,8 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.core.asm.LuaMethod; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; /** * A generic source of {@link LuaMethod} functions. @@ -54,5 +53,5 @@ public interface GenericSource * @return This source's identifier. */ @Nonnull - Identifier id(); + ResourceLocation id(); } diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index 986da717e..e7f7bb7d6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -7,13 +7,12 @@ package dan200.computercraft.api.media; import dan200.computercraft.api.filesystem.IMount; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.sound.SoundEvent; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; /** * Represents an item that can be placed in a disk drive and used by a Computer. @@ -77,11 +76,11 @@ public interface IMedia * dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable() * @see IMount * @see dan200.computercraft.api.filesystem.IWritableMount - * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String) */ @Nullable - default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull Level world ) { return null; } diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index 7afa1e632..46c586ec8 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -6,10 +6,9 @@ package dan200.computercraft.api.media; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.item.ItemStack; /** * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}. diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index 660344a2b..e146c23e7 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -6,10 +6,9 @@ package dan200.computercraft.api.network; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; /** * An object on an {@link IPacketNetwork}, capable of receiving packets. @@ -22,7 +21,7 @@ public interface IPacketReceiver * @return The receivers's world. */ @Nonnull - World getWorld(); + Level getWorld(); /** * Get the position in the world at which this receiver exists. @@ -30,7 +29,7 @@ public interface IPacketReceiver * @return The receiver's position. */ @Nonnull - Vec3d getPosition(); + Vec3 getPosition(); /** * Get the maximum distance this receiver can send and receive messages. diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index f3c06a397..bf9adcead 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -6,10 +6,9 @@ package dan200.computercraft.api.network; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; /** * An object on a {@link IPacketNetwork}, capable of sending packets. @@ -22,7 +21,7 @@ public interface IPacketSender * @return The sender's world. */ @Nonnull - World getWorld(); + Level getWorld(); /** * Get the position in the world at which this sender exists. @@ -30,7 +29,7 @@ public interface IPacketSender * @return The sender's position. */ @Nonnull - Vec3d getPosition(); + Vec3 getPosition(); /** * Get some sort of identification string for this sender. This does not strictly need to be unique, but you should be able to extract some identifiable diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 0514ea509..cd558f849 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -13,10 +13,9 @@ import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.MethodResult; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.level.Level; import java.util.Map; /** @@ -33,7 +32,7 @@ public interface IComputerAccess * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a file in the desired location. * Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount, String) * @see #mountWritable(String, IWritableMount) @@ -55,7 +54,7 @@ public interface IComputerAccess * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a file in the desired location. * Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #mountWritable(String, IWritableMount) @@ -84,7 +83,7 @@ public interface IComputerAccess * @return The location on the computer's file system where you the mount mounted, or null if there was already a file in the desired location. Store * this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #unmount(String) @@ -105,7 +104,7 @@ public interface IComputerAccess * @return The location on the computer's file system where you the mount mounted, or null if there was already a file in the desired location. Store * this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. - * @see ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #unmount(String) diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index ae704dfc7..c2b5c7af4 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -6,12 +6,11 @@ package dan200.computercraft.api.peripheral; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.Optional; /** @@ -34,5 +33,5 @@ public interface IPeripheralProvider * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ @Nonnull - IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); + IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java index b12d7f5c0..9cc83c5fa 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java @@ -5,15 +5,14 @@ */ package dan200.computercraft.api.peripheral; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; /** - * A {@link net.minecraft.block.entity.BlockEntity} which may act as a peripheral. + * A {@link net.minecraft.world.level.block.entity.BlockEntity} which may act as a peripheral. * * If you need more complex capabilities (such as handling TEs not belonging to your mod), you should use {@link IPeripheralProvider}. */ @@ -24,7 +23,7 @@ public interface IPeripheralTile * * @param side The side to get the peripheral from. * @return A peripheral, or {@code null} if there is not a peripheral here. - * @see IPeripheralProvider#getPeripheral(World, BlockPos, Direction) + * @see IPeripheralProvider#getPeripheral(Level, BlockPos, Direction) */ @Nullable IPeripheral getPeripheral( @Nonnull Direction side ); diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 6599d7e90..dc7f2fc9e 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -7,13 +7,12 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.shared.util.NonNullSupplier; -import net.minecraft.item.Item; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.Util; - import javax.annotation.Nonnull; +import net.minecraft.Util; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; import java.util.function.Supplier; /** @@ -23,55 +22,55 @@ import java.util.function.Supplier; */ public abstract class AbstractPocketUpgrade implements IPocketUpgrade { - private final Identifier id; + private final ResourceLocation id; private final String adjective; private final NonNullSupplier stack; - protected AbstractPocketUpgrade( Identifier id, String adjective, NonNullSupplier stack ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, NonNullSupplier stack ) { this.id = id; this.adjective = adjective; this.stack = stack; } - protected AbstractPocketUpgrade( Identifier id, NonNullSupplier item ) + protected AbstractPocketUpgrade( ResourceLocation id, NonNullSupplier item ) { - this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item ); + this( id, Util.makeDescriptionId( "upgrade", id ) + ".adjective", item ); } - protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemStack stack ) { this( id, adjective, () -> stack ); } - protected AbstractPocketUpgrade( Identifier id, ItemStack stack ) + protected AbstractPocketUpgrade( ResourceLocation id, ItemStack stack ) { this( id, () -> stack ); } - protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemLike item ) { this( id, adjective, new CachedStack( () -> item ) ); } - protected AbstractPocketUpgrade( Identifier id, ItemConvertible item ) + protected AbstractPocketUpgrade( ResourceLocation id, ItemLike item ) { this( id, new CachedStack( () -> item ) ); } - protected AbstractPocketUpgrade( Identifier id, String adjective, Supplier item ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, Supplier item ) { this( id, adjective, new CachedStack( item ) ); } - protected AbstractPocketUpgrade( Identifier id, Supplier item ) + protected AbstractPocketUpgrade( ResourceLocation id, Supplier item ) { this( id, new CachedStack( item ) ); } @Nonnull @Override - public final Identifier getUpgradeID() + public final ResourceLocation getUpgradeID() { return id; } @@ -97,11 +96,11 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade */ private static final class CachedStack implements NonNullSupplier { - private final Supplier provider; + private final Supplier provider; private Item item; private ItemStack stack; - CachedStack( Supplier provider ) + CachedStack( Supplier provider ) { this.provider = provider; } diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index 0638f6c5c..f8adb22a6 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -7,12 +7,11 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; import java.util.Map; /** @@ -73,7 +72,7 @@ public interface IPocketAccess * @see #updateUpgradeNBTData() */ @Nonnull - NbtCompound getUpgradeNBTData(); + CompoundTag getUpgradeNBTData(); /** * Mark the upgrade-specific NBT as dirty. @@ -93,5 +92,5 @@ public interface IPocketAccess * @return A collection of all upgrade names. */ @Nonnull - Map getUpgrades(); + Map getUpgrades(); } diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index d8b9d0c13..4bd5ee1de 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -9,10 +9,9 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.level.Level; /** * Additional peripherals for pocket computers. @@ -55,7 +54,7 @@ public interface IPocketUpgrade extends IUpgradeBase * requiring the player to be sneaking - otherwise they will be unable to access the GUI. * @see #createPeripheral(IPocketAccess) */ - default boolean onRightClick( @Nonnull World world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) + default boolean onRightClick( @Nonnull Level world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) { return false; } diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index ad92f3903..2fc121e60 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -6,11 +6,10 @@ package dan200.computercraft.api.redstone; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; /** * This interface is used to provide bundled redstone output for blocks. @@ -29,5 +28,5 @@ public interface IBundledRedstoneProvider * @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block. * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) */ - int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); + int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index 7046cc808..d73dd641c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -7,13 +7,12 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.shared.util.NonNullSupplier; -import net.minecraft.item.Item; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.Util; - import javax.annotation.Nonnull; +import net.minecraft.Util; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; import java.util.function.Supplier; /** @@ -23,12 +22,12 @@ import java.util.function.Supplier; */ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade { - private final Identifier id; + private final ResourceLocation id; private final TurtleUpgradeType type; private final String adjective; private final NonNullSupplier stack; - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, NonNullSupplier stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, NonNullSupplier stack ) { this.id = id; this.type = type; @@ -36,44 +35,44 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade this.stack = stack; } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, NonNullSupplier stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, NonNullSupplier stack ) { - this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack ); + this( id, type, Util.makeDescriptionId( "upgrade", id ) + ".adjective", stack ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack ) { this( id, type, adjective, () -> stack ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack ) { this( id, type, () -> stack ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemLike item ) { this( id, type, adjective, new CachedStack( () -> item ) ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemLike item ) { this( id, type, new CachedStack( () -> item ) ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, Supplier item ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, Supplier item ) { this( id, type, adjective, new CachedStack( item ) ); } - protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, Supplier item ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, Supplier item ) { this( id, type, new CachedStack( item ) ); } @Nonnull @Override - public final Identifier getUpgradeID() + public final ResourceLocation getUpgradeID() { return id; } @@ -106,11 +105,11 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade */ private static final class CachedStack implements NonNullSupplier { - private final Supplier provider; + private final Supplier provider; private Item item; private ItemStack stack; - CachedStack( Supplier provider ) + CachedStack( Supplier provider ) { this.provider = provider; } diff --git a/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java b/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java index e534e648e..994b83648 100644 --- a/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java +++ b/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java @@ -9,31 +9,33 @@ import com.mojang.authlib.GameProfile; import io.netty.channel.ChannelHandlerContext; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; -import net.minecraft.block.entity.CommandBlockBlockEntity; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.command.argument.EntityAnchorArgumentType; -import net.minecraft.entity.Entity; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.passive.HorseBaseEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; +import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.network.*; -import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket; -import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket; -import net.minecraft.recipe.Recipe; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvent; -import net.minecraft.text.Text; -import net.minecraft.util.Hand; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.village.TradeOfferList; - +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ServerboundCommandSuggestionPacket; +import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.animal.horse.AbstractHorse; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.trading.MerchantOffers; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.entity.CommandBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nullable; import javax.crypto.Cipher; import java.util.Collection; @@ -41,26 +43,26 @@ import java.util.OptionalInt; import java.util.UUID; /** - * A wrapper for {@link ServerPlayerEntity} which denotes a "fake" player. + * A wrapper for {@link ServerPlayer} which denotes a "fake" player. * * Please note that this does not implement any of the traditional fake player behaviour. It simply exists to prevent me passing in normal players. */ -public class FakePlayer extends ServerPlayerEntity +public class FakePlayer extends ServerPlayer { - public FakePlayer( ServerWorld world, GameProfile gameProfile ) + public FakePlayer( ServerLevel world, GameProfile gameProfile ) { super( world.getServer(), world, gameProfile ); - networkHandler = new FakeNetHandler( this ); + connection = new FakeNetHandler( this ); } // region Direct networkHandler access @Override - public void enterCombat() + public void onEnterCombat() { } @Override - public void endCombat() + public void onLeaveCombat() { } @@ -70,23 +72,23 @@ public class FakePlayer extends ServerPlayerEntity } @Override - public void playerTick() + public void doTick() { } @Override - public void onDeath( DamageSource damage ) + public void die( DamageSource damage ) { } @Override - public Entity moveToWorld( ServerWorld destination ) + public Entity changeDimension( ServerLevel destination ) { return this; } @Override - public void wakeUp( boolean bl, boolean updateSleepingPlayers ) + public void stopSleepInBed( boolean bl, boolean updateSleepingPlayers ) { } @@ -103,33 +105,33 @@ public class FakePlayer extends ServerPlayerEntity } @Override - public void openEditSignScreen( SignBlockEntity tile ) + public void openTextEdit( SignBlockEntity tile ) { } @Override - public OptionalInt openHandledScreen( @Nullable NamedScreenHandlerFactory container ) + public OptionalInt openMenu( @Nullable MenuProvider container ) { return OptionalInt.empty(); } @Override - public void sendTradeOffers( int id, TradeOfferList list, int level, int experience, boolean levelled, boolean refreshable ) + public void sendMerchantOffers( int id, MerchantOffers list, int level, int experience, boolean levelled, boolean refreshable ) { } @Override - public void openHorseInventory( HorseBaseEntity horse, Inventory inventory ) + public void openHorseInventory( AbstractHorse horse, Container inventory ) { } @Override - public void useBook( ItemStack stack, Hand hand ) + public void openItemGui( ItemStack stack, InteractionHand hand ) { } @Override - public void openCommandBlockScreen( CommandBlockBlockEntity block ) + public void openCommandBlock( CommandBlockEntity block ) { } @@ -149,7 +151,7 @@ public class FakePlayer extends ServerPlayerEntity // } @Override - public void closeHandledScreen() + public void closeContainer() { } @@ -159,55 +161,55 @@ public class FakePlayer extends ServerPlayerEntity // } @Override - public int unlockRecipes( Collection> recipes ) + public int awardRecipes( Collection> recipes ) { return 0; } // Indirect @Override - public int lockRecipes( Collection> recipes ) + public int resetRecipes( Collection> recipes ) { return 0; } @Override - public void sendMessage( Text textComponent, boolean status ) + public void displayClientMessage( Component textComponent, boolean status ) { } @Override - protected void consumeItem() + protected void completeUsingItem() { } @Override - public void lookAt( EntityAnchorArgumentType.EntityAnchor anchor, Vec3d vec3d ) + public void lookAt( EntityAnchorArgument.Anchor anchor, Vec3 vec3d ) { } @Override - public void lookAtEntity( EntityAnchorArgumentType.EntityAnchor self, Entity entity, EntityAnchorArgumentType.EntityAnchor target ) + public void lookAt( EntityAnchorArgument.Anchor self, Entity entity, EntityAnchorArgument.Anchor target ) { } @Override - protected void onStatusEffectApplied( StatusEffectInstance statusEffectInstance, @Nullable Entity source ) + protected void onEffectAdded( MobEffectInstance statusEffectInstance, @Nullable Entity source ) { } @Override - protected void onStatusEffectUpgraded( StatusEffectInstance statusEffectInstance, boolean particles, @Nullable Entity source ) + protected void onEffectUpdated( MobEffectInstance statusEffectInstance, boolean particles, @Nullable Entity source ) { } @Override - protected void onStatusEffectRemoved( StatusEffectInstance statusEffectInstance ) + protected void onEffectRemoved( MobEffectInstance statusEffectInstance ) { } @Override - public void requestTeleport( double x, double y, double z ) + public void teleportTo( double x, double y, double z ) { } @@ -217,13 +219,13 @@ public class FakePlayer extends ServerPlayerEntity // } @Override - public void sendMessage( Text message, MessageType type, UUID senderUuid ) + public void sendMessage( Component message, ChatType type, UUID senderUuid ) { } @Override - public String getIp() + public String getIpAddress() { return "[Fake Player]"; } @@ -239,63 +241,63 @@ public class FakePlayer extends ServerPlayerEntity // } @Override - public void setCameraEntity( Entity entity ) + public void setCamera( Entity entity ) { } @Override - public void teleport( ServerWorld serverWorld, double x, double y, double z, float pitch, float yaw ) + public void teleportTo( ServerLevel serverWorld, double x, double y, double z, float pitch, float yaw ) { } @Override - public void sendInitialChunkPackets( ChunkPos chunkPos, Packet packet, Packet packet2 ) + public void trackChunk( ChunkPos chunkPos, Packet packet, Packet packet2 ) { } @Override - public void sendUnloadChunkPacket( ChunkPos chunkPos ) + public void untrackChunk( ChunkPos chunkPos ) { } @Override - public void playSound( SoundEvent soundEvent, SoundCategory soundCategory, float volume, float pitch ) + public void playNotifySound( SoundEvent soundEvent, SoundSource soundCategory, float volume, float pitch ) { } - private static class FakeNetHandler extends ServerPlayNetworkHandler + private static class FakeNetHandler extends ServerGamePacketListenerImpl { - FakeNetHandler( ServerPlayerEntity player ) + FakeNetHandler( ServerPlayer player ) { super( player.server, new FakeConnection(), player ); } @Override - public void disconnect( Text message ) + public void disconnect( Component message ) { } @Override - public void onVehicleMove( VehicleMoveC2SPacket move ) + public void handleMoveVehicle( ServerboundMoveVehiclePacket move ) { } @Override - public void onRequestCommandCompletions( RequestCommandCompletionsC2SPacket packet ) + public void handleCustomCommandSuggestions( ServerboundCommandSuggestionPacket packet ) { } @Override - public void sendPacket( Packet packet, @Nullable GenericFutureListener> listener ) + public void send( Packet packet, @Nullable GenericFutureListener> listener ) { } } - private static class FakeConnection extends ClientConnection + private static class FakeConnection extends Connection { FakeConnection() { - super( NetworkSide.CLIENTBOUND ); + super( PacketFlow.CLIENTBOUND ); } @Override @@ -304,7 +306,7 @@ public class FakePlayer extends ServerPlayerEntity } @Override - public void setState( NetworkState state ) + public void setProtocol( ConnectionProtocol state ) { } @@ -329,18 +331,18 @@ public class FakePlayer extends ServerPlayerEntity } @Override - public void disconnect( Text message ) + public void disconnect( Component message ) { } @Override - public void setupEncryption( Cipher cipher, Cipher cipher2 ) + public void setEncryptionKey( Cipher cipher, Cipher cipher2 ) { - super.setupEncryption( cipher, cipher2 ); + super.setEncryptionKey( cipher, cipher2 ); } @Override - public void disableAutoRead() + public void setReadOnly() { } } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index c50b83eb3..0932709f0 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -11,15 +11,14 @@ import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.ItemStorage; -import net.minecraft.inventory.Inventory; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.Container; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; /** * The interface passed to turtle by turtles, providing methods that they can call. @@ -34,7 +33,7 @@ public interface ITurtleAccess * @return the world in which the turtle resides. */ @Nonnull - World getWorld(); + Level getWorld(); /** * Returns a vector containing the integer co-ordinates at which the turtle resides. @@ -55,7 +54,7 @@ public interface ITurtleAccess * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement was cancelled. * @throws UnsupportedOperationException When attempting to teleport on the client side. */ - boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ); + boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ); /** * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. This will shift when the turtle is moving. @@ -65,7 +64,7 @@ public interface ITurtleAccess * @see #getVisualYaw(float) */ @Nonnull - Vec3d getVisualPosition( float f ); + Vec3 getVisualPosition( float f ); /** * Returns the yaw the turtle is facing when it is rendered. @@ -255,7 +254,7 @@ public interface ITurtleAccess * @see #updateUpgradeNBTData(TurtleSide) */ @Nonnull - NbtCompound getUpgradeNBTData( @Nullable TurtleSide side ); + CompoundTag getUpgradeNBTData( @Nullable TurtleSide side ); /** * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the client and persisted. @@ -278,5 +277,5 @@ public interface ITurtleAccess * @return This turtle's inventory */ @Nonnull - Inventory getInventory(); + Container getInventory(); } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index bc9d9e018..da1938e1d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -12,8 +12,7 @@ import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.util.math.Direction; - +import net.minecraft.core.Direction; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java index fa8c492cc..0517bdf51 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java @@ -10,9 +10,8 @@ import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.entity.Entity; - import javax.annotation.Nonnull; +import net.minecraft.world.entity.Entity; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index 2a195e62a..28ffd9b7d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -11,12 +11,11 @@ import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.block.BlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import java.util.Map; import java.util.Objects; @@ -31,10 +30,10 @@ import java.util.Objects; */ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { - private final World world; + private final Level world; private final BlockPos pos; - protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, + protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos ) { super( turtle, action, player ); @@ -50,7 +49,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent * * @return The world the turtle is interacting in. */ - public World getWorld() + public Level getWorld() { return world; } @@ -76,7 +75,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent private final ITurtleUpgrade upgrade; private final TurtleSide side; - public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState block, + public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side ) { super( turtle, TurtleAction.DIG, player, world, pos ); @@ -130,7 +129,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent */ public static class Move extends TurtleBlockEvent { - public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos ) + public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos ) { super( turtle, TurtleAction.MOVE, player, world, pos ); } @@ -145,7 +144,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent { private final ItemStack stack; - public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull ItemStack stack ) + public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull ItemStack stack ) { super( turtle, TurtleAction.PLACE, player, world, pos ); @@ -177,7 +176,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent private final BlockState state; private final Map data; - public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, + public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Map data ) { super( turtle, TurtleAction.INSPECT, player, world, pos ); diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index d22b6673d..0aef37ca4 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -8,9 +8,8 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java index 37b01ecb5..5cc15f9f0 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java @@ -8,13 +8,12 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import java.util.Objects; /** @@ -22,10 +21,10 @@ import java.util.Objects; */ public abstract class TurtleInventoryEvent extends TurtleBlockEvent { - private final Inventory handler; + private final Container handler; - protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, - @Nonnull BlockPos pos, @Nullable Inventory handler ) + protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, + @Nonnull BlockPos pos, @Nullable Container handler ) { super( turtle, action, player, world, pos ); this.handler = handler; @@ -37,7 +36,7 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent * @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world. */ @Nullable - public Inventory getItemHandler() + public Container getItemHandler() { return handler; } @@ -49,7 +48,7 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent */ public static class Suck extends TurtleInventoryEvent { - public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler ) + public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler ) { super( turtle, TurtleAction.SUCK, player, world, pos, handler ); } @@ -64,7 +63,7 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent { private final ItemStack stack; - public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable Inventory handler, + public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler, @Nonnull ItemStack stack ) { super( turtle, TurtleAction.DROP, player, world, pos, handler ); diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index a5374d684..6a3e64960 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -7,10 +7,9 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.item.ItemStack; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 25ac05541..c84ff64c6 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -15,16 +15,15 @@ import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.render.model.ModelRotation; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.texture.SpriteAtlasTexture; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; import java.util.HashSet; import java.util.function.Consumer; @@ -68,20 +67,20 @@ public final class ClientRegistry private ClientRegistry() {} - public static void onTextureStitchEvent( SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry ) + public static void onTextureStitchEvent( TextureAtlas atlasTexture, ClientSpriteRegistryCallback.Registry registry ) { for( String extra : EXTRA_TEXTURES ) { - registry.register( new Identifier( ComputerCraft.MOD_ID, extra ) ); + registry.register( new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); } } @SuppressWarnings( "NewExpressionSideOnly" ) - public static void onModelBakeEvent( ResourceManager manager, Consumer out ) + public static void onModelBakeEvent( ResourceManager manager, Consumer out ) { for( String model : EXTRA_MODELS ) { - out.accept( new ModelIdentifier( new Identifier( ComputerCraft.MOD_ID, model ), "inventory" ) ); + out.accept( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ) ); } } @@ -114,14 +113,14 @@ public final class ClientRegistry ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED ); } - private static BakedModel bake( ModelLoader loader, UnbakedModel model, Identifier identifier ) + private static BakedModel bake( ModelBakery loader, UnbakedModel model, ResourceLocation identifier ) { - model.getTextureDependencies( loader::getOrLoadModel, new HashSet<>() ); + model.getMaterials( loader::getModel, new HashSet<>() ); return model.bake( loader, - spriteIdentifier -> MinecraftClient.getInstance() - .getSpriteAtlas( spriteIdentifier.getAtlasId() ) - .apply( spriteIdentifier.getTextureId() ), - ModelRotation.X0_Y0, + spriteIdentifier -> Minecraft.getInstance() + .getTextureAtlas( spriteIdentifier.atlasLocation() ) + .apply( spriteIdentifier.texture() ), + BlockModelRotation.X0_Y0, identifier ); } } diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 194c23689..0d076d5ce 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -11,15 +11,15 @@ import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.command.text.TableFormatter; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.hud.ChatHud; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.components.ChatComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; public class ClientTableFormatter implements TableFormatter { @@ -29,7 +29,7 @@ public class ClientTableFormatter implements TableFormatter @Override @Nullable - public Text getPadding( Text component, int width ) + public Component getPadding( Component component, int width ) { int extraWidth = width - getWidth( component ); if( extraWidth <= 0 ) @@ -37,18 +37,18 @@ public class ClientTableFormatter implements TableFormatter return null; } - TextRenderer renderer = renderer(); + Font renderer = renderer(); - float spaceWidth = renderer.getWidth( " " ); - int spaces = MathHelper.floor( extraWidth / spaceWidth ); + float spaceWidth = renderer.width( " " ); + int spaces = Mth.floor( extraWidth / spaceWidth ); int extra = extraWidth - (int) (spaces * spaceWidth); - return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), Formatting.GRAY ); + return ChatHelpers.coloured( StringUtils.repeat( ' ', spaces ) + StringUtils.repeat( (char) 712, extra ), ChatFormatting.GRAY ); } - private static TextRenderer renderer() + private static Font renderer() { - return MinecraftClient.getInstance().textRenderer; + return Minecraft.getInstance().font; } @Override @@ -58,16 +58,16 @@ public class ClientTableFormatter implements TableFormatter } @Override - public int getWidth( Text component ) + public int getWidth( Component component ) { - return renderer().getWidth( component ); + return renderer().width( component ); } @Override - public void writeLine( int id, Text component ) + public void writeLine( int id, Component component ) { - MinecraftClient mc = MinecraftClient.getInstance(); - ChatHud chat = mc.inGameHud.getChatHud(); + Minecraft mc = Minecraft.getInstance(); + ChatComponent chat = mc.gui.getChat(); // TODO: Trim the text if it goes over the allowed length // int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); @@ -79,7 +79,7 @@ public class ClientTableFormatter implements TableFormatter @Override public int display( TableBuilder table ) { - ChatHud chat = MinecraftClient.getInstance().inGameHud.getChatHud(); + ChatComponent chat = Minecraft.getInstance().gui.getChat(); int lastHeight = lastHeights.get( table.getId() ); diff --git a/src/main/java/dan200/computercraft/client/SoundManager.java b/src/main/java/dan200/computercraft/client/SoundManager.java index fe452eb7d..67827a498 100644 --- a/src/main/java/dan200/computercraft/client/SoundManager.java +++ b/src/main/java/dan200/computercraft/client/SoundManager.java @@ -5,25 +5,24 @@ */ package dan200.computercraft.client; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.sound.AbstractSoundInstance; -import net.minecraft.client.sound.SoundInstance; -import net.minecraft.client.sound.TickableSoundInstance; -import net.minecraft.sound.SoundCategory; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Vec3d; - import java.util.HashMap; import java.util.Map; import java.util.UUID; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.AbstractSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.resources.sounds.TickableSoundInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.phys.Vec3; public class SoundManager { private static final Map sounds = new HashMap<>(); - public static void playSound( UUID source, Vec3d position, Identifier event, float volume, float pitch ) + public static void playSound( UUID source, Vec3 position, ResourceLocation event, float volume, float pitch ) { - var soundManager = MinecraftClient.getInstance().getSoundManager(); + var soundManager = Minecraft.getInstance().getSoundManager(); MoveableSound oldSound = sounds.get( source ); if( oldSound != null ) soundManager.stop( oldSound ); @@ -38,10 +37,10 @@ public class SoundManager SoundInstance sound = sounds.remove( source ); if( sound == null ) return; - MinecraftClient.getInstance().getSoundManager().stop( sound ); + Minecraft.getInstance().getSoundManager().stop( sound ); } - public static void moveSound( UUID source, Vec3d position ) + public static void moveSound( UUID source, Vec3 position ) { MoveableSound sound = sounds.get( source ); if( sound != null ) sound.setPosition( position ); @@ -54,24 +53,24 @@ public class SoundManager private static class MoveableSound extends AbstractSoundInstance implements TickableSoundInstance { - protected MoveableSound( Identifier sound, Vec3d position, float volume, float pitch ) + protected MoveableSound( ResourceLocation sound, Vec3 position, float volume, float pitch ) { - super( sound, SoundCategory.RECORDS ); + super( sound, SoundSource.RECORDS ); setPosition( position ); this.volume = volume; this.pitch = pitch; - attenuationType = SoundInstance.AttenuationType.LINEAR; + attenuation = SoundInstance.Attenuation.LINEAR; } - void setPosition( Vec3d position ) + void setPosition( Vec3 position ) { - x = (float) position.getX(); - y = (float) position.getY(); - z = (float) position.getZ(); + x = (float) position.x(); + y = (float) position.y(); + z = (float) position.z(); } @Override - public boolean isDone() + public boolean isStopped() { return false; } diff --git a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java index fdab4ce8e..42557de5c 100644 --- a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java +++ b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.WidgetTerminal; @@ -16,14 +17,13 @@ import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.ContinueUploadMessage; import dan200.computercraft.shared.network.server.UploadFileMessage; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; import org.lwjgl.glfw.GLFW; import javax.annotation.Nonnull; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Inventory; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; @@ -34,12 +34,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -public abstract class ComputerScreenBase extends HandledScreen +public abstract class ComputerScreenBase extends AbstractContainerScreen { - private static final Text OK = new TranslatableText( "gui.ok" ); - private static final Text CANCEL = new TranslatableText( "gui.cancel" ); - private static final Text OVERWRITE = new TranslatableText( "gui.computercraft.upload.overwrite_button" ); + private static final Component OK = new TranslatableComponent( "gui.ok" ); + private static final Component CANCEL = new TranslatableComponent( "gui.cancel" ); + private static final Component OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite_button" ); protected WidgetTerminal terminal; protected final ClientComputer computer; @@ -47,7 +47,7 @@ public abstract class ComputerScreenBase extend protected final int sidebarYOffset; - public ComputerScreenBase( T container, PlayerInventory player, Text title, int sidebarYOffset ) + public ComputerScreenBase( T container, Inventory player, Component title, int sidebarYOffset ) { super( container, player, title ); computer = (ClientComputer) container.getComputer(); @@ -61,10 +61,10 @@ public abstract class ComputerScreenBase extend protected final void init() { super.init(); - client.keyboard.setRepeatEvents( true ); + minecraft.keyboardHandler.setSendRepeatsToGui( true ); - terminal = addDrawableChild( createTerminal() ); - ComputerSidebar.addButtons( this, computer, this::addDrawableChild, x, y + sidebarYOffset ); + terminal = addRenderableWidget( createTerminal() ); + ComputerSidebar.addButtons( this, computer, this::addRenderableWidget, leftPos, topPos + sidebarYOffset ); setFocused( terminal ); } @@ -72,13 +72,13 @@ public abstract class ComputerScreenBase extend public final void removed() { super.removed(); - client.keyboard.setRepeatEvents( false ); + minecraft.keyboardHandler.setSendRepeatsToGui( false ); } @Override - public final void handledScreenTick() + public final void containerTick() { - super.handledScreenTick(); + super.containerTick(); terminal.update(); } @@ -95,11 +95,11 @@ public abstract class ComputerScreenBase extend } @Override - public final void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) + public final void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) { renderBackground( stack ); super.render( stack, mouseX, mouseY, partialTicks ); - drawMouseoverTooltip( stack, mouseX, mouseY ); + renderTooltip( stack, mouseX, mouseY ); } @Override @@ -109,13 +109,13 @@ public abstract class ComputerScreenBase extend } @Override - protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + protected void renderLabels( @Nonnull PoseStack transform, int mouseX, int mouseY ) { // Skip rendering labels. } @Override - public void filesDragged( @Nonnull List files ) + public void onFilesDrop( @Nonnull List files ) { if( files.isEmpty() ) return; @@ -145,7 +145,7 @@ public abstract class ComputerScreenBase extend String name = file.getFileName().toString(); if( name.length() > UploadFileMessage.MAX_FILE_NAME ) { - alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.name_too_long" ) ); + alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.name_too_long" ) ); return; } @@ -156,7 +156,7 @@ public abstract class ComputerScreenBase extend byte[] digest = FileUpload.getDigest( buffer ); if( digest == null ) { - alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) ); + alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.corrupted" ) ); return; } @@ -166,13 +166,13 @@ public abstract class ComputerScreenBase extend catch( IOException e ) { ComputerCraft.log.error( "Failed uploading files", e ); - alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) ); + alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) ); } } if( toUpload.size() > UploadFileMessage.MAX_FILES ) { - alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.too_many_files" ) ); + alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.too_many_files" ) ); return; } @@ -182,7 +182,7 @@ public abstract class ComputerScreenBase extend } } - public void uploadResult( UploadResult result, Text message ) + public void uploadResult( UploadResult result, Component message ) { switch( result ) { @@ -194,7 +194,7 @@ public abstract class ComputerScreenBase extend break; case CONFIRM_OVERWRITE: OptionScreen.show( - client, UploadResult.UPLOAD_OVERWRITE, message, + minecraft, UploadResult.UPLOAD_OVERWRITE, message, Arrays.asList( OptionScreen.newButton( CANCEL, b -> cancelUpload() ), OptionScreen.newButton( OVERWRITE, b -> continueUpload() ) @@ -207,21 +207,21 @@ public abstract class ComputerScreenBase extend private void continueUpload() { - if( client.currentScreen instanceof OptionScreen ) ((OptionScreen) client.currentScreen).disable(); + if( minecraft.screen instanceof OptionScreen ) ((OptionScreen) minecraft.screen).disable(); NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) ); } private void cancelUpload() { - client.setScreen( this ); + minecraft.setScreen( this ); NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) ); } - private void alert( Text title, Text message ) + private void alert( Component title, Component message ) { - OptionScreen.show( client, title, message, - Collections.singletonList( OptionScreen.newButton( OK, b -> client.setScreen( this ) ) ), - () -> client.setScreen( this ) + OptionScreen.show( minecraft, title, message, + Collections.singletonList( OptionScreen.newButton( OK, b -> minecraft.setScreen( this ) ) ), + () -> minecraft.setScreen( this ) ); } diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index b0456bd69..bb405b39b 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -12,18 +12,18 @@ import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.AffineTransformation; -import net.minecraft.util.math.Matrix4f; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.resources.ResourceLocation; import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.mojang.math.Transformation; + public final class FixedWidthFontRenderer { public static final int FONT_HEIGHT = 9; @@ -31,9 +31,9 @@ public final class FixedWidthFontRenderer public static final float WIDTH = 256.0f; public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; - private static final Matrix4f IDENTITY = AffineTransformation.identity() + private static final Matrix4f IDENTITY = Transformation.identity() .getMatrix(); - public static final Identifier FONT = new Identifier( "computercraft", "textures/gui/term_font.png" ); + public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" ); private FixedWidthFontRenderer() @@ -157,34 +157,34 @@ public final class FixedWidthFontRenderer buffer.vertex( transform, x, y, 0f ) .color( r, g, b, 1.0f ) - .texture( xStart / WIDTH, yStart / WIDTH ) - .light( light ) - .next(); + .uv( xStart / WIDTH, yStart / WIDTH ) + .uv2( light ) + .endVertex(); buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ) .color( r, g, b, 1.0f ) - .texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) - .light( light ) - .next(); + .uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) + .uv2( light ) + .endVertex(); buffer.vertex( transform, x + FONT_WIDTH, y, 0f ) .color( r, g, b, 1.0f ) - .texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) - .light( light ) - .next(); + .uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) + .uv2( light ) + .endVertex(); buffer.vertex( transform, x + FONT_WIDTH, y, 0f ) .color( r, g, b, 1.0f ) - .texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) - .light( light ) - .next(); + .uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) + .uv2( light ) + .endVertex(); buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ) .color( r, g, b, 1.0f ) - .texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) - .light( light ) - .next(); + .uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) + .uv2( light ) + .endVertex(); buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ) .color( r, g, b, 1.0f ) - .texture( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) - .light( light ) - .next(); + .uv( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) + .uv2( light ) + .endVertex(); } private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, @@ -210,28 +210,28 @@ public final class FixedWidthFontRenderer { buffer.vertex( transform, x, y, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_START, BACKGROUND_START ) - .next(); + .uv( BACKGROUND_START, BACKGROUND_START ) + .endVertex(); buffer.vertex( transform, x, y + height, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_START, BACKGROUND_END ) - .next(); + .uv( BACKGROUND_START, BACKGROUND_END ) + .endVertex(); buffer.vertex( transform, x + width, y, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_END, BACKGROUND_START ) - .next(); + .uv( BACKGROUND_END, BACKGROUND_START ) + .endVertex(); buffer.vertex( transform, x + width, y, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_END, BACKGROUND_START ) - .next(); + .uv( BACKGROUND_END, BACKGROUND_START ) + .endVertex(); buffer.vertex( transform, x, y + height, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_START, BACKGROUND_END ) - .next(); + .uv( BACKGROUND_START, BACKGROUND_END ) + .endVertex(); buffer.vertex( transform, x + width, y + height, 0 ) .color( r, g, b, 1.0f ) - .texture( BACKGROUND_END, BACKGROUND_END ) - .next(); + .uv( BACKGROUND_END, BACKGROUND_END ) + .endVertex(); } public static void drawTerminalWithoutCursor( @Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @@ -319,12 +319,12 @@ public final class FixedWidthFontRenderer public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize ) { - VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() - .getBufferBuilders() - .getEntityVertexConsumers(); + MultiBufferSource.BufferSource renderer = Minecraft.getInstance() + .renderBuffers() + .bufferSource(); VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ); drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); - renderer.draw(); + renderer.endBatch(); } public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, @@ -341,21 +341,21 @@ public final class FixedWidthFontRenderer public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) { - VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() - .getBufferBuilders() - .getEntityVertexConsumers(); + MultiBufferSource.BufferSource renderer = Minecraft.getInstance() + .renderBuffers() + .bufferSource(); drawEmptyTerminal( transform, renderer, x, y, width, height ); - renderer.draw(); + renderer.endBatch(); } - public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, + public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height ) { Colour colour = Colour.BLACK; drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); } - public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, float height ) + public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height ) { Colour colour = Colour.BLACK; drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 8d3eba876..52772c7ea 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -13,41 +13,41 @@ import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; - import javax.annotation.Nonnull; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; import static dan200.computercraft.client.render.ComputerBorderRenderer.getTexture; +import com.mojang.blaze3d.vertex.PoseStack; + public final class GuiComputer extends ComputerScreenBase { private final int termWidth; private final int termHeight; - private GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight ) + private GuiComputer( T container, Inventory player, Component title, int termWidth, int termHeight ) { super( container, player, title, BORDER ); this.termWidth = termWidth; this.termHeight = termHeight; - backgroundWidth = WidgetTerminal.getWidth( termWidth ) + BORDER * 2 + ComputerSidebar.WIDTH; - backgroundHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; + imageWidth = WidgetTerminal.getWidth( termWidth ) + BORDER * 2 + ComputerSidebar.WIDTH; + imageHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; } - public static GuiComputer create( ContainerComputerBase container, PlayerInventory inventory, Text component ) + public static GuiComputer create( ContainerComputerBase container, Inventory inventory, Component component ) { return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); } - public static GuiComputer createPocket( ContainerComputerBase container, PlayerInventory inventory, Text component ) + public static GuiComputer createPocket( ContainerComputerBase container, Inventory inventory, Component component ) { return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); } - public static GuiComputer createView( ContainerViewComputer container, PlayerInventory inventory, Text component ) + public static GuiComputer createView( ContainerViewComputer container, Inventory inventory, Component component ) { return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() ); } @@ -56,15 +56,15 @@ public final class GuiComputer extends Computer protected WidgetTerminal createTerminal() { return new WidgetTerminal( computer, - x + ComputerSidebar.WIDTH + BORDER, y + BORDER, termWidth, termHeight + leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER, termWidth, termHeight ); } @Override - public void drawBackground( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY ) + public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY ) { ComputerBorderRenderer.render( - getTexture( family ), terminal.x, terminal.y, getZOffset(), + getTexture( family ), terminal.x, terminal.y, getBlitOffset(), RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() ); - ComputerSidebar.renderBackground( stack, x, y + sidebarYOffset ); + ComputerSidebar.renderBackground( stack, leftPos, topPos + sidebarYOffset ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 0cfbc3daa..58e97f3f6 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -7,39 +7,38 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +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; -public class GuiDiskDrive extends HandledScreen +public class GuiDiskDrive extends AbstractContainerScreen { - private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/disk_drive.png" ); + private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" ); - public GuiDiskDrive( ContainerDiskDrive container, PlayerInventory player, Text title ) + public GuiDiskDrive( ContainerDiskDrive container, Inventory player, Component title ) { super( container, player, title ); } @Override - public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) { renderBackground( transform ); super.render( transform, mouseX, mouseY, partialTicks ); - drawMouseoverTooltip( transform, mouseX, mouseY ); + renderTooltip( transform, mouseX, mouseY ); } @Override - protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.setShader( GameRenderer::getPositionTexShader ); RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.setShaderTexture( 0, BACKGROUND ); - drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight ); + blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index 917a6861a..7b3be404e 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -7,42 +7,41 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; -public class GuiPrinter extends HandledScreen +public class GuiPrinter extends AbstractContainerScreen { - private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/printer.png" ); + private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" ); - public GuiPrinter( ContainerPrinter container, PlayerInventory player, Text title ) + public GuiPrinter( ContainerPrinter container, Inventory player, Component title ) { super( container, player, title ); } @Override - public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) { renderBackground( stack ); super.render( stack, mouseX, mouseY, partialTicks ); - drawMouseoverTooltip( stack, mouseX, mouseY ); + renderTooltip( stack, mouseX, mouseY ); } @Override - protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.setShaderTexture( 0, BACKGROUND ); - drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight ); + blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight ); - if( getScreenHandler().isPrinting() ) + if( getMenu().isPrinting() ) { - drawTexture( transform, x + 34, y + 21, 176, 0, 25, 45 ); + blit( transform, leftPos + 34, topPos + 21, 176, 0, 25, 45 ); } } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 2163ef355..b985cf47a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -7,24 +7,24 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.util.math.Matrix4f; import org.lwjgl.glfw.GLFW; import javax.annotation.Nonnull; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; -public class GuiPrintout extends HandledScreen +public class GuiPrintout extends AbstractContainerScreen { private final boolean book; private final int pages; @@ -32,11 +32,11 @@ public class GuiPrintout extends HandledScreen private final TextBuffer[] colours; private int page; - public GuiPrintout( ContainerHeldItem container, PlayerInventory player, Text title ) + public GuiPrintout( ContainerHeldItem container, Inventory player, Component title ) { super( container, player, title ); - backgroundHeight = Y_SIZE; + imageHeight = Y_SIZE; String[] text = ItemPrintout.getText( container.getStack() ); this.text = new TextBuffer[text.length]; @@ -89,37 +89,37 @@ public class GuiPrintout extends HandledScreen } @Override - public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) { // We must take the background further back in order to not overlap with our printed pages. - setZOffset( getZOffset() - 1 ); + setBlitOffset( getBlitOffset() - 1 ); renderBackground( stack ); - setZOffset( getZOffset() + 1 ); + setBlitOffset( getBlitOffset() + 1 ); super.render( stack, mouseX, mouseY, partialTicks ); } @Override - protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + protected void renderLabels( @Nonnull PoseStack transform, int mouseX, int mouseY ) { // Skip rendering labels. } @Override - protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw the printout RenderSystem.setShaderColor( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.enableDepthTest(); - VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() - .getBufferBuilders() - .getEntityVertexConsumers(); - Matrix4f matrix = transform.peek() - .getModel(); - drawBorder( matrix, renderer, x, y, getZOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP ); - drawText( matrix, renderer, x + X_TEXT_MARGIN, y + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours ); - renderer.draw(); + MultiBufferSource.BufferSource renderer = Minecraft.getInstance() + .renderBuffers() + .bufferSource(); + Matrix4f matrix = transform.last() + .pose(); + drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP ); + drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours ); + renderer.endBatch(); } @Override diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 56dd0b1be..4f0434b17 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -7,38 +7,37 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; import static dan200.computercraft.shared.turtle.inventory.ContainerTurtle.BORDER; public class GuiTurtle extends ComputerScreenBase { - private static final Identifier BACKGROUND_NORMAL = new Identifier( "computercraft", "textures/gui/turtle_normal.png" ); - private static final Identifier BACKGROUND_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" ); + private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); + private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" ); private static final int TEX_WIDTH = 254; private static final int TEX_HEIGHT = 217; private final ComputerFamily family; - public GuiTurtle( ContainerTurtle container, PlayerInventory player, Text title ) + public GuiTurtle( ContainerTurtle container, Inventory player, Component title ) { super( container, player, title, BORDER ); family = container.getFamily(); - backgroundWidth = TEX_WIDTH + ComputerSidebar.WIDTH; - backgroundHeight = TEX_HEIGHT; + imageWidth = TEX_WIDTH + ComputerSidebar.WIDTH; + imageHeight = TEX_HEIGHT; } @@ -46,25 +45,25 @@ public class GuiTurtle extends ComputerScreenBase protected WidgetTerminal createTerminal() { return new WidgetTerminal( - computer, x + BORDER + ComputerSidebar.WIDTH, y + BORDER, + computer, leftPos + BORDER + ComputerSidebar.WIDTH, topPos + BORDER, ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight ); } @Override - public void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + public void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) { boolean advanced = family == ComputerFamily.ADVANCED; RenderSystem.setShaderTexture( 0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - drawTexture( transform, x + ComputerSidebar.WIDTH, y, 0, 0, TEX_WIDTH, TEX_HEIGHT ); + blit( transform, leftPos + ComputerSidebar.WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT ); // Draw selection slot - int slot = getScreenHandler().getSelectedSlot(); + int slot = getMenu().getSelectedSlot(); if( slot >= 0 ) { int slotX = slot % 4; int slotY = slot / 4; - drawTexture( transform, x + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, y + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, + blit( transform, leftPos + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, topPos + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, @@ -72,6 +71,6 @@ public class GuiTurtle extends ComputerScreenBase } RenderSystem.setShaderTexture( 0, advanced ? ComputerBorderRenderer.BACKGROUND_ADVANCED : ComputerBorderRenderer.BACKGROUND_NORMAL ); - ComputerSidebar.renderBackground( transform, x, y + sidebarYOffset ); + ComputerSidebar.renderBackground( transform, leftPos, topPos + sidebarYOffset ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java index 5ea1642a5..67b720e99 100644 --- a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java +++ b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java @@ -5,29 +5,29 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.OrderedText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; import org.lwjgl.glfw.GLFW; import javax.annotation.Nonnull; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.entity.player.Inventory; import java.util.List; -public class NoTermComputerScreen extends Screen implements ScreenHandlerProvider +public class NoTermComputerScreen extends Screen implements MenuAccess { private final T menu; private WidgetTerminal terminal; - public NoTermComputerScreen( T menu, PlayerInventory player, Text title ) + public NoTermComputerScreen( T menu, Inventory player, Component title ) { super( title ); this.menu = menu; @@ -35,7 +35,7 @@ public class NoTermComputerScreen extends Scree @Nonnull @Override - public T getScreenHandler() + public T getMenu() { return menu; } @@ -44,12 +44,12 @@ public class NoTermComputerScreen extends Scree protected void init() { this.passEvents = true; - client.mouse.lockCursor(); - client.currentScreen = this; + minecraft.mouseHandler.grabMouse(); + minecraft.screen = this; super.init(); - client.keyboard.setRepeatEvents( true ); + minecraft.keyboardHandler.setSendRepeatsToGui( true ); - terminal = addSelectableChild( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) ); + terminal = addWidget( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) ); terminal.visible = false; terminal.active = false; setFocused( terminal ); @@ -59,7 +59,7 @@ public class NoTermComputerScreen extends Scree public final void removed() { super.removed(); - client.keyboard.setRepeatEvents( false ); + minecraft.keyboardHandler.setSendRepeatsToGui( false ); } @Override @@ -72,14 +72,14 @@ public class NoTermComputerScreen extends Scree @Override public boolean mouseScrolled( double pMouseX, double pMouseY, double pDelta ) { - client.player.getInventory().scrollInHotbar( pDelta ); + minecraft.player.getInventory().swapPaint( pDelta ); return super.mouseScrolled( pMouseX, pMouseY, pDelta ); } @Override public void onClose() { - client.player.closeHandledScreen(); + minecraft.player.closeContainer(); super.onClose(); } @@ -102,16 +102,16 @@ public class NoTermComputerScreen extends Scree } @Override - public void render( MatrixStack transform, int mouseX, int mouseY, float partialTicks ) + public void render( PoseStack transform, int mouseX, int mouseY, float partialTicks ) { super.render( transform, mouseX, mouseY, partialTicks ); - TextRenderer font = client.textRenderer; - List lines = font.wrapLines( new TranslatableText( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) ); + Font font = minecraft.font; + List lines = font.split( new TranslatableComponent( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) ); float y = 10.0f; - for( OrderedText line : lines ) + for( FormattedCharSequence line : lines ) { - font.drawWithShadow( transform, line, (float) ((width / 2) - (client.textRenderer.getWidth( line ) / 2)), y, 0xFFFFFF ); + font.drawShadow( transform, line, (float) ((width / 2) - (minecraft.font.width( line ) / 2)), y, 0xFFFFFF ); y += 9.0f; } } diff --git a/src/main/java/dan200/computercraft/client/gui/OptionScreen.java b/src/main/java/dan200/computercraft/client/gui/OptionScreen.java index 23de17f2a..8ecdf2d38 100644 --- a/src/main/java/dan200/computercraft/client/gui/OptionScreen.java +++ b/src/main/java/dan200/computercraft/client/gui/OptionScreen.java @@ -6,21 +6,20 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - +import com.mojang.blaze3d.vertex.PoseStack; import javax.annotation.Nonnull; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.MultiLineLabel; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import java.util.List; public final class OptionScreen extends Screen { - private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/blank_screen.png" ); + private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/blank_screen.png" ); public static final int BUTTON_WIDTH = 100; public static final int BUTTON_HEIGHT = 20; @@ -33,14 +32,14 @@ public final class OptionScreen extends Screen private int innerWidth; private int innerHeight; - private MultilineText messageRenderer; - private final Text message; - private final List buttons; + private MultiLineLabel messageRenderer; + private final Component message; + private final List buttons; private final Runnable exit; private final Screen originalScreen; - private OptionScreen( Text title, Text message, List buttons, Runnable exit, Screen originalScreen ) + private OptionScreen( Component title, Component message, List buttons, Runnable exit, Screen originalScreen ) { super( title ); this.message = message; @@ -49,9 +48,9 @@ public final class OptionScreen extends Screen this.originalScreen = originalScreen; } - public static void show( MinecraftClient client, Text title, Text message, List buttons, Runnable exit ) + public static void show( Minecraft client, Component title, Component message, List buttons, Runnable exit ) { - client.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( client.currentScreen ) ) ); + client.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( client.screen ) ) ); } public static Screen unwrap( Screen screen ) @@ -67,40 +66,40 @@ public final class OptionScreen extends Screen int buttonWidth = BUTTON_WIDTH * buttons.size() + PADDING * (buttons.size() - 1); int innerWidth = this.innerWidth = Math.max( 256, buttonWidth + PADDING * 2 ); - messageRenderer = MultilineText.create( textRenderer, message, innerWidth - PADDING * 2 ); + messageRenderer = MultiLineLabel.create( font, message, innerWidth - PADDING * 2 ); - int textHeight = messageRenderer.count() * FONT_HEIGHT + PADDING * 2; + int textHeight = messageRenderer.getLineCount() * FONT_HEIGHT + PADDING * 2; innerHeight = textHeight + (buttons.isEmpty() ? 0 : buttons.get( 0 ).getHeight()) + PADDING; x = (width - innerWidth) / 2; y = (height - innerHeight) / 2; int x = (width - buttonWidth) / 2; - for( ClickableWidget button : buttons ) + for( AbstractWidget button : buttons ) { button.x = x; button.y = y + textHeight; - addDrawableChild( button ); + addRenderableWidget( button ); x += BUTTON_WIDTH + PADDING; } } @Override - public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) { renderBackground( transform ); // Render the actual texture. RenderSystem.setShaderTexture( 0, BACKGROUND ); - drawTexture( transform, x, y, 0, 0, innerWidth, PADDING ); - drawTexture( transform, + blit( transform, x, y, 0, 0, innerWidth, PADDING ); + blit( transform, x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2, innerWidth, PADDING ); - drawTexture( transform, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING ); + blit( transform, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING ); - messageRenderer.draw( transform, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040 ); + messageRenderer.renderLeftAlignedNoShadow( transform, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040 ); super.render( transform, mouseX, mouseY, partialTicks ); } @@ -110,14 +109,14 @@ public final class OptionScreen extends Screen exit.run(); } - public static ClickableWidget newButton( Text component, ButtonWidget.PressAction clicked ) + public static AbstractWidget newButton( Component component, Button.OnPress clicked ) { - return new ButtonWidget( 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, component, clicked ); + return new Button( 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, component, clicked ); } public void disable() { - for( ClickableWidget widget : buttons ) widget.active = false; + for( AbstractWidget widget : buttons ) widget.active = false; } @Nonnull diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java index 25d87c8dc..2faf45680 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java @@ -5,26 +5,25 @@ */ package dan200.computercraft.client.gui.widgets; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.computer.core.ClientComputer; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; - import java.util.Arrays; import java.util.function.Consumer; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; /** * Registers buttons to interact with a computer. */ public final class ComputerSidebar { - private static final Identifier TEXTURE = new Identifier( ComputerCraft.MOD_ID, "textures/gui/buttons.png" ); + private static final ResourceLocation TEXTURE = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/buttons.png" ); private static final int TEX_SIZE = 64; @@ -45,7 +44,7 @@ public final class ComputerSidebar { } - public static void addButtons( Screen screen, ClientComputer computer, Consumer add, int x, int y ) + public static void addButtons( Screen screen, ClientComputer computer, Consumer add, int x, int y ) { x += CORNERS_BORDER + 1; y += CORNERS_BORDER + ICON_MARGIN; @@ -54,11 +53,11 @@ public final class ComputerSidebar screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF, TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ), () -> computer.isOn() ? Arrays.asList( - new TranslatableText( "gui.computercraft.tooltip.turn_off" ), - ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.turn_off.key" ), Formatting.GRAY ) + new TranslatableComponent( "gui.computercraft.tooltip.turn_off" ), + ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ), ChatFormatting.GRAY ) ) : Arrays.asList( - new TranslatableText( "gui.computercraft.tooltip.turn_on" ), - ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.turn_off.key" ), Formatting.GRAY ) + new TranslatableComponent( "gui.computercraft.tooltip.turn_on" ), + ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ), ChatFormatting.GRAY ) ) ) ); @@ -68,26 +67,26 @@ public final class ComputerSidebar screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF, TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ), Arrays.asList( - new TranslatableText( "gui.computercraft.tooltip.terminate" ), - ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.terminate.key" ), Formatting.GRAY ) + new TranslatableComponent( "gui.computercraft.tooltip.terminate" ), + ChatHelpers.coloured( new TranslatableComponent( "gui.computercraft.tooltip.terminate.key" ), ChatFormatting.GRAY ) ) ) ); } - public static void renderBackground( MatrixStack transform, int x, int y ) + public static void renderBackground( PoseStack transform, int x, int y ) { - Screen.drawTexture( transform, + Screen.blit( transform, x, y, 0, 102, WIDTH, FULL_BORDER, ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE ); - Screen.drawTexture( transform, + Screen.blit( transform, x, y + FULL_BORDER, WIDTH, HEIGHT - FULL_BORDER * 2, 0, 107, WIDTH, 4, ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE ); - Screen.drawTexture( transform, + Screen.blit( transform, x, y + HEIGHT - FULL_BORDER, 0, 111, WIDTH, FULL_BORDER, ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE ); diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java b/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java index 4e8751883..a2ed56dc6 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java @@ -6,37 +6,36 @@ package dan200.computercraft.client.gui.widgets; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - +import com.mojang.blaze3d.vertex.PoseStack; import javax.annotation.Nonnull; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; import java.util.List; import java.util.function.IntSupplier; import java.util.function.Supplier; /** - * Version of {@link net.minecraft.client.gui.widget.TexturedButtonWidget} which allows changing some properties + * Version of {@link net.minecraft.client.gui.components.ImageButton} which allows changing some properties * dynamically. */ -public class DynamicImageButton extends ButtonWidget +public class DynamicImageButton extends Button { private final Screen screen; - private final Identifier texture; + private final ResourceLocation texture; private final IntSupplier xTexStart; private final int yTexStart; private final int yDiffTex; private final int textureWidth; private final int textureHeight; - private final Supplier> tooltip; + private final Supplier> tooltip; public DynamicImageButton( Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex, - Identifier texture, int textureWidth, int textureHeight, - PressAction onPress, List tooltip + ResourceLocation texture, int textureWidth, int textureHeight, + OnPress onPress, List tooltip ) { this( @@ -49,11 +48,11 @@ public class DynamicImageButton extends ButtonWidget public DynamicImageButton( Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex, - Identifier texture, int textureWidth, int textureHeight, - PressAction onPress, Supplier> tooltip + ResourceLocation texture, int textureWidth, int textureHeight, + OnPress onPress, Supplier> tooltip ) { - super( x, y, width, height, LiteralText.EMPTY, onPress ); + super( x, y, width, height, TextComponent.EMPTY, onPress ); this.screen = screen; this.textureWidth = textureWidth; this.textureHeight = textureHeight; @@ -65,7 +64,7 @@ public class DynamicImageButton extends ButtonWidget } @Override - public void renderButton( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) + public void renderButton( @Nonnull PoseStack stack, int mouseX, int mouseY, float partialTicks ) { RenderSystem.setShaderTexture( 0, texture ); RenderSystem.disableDepthTest(); @@ -73,7 +72,7 @@ public class DynamicImageButton extends ButtonWidget int yTex = yTexStart; if( isHovered() ) yTex += yDiffTex; - drawTexture( stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight ); + blit( stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight ); RenderSystem.enableDepthTest(); if( isHovered() ) renderToolTip( stack, mouseX, mouseY ); @@ -81,20 +80,20 @@ public class DynamicImageButton extends ButtonWidget @Nonnull @Override - public Text getMessage() + public Component getMessage() { - List tooltip = this.tooltip.get(); - return tooltip.isEmpty() ? LiteralText.EMPTY : tooltip.get( 0 ); + List tooltip = this.tooltip.get(); + return tooltip.isEmpty() ? TextComponent.EMPTY : tooltip.get( 0 ); } // @Override - public void renderToolTip( @Nonnull MatrixStack stack, int mouseX, int mouseY ) + public void renderToolTip( @Nonnull PoseStack stack, int mouseX, int mouseY ) { - List tooltip = this.tooltip.get(); + List tooltip = this.tooltip.get(); if( !tooltip.isEmpty() ) { - screen.renderTooltip( stack, tooltip, mouseX, mouseY ); + screen.renderComponentTooltip( stack, tooltip, mouseX, mouseY ); } } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 62c3d8404..0a79ad45a 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -10,12 +10,10 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ClientComputer; import net.minecraft.SharedConstants; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.LiteralText; -import net.minecraft.util.math.Matrix4f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.network.chat.TextComponent; import org.lwjgl.glfw.GLFW; import javax.annotation.Nonnull; @@ -25,7 +23,10 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; -public class WidgetTerminal extends ClickableWidget +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; + +public class WidgetTerminal extends AbstractWidget { private static final float TERMINATE_TIME = 0.5f; @@ -49,7 +50,7 @@ public class WidgetTerminal extends ClickableWidget public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight ) { - super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, LiteralText.EMPTY ); + super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, TextComponent.EMPTY ); this.computer = computer; @@ -207,7 +208,7 @@ public class WidgetTerminal extends ClickableWidget case GLFW.GLFW_KEY_V: // Ctrl+V for paste - String clipboard = MinecraftClient.getInstance().keyboard.getClipboard(); + String clipboard = Minecraft.getInstance().keyboardHandler.getClipboard(); if( clipboard != null ) { // Clip to the first occurrence of \r or \n @@ -227,7 +228,7 @@ public class WidgetTerminal extends ClickableWidget } // Filter the string - clipboard = SharedConstants.stripInvalidChars( clipboard ); + clipboard = SharedConstants.filterText( clipboard ); if( !clipboard.isEmpty() ) { // Clip to 512 characters and queue the event @@ -346,10 +347,10 @@ public class WidgetTerminal extends ClickableWidget } @Override - public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) { if( !visible ) return; - Matrix4f matrix = transform.peek().getModel(); + Matrix4f matrix = transform.last().pose(); Terminal terminal = computer.getTerminal(); if( terminal != null ) { @@ -362,7 +363,7 @@ public class WidgetTerminal extends ClickableWidget } @Override - public void appendNarrations( NarrationMessageBuilder builder ) + public void updateNarration( NarrationElementOutput builder ) { } diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 3d22b88ef..b8791841e 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -39,12 +39,11 @@ import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry; -import net.minecraft.client.item.UnclampedModelPredicateProvider; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.item.Item; -import net.minecraft.screen.PlayerScreenHandler; -import net.minecraft.util.Identifier; - +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.Item; import java.util.function.Supplier; @Environment( EnvType.CLIENT ) @@ -73,11 +72,11 @@ public final class ComputerCraftProxyClient implements ClientModInitializer registerContainers(); // While turtles themselves are not transparent, their upgrades may be. - BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderLayer.getTranslucent() ); - BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderLayer.getTranslucent() ); + BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderType.translucent() ); + BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderType.translucent() ); // Monitors' textures have transparent fronts and so count as cutouts. - BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_NORMAL, RenderLayer.getCutout() ); - BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_ADVANCED, RenderLayer.getCutout() ); + BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_NORMAL, RenderType.cutout() ); + BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_ADVANCED, RenderType.cutout() ); // Setup TESRs BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new ); @@ -85,7 +84,7 @@ public final class ComputerCraftProxyClient implements ClientModInitializer BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new ); BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new ); - ClientSpriteRegistryCallback.event( PlayerScreenHandler.BLOCK_ATLAS_TEXTURE ) + ClientSpriteRegistryCallback.event( InventoryMenu.BLOCK_ATLAS ) .register( ClientRegistry::onTextureStitchEvent ); ModelLoadingRegistry.INSTANCE.registerModelProvider( ClientRegistry::onModelBakeEvent ); ModelLoadingRegistry.INSTANCE.registerResourceProvider( loader -> ( name, context ) -> TurtleModelLoader.INSTANCE.accepts( name ) ? @@ -127,9 +126,9 @@ public final class ComputerCraftProxyClient implements ClientModInitializer } @SafeVarargs - private static void registerItemProperty( String name, UnclampedModelPredicateProvider getter, Supplier... items ) + private static void registerItemProperty( String name, ClampedItemPropertyFunction getter, Supplier... items ) { - Identifier id = new Identifier( ComputerCraft.MOD_ID, name ); + ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, name ); for( Supplier item : items ) { FabricModelPredicateProviderRegistry.register( item.get(), id, getter ); diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index ee0a1e93a..a1d2e03df 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -6,21 +6,26 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.util.hit.HitResult; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; import net.minecraft.util.math.*; -import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; @Environment( EnvType.CLIENT ) public final class CableHighlightRenderer @@ -29,21 +34,21 @@ public final class CableHighlightRenderer { } - public static boolean drawHighlight( MatrixStack stack, VertexConsumer consumer, Entity entity, double d, double e, double f, BlockPos pos, + public static boolean drawHighlight( PoseStack stack, VertexConsumer consumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState state ) { - Camera info = MinecraftClient.getInstance().gameRenderer.getCamera(); + Camera info = Minecraft.getInstance().gameRenderer.getMainCamera(); // We only care about instances with both cable and modem. - if( state.getBlock() != ComputerCraftRegistry.ModBlocks.CABLE || state.get( BlockCable.MODEM ) - .getFacing() == null || !state.get( BlockCable.CABLE ) ) + if( state.getBlock() != ComputerCraftRegistry.ModBlocks.CABLE || state.getValue( BlockCable.MODEM ) + .getFacing() == null || !state.getValue( BlockCable.CABLE ) ) { return false; } - HitResult hitResult = MinecraftClient.getInstance().crosshairTarget; + HitResult hitResult = Minecraft.getInstance().hitResult; - Vec3d hitPos = hitResult != null ? hitResult.getPos() : new Vec3d( d, e, f ); + Vec3 hitPos = hitResult != null ? hitResult.getLocation() : new Vec3( d, e, f ); VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hitPos.subtract( pos.getX(), @@ -51,19 +56,19 @@ public final class CableHighlightRenderer pos.getZ() ) ) ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); - Vec3d cameraPos = info.getPos(); + Vec3 cameraPos = info.getPosition(); - double xOffset = pos.getX() - cameraPos.getX(); - double yOffset = pos.getY() - cameraPos.getY(); - double zOffset = pos.getZ() - cameraPos.getZ(); - Matrix4f matrix4f = stack.peek() - .getModel(); - Matrix3f normal = stack.peek().getNormal(); - shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> { + double xOffset = pos.getX() - cameraPos.x(); + double yOffset = pos.getY() - cameraPos.y(); + double zOffset = pos.getZ() - cameraPos.z(); + Matrix4f matrix4f = stack.last() + .pose(); + Matrix3f normal = stack.last().normal(); + shape.forAllEdges( ( x1, y1, z1, x2, y2, z2 ) -> { float xDelta = (float) (x2 - x1); float yDelta = (float) (y2 - y1); float zDelta = (float) (z2 - z1); - float len = MathHelper.sqrt( xDelta * xDelta + yDelta * yDelta + zDelta * zDelta ); + float len = Mth.sqrt( xDelta * xDelta + yDelta * yDelta + zDelta * zDelta ); xDelta = xDelta / len; yDelta = yDelta / len; zDelta = zDelta / len; @@ -71,11 +76,11 @@ public final class CableHighlightRenderer consumer.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) ) .color( 0, 0, 0, 0.4f ) .normal( normal, xDelta, yDelta, zDelta ) - .next(); + .endVertex(); consumer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) ) .color( 0, 0, 0, 0.4f ) .normal( normal, xDelta, yDelta, zDelta ) - .next(); + .endVertex(); } ); return true; diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java index c36acd10e..f5d85c67c 100644 --- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -5,23 +5,22 @@ */ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Matrix4f; - import javax.annotation.Nonnull; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; public class ComputerBorderRenderer { - public static final Identifier BACKGROUND_NORMAL = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); - public static final Identifier BACKGROUND_ADVANCED = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); - public static final Identifier BACKGROUND_COMMAND = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); - public static final Identifier BACKGROUND_COLOUR = new Identifier( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" ); + public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); + public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); + public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); + public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" ); /** * The margin between the terminal and its border. */ @@ -45,7 +44,7 @@ public class ComputerBorderRenderer static { - IDENTITY.loadIdentity(); + IDENTITY.setIdentity(); } private final Matrix4f transform; @@ -68,7 +67,7 @@ public class ComputerBorderRenderer @Nonnull - public static Identifier getTexture( @Nonnull ComputerFamily family ) + public static ResourceLocation getTexture( @Nonnull ComputerFamily family ) { switch( family ) { @@ -82,11 +81,11 @@ public class ComputerBorderRenderer } } - public static void render( Identifier location, int x, int y, int z, int light, int width, int height ) + public static void render( ResourceLocation location, int x, int y, int z, int light, int width, int height ) { - VertexConsumerProvider.Immediate source = VertexConsumerProvider.immediate( Tessellator.getInstance().getBuffer() ); - render( IDENTITY, source.getBuffer( RenderLayer.getText( location ) ), x, y, z, light, width, height, false, 1, 1, 1 ); - source.draw(); + MultiBufferSource.BufferSource source = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); + render( IDENTITY, source.getBuffer( RenderType.text( location ) ), x, y, z, light, width, height, false, 1, 1, 1 ); + source.endBatch(); } @@ -144,23 +143,23 @@ public class ComputerBorderRenderer { builder.vertex( transform, x, y + height, z ) .color( r, g, b, 1.0f ) - .texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) - .light( light ) - .next(); + .uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) + .uv2( light ) + .endVertex(); builder.vertex( transform, x + width, y + height, z ) .color( r, g, b, 1.0f ) - .texture( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) - .light( light ) - .next(); + .uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) + .uv2( light ) + .endVertex(); builder.vertex( transform, x + width, y, z ) .color( r, g, b, 1.0f ) - .texture( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ) - .light( light ) - .next(); + .uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ) + .uv2( light ) + .endVertex(); builder.vertex( transform, x, y, z ) .color( r, g, b, 1.0f ) - .texture( u * TEX_SCALE, v * TEX_SCALE ) - .light( light ) - .next(); + .uv( u * TEX_SCALE, v * TEX_SCALE ) + .uv2( light ) + .endVertex(); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index f1ef584c5..2e07e7148 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -6,32 +6,32 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; import dan200.computercraft.fabric.mixin.HeldItemRendererAccess; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.item.HeldItemRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; -import net.minecraft.util.Hand; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; @Environment( EnvType.CLIENT ) public abstract class ItemMapLikeRenderer { public void renderItemFirstPerson( - MatrixStack transform, VertexConsumerProvider render, int lightTexture, Hand hand, float pitch, float equipProgress, + PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) { - PlayerEntity player = MinecraftClient.getInstance().player; + Player player = Minecraft.getInstance().player; - transform.push(); - if( hand == Hand.MAIN_HAND && player.getOffHandStack().isEmpty() ) + transform.pushPose(); + if( hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty() ) { renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack ); } @@ -40,12 +40,12 @@ public abstract class ItemMapLikeRenderer renderItemFirstPersonSide( transform, render, lightTexture, - hand == Hand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(), + hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(), equipProgress, swingProgress, stack ); } - transform.pop(); + transform.popPose(); } /** @@ -59,34 +59,34 @@ public abstract class ItemMapLikeRenderer * @param swingProgress The swing progress of this item * @param stack The stack to render */ - private void renderItemFirstPersonCenter( MatrixStack transform, VertexConsumerProvider render, int combinedLight, float pitch, float equipProgress, + private void renderItemFirstPersonCenter( PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack ) { - MinecraftClient minecraft = MinecraftClient.getInstance(); - HeldItemRenderer renderer = minecraft.getHeldItemRenderer(); + Minecraft minecraft = Minecraft.getInstance(); + ItemInHandRenderer renderer = minecraft.getItemInHandRenderer(); // Setup the appropriate transformations. This is just copied from the // corresponding method in ItemRenderer. - float swingRt = MathHelper.sqrt( swingProgress ); - float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); - float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); + float swingRt = Mth.sqrt( swingProgress ); + float tX = -0.2f * Mth.sin( swingProgress * (float) Math.PI ); + float tZ = -0.4f * Mth.sin( swingRt * (float) Math.PI ); transform.translate( 0, -tX / 2, tZ ); HeldItemRendererAccess access = (HeldItemRendererAccess) renderer; float pitchAngle = access.callGetMapAngle( pitch ); transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); - transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( pitchAngle * -85.0f ) ); + transform.mulPose( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) ); if( !minecraft.player.isInvisible() ) { - transform.push(); - transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 90.0F ) ); - access.callRenderArm( transform, render, combinedLight, Arm.RIGHT ); - access.callRenderArm( transform, render, combinedLight, Arm.LEFT ); - transform.pop(); + transform.pushPose(); + transform.mulPose( Vector3f.YP.rotationDegrees( 90.0F ) ); + access.callRenderArm( transform, render, combinedLight, HumanoidArm.RIGHT ); + access.callRenderArm( transform, render, combinedLight, HumanoidArm.LEFT ); + transform.popPose(); } - float rX = MathHelper.sin( swingRt * (float) Math.PI ); - transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( rX * 20.0F ) ); + float rX = Mth.sin( swingRt * (float) Math.PI ); + transform.mulPose( Vector3f.XP.rotationDegrees( rX * 20.0F ) ); transform.scale( 2.0F, 2.0F, 2.0F ); renderItem( transform, render, stack, combinedLight ); @@ -103,39 +103,39 @@ public abstract class ItemMapLikeRenderer * @param swingProgress The swing progress of this item * @param stack The stack to render */ - private void renderItemFirstPersonSide( MatrixStack transform, VertexConsumerProvider render, int combinedLight, Arm side, float equipProgress, + private void renderItemFirstPersonSide( PoseStack transform, MultiBufferSource render, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack ) { - MinecraftClient minecraft = MinecraftClient.getInstance(); - float offset = side == Arm.RIGHT ? 1f : -1f; + Minecraft minecraft = Minecraft.getInstance(); + float offset = side == HumanoidArm.RIGHT ? 1f : -1f; transform.translate( offset * 0.125f, -0.125f, 0f ); // If the player is not invisible then render a single arm if( !minecraft.player.isInvisible() ) { - transform.push(); - transform.multiply( Vec3f.POSITIVE_Z.getDegreesQuaternion( offset * 10f ) ); - ((HeldItemRendererAccess) minecraft.getHeldItemRenderer()) + transform.pushPose(); + transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) ); + ((HeldItemRendererAccess) minecraft.getItemInHandRenderer()) .callRenderArmHoldingItem( transform, render, combinedLight, equipProgress, swingProgress, side ); - transform.pop(); + transform.popPose(); } // Setup the appropriate transformations. This is just copied from the // corresponding method in ItemRenderer. - transform.push(); + transform.pushPose(); transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); - float f1 = MathHelper.sqrt( swingProgress ); - float f2 = MathHelper.sin( f1 * (float) Math.PI ); + float f1 = Mth.sqrt( swingProgress ); + float f2 = Mth.sin( f1 * (float) Math.PI ); float f3 = -0.5f * f2; - float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); - float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); + float f4 = 0.4f * Mth.sin( f1 * ((float) Math.PI * 2f) ); + float f5 = -0.3f * Mth.sin( swingProgress * (float) Math.PI ); transform.translate( offset * f3, f4 - 0.3f * f2, f5 ); - transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( f2 * -45f ) ); - transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( offset * f2 * -30f ) ); + transform.mulPose( Vector3f.XP.rotationDegrees( f2 * -45f ) ); + transform.mulPose( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) ); renderItem( transform, render, stack, combinedLight ); - transform.pop(); + transform.popPose(); } /** @@ -146,5 +146,5 @@ public abstract class ItemMapLikeRenderer * @param stack The stack to render * @param light TODO rebase */ - protected abstract void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light ); + protected abstract void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ); } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 23982f3a9..e8057cb36 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -7,6 +7,13 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -14,13 +21,12 @@ import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Vec3f; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; @@ -38,7 +44,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer } @Override - protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light ) + protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) { ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); Terminal terminal = computer == null ? null : computer.getTerminal(); @@ -60,9 +66,9 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer // Setup various transformations. Note that these are partially adapted from the corresponding method // in ItemRenderer - transform.push(); - transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180f ) ); - transform.multiply( Vec3f.POSITIVE_Z.getDegreesQuaternion( 180f ) ); + transform.pushPose(); + transform.mulPose( Vector3f.YP.rotationDegrees( 180f ) ); + transform.mulPose( Vector3f.ZP.rotationDegrees( 180f ) ); transform.scale( 0.5f, 0.5f, 0.5f ); float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT ); @@ -74,8 +80,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer ComputerFamily family = item.getFamily(); int frameColour = item.getColour( stack ); - Matrix4f matrix = transform.peek() - .getModel(); + Matrix4f matrix = transform.last() + .pose(); renderFrame( matrix, render, family, frameColour, light, width, height ); // Render the light @@ -92,7 +98,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer matrix, render.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); - FixedWidthFontRenderer.drawBlocker( transform.peek().getModel(), render, 0, 0, width, height ); + FixedWidthFontRenderer.drawBlocker( transform.last().pose(), render, 0, 0, width, height ); } else @@ -100,23 +106,23 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height ); } - transform.pop(); + transform.popPose(); } - private static void renderFrame( Matrix4f transform, VertexConsumerProvider render, ComputerFamily family, int colour, int light, int width, int height ) + private static void renderFrame( Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height ) { RenderSystem.enableBlend(); - MinecraftClient.getInstance() + Minecraft.getInstance() .getTextureManager() - .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) ); + .bindForSetup( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) ); - Identifier texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ); + ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ); float r = ((colour >>> 16) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f; - ComputerBorderRenderer.render( transform, render.getBuffer( RenderLayer.getText( texture ) ), 0, 0, 0, light, width, height, true, r, g, b ); + ComputerBorderRenderer.render( transform, render.getBuffer( RenderType.text( texture ) ), 0, 0, 0, light, width, height, true, r, g, b ); } private static void renderLight( Matrix4f transform, int colour, int width, int height ) @@ -127,23 +133,23 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer float g = ((colour >>> 8) & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f; - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR ); + Tesselator tessellator = Tesselator.getInstance(); + BufferBuilder buffer = tessellator.getBuilder(); + buffer.begin( VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR ); buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ) .color( r, g, b, 1.0f ) - .next(); + .endVertex(); buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ) .color( r, g, b, 1.0f ) - .next(); + .endVertex(); buffer.vertex( transform, width, height + BORDER / 2.0f, 0 ) .color( r, g, b, 1.0f ) - .next(); + .endVertex(); buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 ) .color( r, g, b, 1.0f ) - .next(); + .endVertex(); - tessellator.draw(); + tessellator.end(); RenderSystem.enableTexture(); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index e432af8c3..466d043ea 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -7,11 +7,8 @@ package dan200.computercraft.client.render; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Vec3f; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.item.ItemStack; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; @@ -19,6 +16,10 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; + /** * Emulates map and item-frame rendering for printouts. */ @@ -31,16 +32,16 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer } @Override - protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light ) + protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) { - transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( 180f ) ); + transform.mulPose( Vector3f.XP.rotationDegrees( 180f ) ); transform.scale( 0.42f, 0.42f, -0.42f ); transform.translate( -0.5f, -0.48f, 0.0f ); drawPrintout( transform, render, stack, light ); } - private static void drawPrintout( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light ) + private static void drawPrintout( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) { int pages = ItemPrintout.getPageCount( stack ); boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; @@ -70,13 +71,13 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer transform.scale( scale, scale, scale ); transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); - Matrix4f matrix = transform.peek() - .getModel(); + Matrix4f matrix = transform.last() + .pose(); drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light ); drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); } - public boolean renderInFrame( MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack, int light ) + public boolean renderInFrame( PoseStack matrixStack, MultiBufferSource consumerProvider, ItemStack stack, int light ) { if( !(stack.getItem() instanceof ItemPrintout) ) { @@ -85,7 +86,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer // Move a little bit forward to ensure we're not clipping with the frame matrixStack.translate( 0.0f, 0.0f, -0.001f ); - matrixStack.multiply( Vec3f.POSITIVE_Z.getDegreesQuaternion( 180f ) ); + matrixStack.mulPose( Vector3f.ZP.rotationDegrees( 180f ) ); matrixStack.scale( 0.95f, 0.95f, -0.95f ); matrixStack.translate( -0.5f, -0.5f, 0.0f ); diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index a14ae9e07..71cb4f673 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -7,13 +7,12 @@ package dan200.computercraft.client.render; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormatElement; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Vector4f; - +import net.minecraft.client.renderer.block.model.BakedQuad; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector4f; import java.util.List; /** @@ -27,7 +26,7 @@ public final class ModelTransformer static { identity = new Matrix4f(); - identity.loadIdentity(); + identity.setIdentity(); } private ModelTransformer() @@ -36,7 +35,7 @@ public final class ModelTransformer public static void transformQuadsTo( List output, List input, Matrix4f transform ) { - transformQuadsTo( VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, output, input, transform ); + transformQuadsTo( DefaultVertexFormat.BLOCK, output, input, transform ); } public static void transformQuadsTo( VertexFormat format, List output, List input, Matrix4f transform ) @@ -56,8 +55,8 @@ public final class ModelTransformer private static BakedQuad doTransformQuad( VertexFormat format, BakedQuad quad, Matrix4f transform ) { - int[] vertexData = quad.getVertexData().clone(); - BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), quad.getSprite(), true ); + int[] vertexData = quad.getVertices().clone(); + BakedQuad copy = new BakedQuad( vertexData, -1, quad.getDirection(), quad.getSprite(), true ); int offsetBytes = 0; for( int v = 0; v < 4; ++v ) @@ -65,7 +64,7 @@ public final class ModelTransformer for( VertexFormatElement element : format.getElements() ) // For each vertex element { int start = offsetBytes / Integer.BYTES; - if( element.getType() == VertexFormatElement.Type.POSITION && element.getDataType() == VertexFormatElement.DataType.FLOAT ) // When we find a position element + if( element.getUsage() == VertexFormatElement.Usage.POSITION && element.getType() == VertexFormatElement.Type.FLOAT ) // When we find a position element { Vector4f pos = new Vector4f( Float.intBitsToFloat( vertexData[start] ), Float.intBitsToFloat( vertexData[start + 1] ), @@ -76,11 +75,11 @@ public final class ModelTransformer pos.transform( transform ); // Insert the position - vertexData[start] = Float.floatToRawIntBits( pos.getX() ); - vertexData[start + 1] = Float.floatToRawIntBits( pos.getY() ); - vertexData[start + 2] = Float.floatToRawIntBits( pos.getZ() ); + vertexData[start] = Float.floatToRawIntBits( pos.x() ); + vertexData[start + 1] = Float.floatToRawIntBits( pos.y() ); + vertexData[start + 2] = Float.floatToRawIntBits( pos.z() ); } - offsetBytes += element.getByteLength(); + offsetBytes += element.getByteSize(); } } return copy; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index d4083c67f..9b5b9fafc 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -9,17 +9,22 @@ package dan200.computercraft.client.render; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.util.math.*; -import net.minecraft.world.World; - +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; import java.util.EnumSet; -import static net.minecraft.util.math.Direction.*; +import static net.minecraft.core.Direction.*; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; /** * Overrides monitor highlighting to only render the outline of the whole monitor, rather than the current block. This means you do not get an @@ -32,15 +37,15 @@ public final class MonitorHighlightRenderer { } - public static boolean drawHighlight( MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState ) + public static boolean drawHighlight( PoseStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState ) { // Preserve normal behaviour when crouching. - if( entity.isInSneakingPose() ) + if( entity.isCrouching() ) { return false; } - World world = entity.getEntityWorld(); + Level world = entity.getCommandSenderWorld(); BlockEntity tile = world.getBlockEntity( pos ); if( !(tile instanceof TileMonitor monitor) ) @@ -71,15 +76,15 @@ public final class MonitorHighlightRenderer faces.remove( monitor.getDown() ); } - Vec3d cameraPos = MinecraftClient.getInstance().gameRenderer.getCamera() - .getPos(); - matrixStack.push(); - matrixStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); + Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera() + .getPosition(); + matrixStack.pushPose(); + matrixStack.translate( pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z() ); // I wish I could think of a better way to do this - Matrix4f transform = matrixStack.peek() - .getModel(); - Matrix3f normal = matrixStack.peek().getNormal(); + Matrix4f transform = matrixStack.last() + .pose(); + Matrix3f normal = matrixStack.last().normal(); if( faces.contains( NORTH ) || faces.contains( WEST ) ) { line( vertexConsumer, transform, normal, 0, 0, 0, UP ); @@ -129,7 +134,7 @@ public final class MonitorHighlightRenderer line( vertexConsumer, transform, normal, 1, 1, 0, SOUTH ); } - matrixStack.pop(); + matrixStack.popPose(); return true; } @@ -138,11 +143,11 @@ public final class MonitorHighlightRenderer { buffer.vertex( transform, x, y, z ) .color( 0, 0, 0, 0.4f ) - .normal( normal, direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ() ) - .next(); - buffer.vertex( transform, x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ() ) + .normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() ) + .endVertex(); + buffer.vertex( transform, x + direction.getStepX(), y + direction.getStepY(), z + direction.getStepZ() ) .color( 0, 0, 0, 0.4f ) - .normal( normal, direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ() ) - .next(); + .normal( normal, direction.getStepX(), direction.getStepY(), direction.getStepZ() ) + .endVertex(); } } diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index bd14234a0..fe6746854 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -5,40 +5,40 @@ */ package dan200.computercraft.client.render; +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.vertex.VertexFormat; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.gl.GlUniform; -import net.minecraft.client.render.Shader; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.resource.ResourceFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL13; import javax.annotation.Nullable; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.server.packs.resources.ResourceProvider; import java.io.IOException; import java.nio.FloatBuffer; -public class MonitorTextureBufferShader extends Shader +public class MonitorTextureBufferShader extends ShaderInstance { static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; private static final Logger LOGGER = LogManager.getLogger(); - private final GlUniform palette; - private final GlUniform width; - private final GlUniform height; + private final Uniform palette; + private final Uniform width; + private final Uniform height; - public MonitorTextureBufferShader( ResourceFactory factory, String name, VertexFormat format ) throws IOException + public MonitorTextureBufferShader( ResourceProvider factory, String name, VertexFormat format ) throws IOException { super( factory, name, format ); width = getUniformChecked( "Width" ); height = getUniformChecked( "Height" ); - palette = new GlUniform( "Palette", GlUniform.field_32044 /* UT_FLOAT3 */, 16 * 3, this ); + palette = new Uniform( "Palette", Uniform.UT_FLOAT3 /* UT_FLOAT3 */, 16 * 3, this ); updateUniformLocation( palette ); - GlUniform tbo = getUniformChecked( "Tbo" ); + Uniform tbo = getUniformChecked( "Tbo" ); if( tbo != null ) tbo.set( TEXTURE_INDEX - GL13.GL_TEXTURE0 ); } @@ -53,7 +53,7 @@ public class MonitorTextureBufferShader extends Shader { if( this.palette == null ) return; - FloatBuffer paletteBuffer = this.palette.getFloatData(); + FloatBuffer paletteBuffer = this.palette.getFloatBuffer(); paletteBuffer.rewind(); for( int i = 0; i < 16; i++ ) { @@ -71,9 +71,9 @@ public class MonitorTextureBufferShader extends Shader } @Override - public void bind() + public void apply() { - super.bind(); + super.apply(); palette.upload(); } @@ -84,23 +84,23 @@ public class MonitorTextureBufferShader extends Shader super.close(); } - private void updateUniformLocation( GlUniform uniform ) + private void updateUniformLocation( Uniform uniform ) { - int id = GlUniform.getUniformLocation( getProgramRef(), uniform.getName() ); + int id = Uniform.glGetUniformLocation( getId(), uniform.getName() ); if( id == -1 ) { LOGGER.warn( "Shader {} could not find uniform named {} in the specified shader program.", getName(), uniform.getName() ); } else { - uniform.setLoc( id ); + uniform.setLocation( id ); } } @Nullable - private GlUniform getUniformChecked( String name ) + private Uniform getUniformChecked( String name ) { - GlUniform uniform = getUniform( name ); + Uniform uniform = getUniform( name ); if( uniform == null ) { LOGGER.warn( "Monitor shader {} should have uniform {}, but it was not present.", getName(), name ); diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 7b8c809a5..405a9f4d2 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -9,13 +9,14 @@ package dan200.computercraft.client.render; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.util.math.Matrix4f; +import net.minecraft.client.renderer.MultiBufferSource; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; + public final class PrintoutRenderer { /** @@ -48,7 +49,7 @@ public final class PrintoutRenderer private PrintoutRenderer() {} - public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours ) + public static void drawText( Matrix4f transform, MultiBufferSource renderer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours ) { VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT ); for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) @@ -68,7 +69,7 @@ public final class PrintoutRenderer } } - public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, int light, String[] text, String[] colours ) + public static void drawText( Matrix4f transform, MultiBufferSource renderer, int x, int y, int start, int light, String[] text, String[] colours ) { VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT ); for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) @@ -88,7 +89,7 @@ public final class PrintoutRenderer } } - public static void drawBorder( Matrix4f transform, VertexConsumerProvider renderer, float x, float y, float z, int page, int pages, boolean isBook, int light ) + public static void drawBorder( Matrix4f transform, MultiBufferSource renderer, float x, float y, float z, int page, int pages, boolean isBook, int light ) { int leftPages = page; int rightPages = pages - page - 1; @@ -173,6 +174,6 @@ public final class PrintoutRenderer private static void vertex( VertexConsumer buffer, Matrix4f matrix, float x, float y, float z, float u, float v, int light ) { - buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).texture( u, v ).light( light ).next(); + buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).uv( u, v ).uv2( light ).endVertex(); } } diff --git a/src/main/java/dan200/computercraft/client/render/RenderTypes.java b/src/main/java/dan200/computercraft/client/render/RenderTypes.java index cabc1c870..6be3ae0d6 100644 --- a/src/main/java/dan200/computercraft/client/render/RenderTypes.java +++ b/src/main/java/dan200/computercraft/client/render/RenderTypes.java @@ -5,10 +5,14 @@ */ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import net.minecraft.client.render.*; -import net.minecraft.util.Identifier; - +import net.minecraft.client.renderer.RenderStateShard; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -21,17 +25,17 @@ public class RenderTypes public static MonitorTextureBufferShader monitorTboShader; @Nullable - public static Shader terminalShader; + public static ShaderInstance terminalShader; - public static final RenderLayer TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH; - public static final RenderLayer MONITOR_TBO = Types.MONITOR_TBO; - public static final RenderLayer TERMINAL_BLOCKER = Types.BLOCKER; - public static final RenderLayer TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH; - public static final RenderLayer PRINTOUT_TEXT = Types.PRINTOUT_TEXT; + public static final RenderType TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH; + public static final RenderType MONITOR_TBO = Types.MONITOR_TBO; + public static final RenderType TERMINAL_BLOCKER = Types.BLOCKER; + public static final RenderType TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH; + public static final RenderType PRINTOUT_TEXT = Types.PRINTOUT_TEXT; - public static final RenderLayer PRINTOUT_BACKGROUND = RenderLayer.getText( new Identifier( "computercraft", "textures/gui/printout.png" ) ); + public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) ); - public static final RenderLayer POSITION_COLOR = Types.POSITION_COLOR; + public static final RenderType POSITION_COLOR = Types.POSITION_COLOR; @Nonnull static MonitorTextureBufferShader getMonitorTextureBufferShader() @@ -41,72 +45,72 @@ public class RenderTypes } @Nonnull - static Shader getTerminalShader() + static ShaderInstance getTerminalShader() { if( terminalShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" ); return terminalShader; } - private static final class Types extends RenderPhase + private static final class Types extends RenderStateShard { - private static final VertexFormat.DrawMode GL_MODE = VertexFormat.DrawMode.TRIANGLES; - private static final VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE; - private static final Shader TERM_SHADER = new Shader( RenderTypes::getTerminalShader ); + private static final VertexFormat.Mode GL_MODE = VertexFormat.Mode.TRIANGLES; + private static final VertexFormat FORMAT = DefaultVertexFormat.POSITION_COLOR_TEX; + private static final ShaderStateShard TERM_SHADER = new ShaderStateShard( RenderTypes::getTerminalShader ); - private static final RenderPhase.Texture TERM_FONT_TEXTURE = new RenderPhase.Texture( + private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new RenderStateShard.TextureStateShard( FixedWidthFontRenderer.FONT, false, false // blur, minimap ); - public static final RenderLayer MONITOR_TBO = RenderLayer.of( "monitor_tbo", VertexFormats.POSITION_TEXTURE, VertexFormat.DrawMode.TRIANGLE_STRIP, 128, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .texture( TERM_FONT_TEXTURE ) // blur, minimap - .shader( new RenderPhase.Shader( RenderTypes::getMonitorTextureBufferShader ) ) - .writeMaskState( RenderLayer.ALL_MASK ) - .build( false ) ); + public static final RenderType MONITOR_TBO = RenderType.create( "monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128, false, false, // useDelegate, needsSorting + RenderType.CompositeState.builder() + .setTextureState( TERM_FONT_TEXTURE ) // blur, minimap + .setShaderState( new RenderStateShard.ShaderStateShard( RenderTypes::getMonitorTextureBufferShader ) ) + .setWriteMaskState( RenderType.COLOR_DEPTH_WRITE ) + .createCompositeState( false ) ); - static final RenderLayer TERMINAL_WITHOUT_DEPTH = RenderLayer.of( + static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create( "terminal_without_depth", FORMAT, GL_MODE, 1024, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .texture( TERM_FONT_TEXTURE ) - .shader( TERM_SHADER ) - .writeMaskState( COLOR_MASK ) - .build( false ) + RenderType.CompositeState.builder() + .setTextureState( TERM_FONT_TEXTURE ) + .setShaderState( TERM_SHADER ) + .setWriteMaskState( COLOR_WRITE ) + .createCompositeState( false ) ); - static final RenderLayer BLOCKER = RenderLayer.of( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .texture( TERM_FONT_TEXTURE ) - .shader( TERM_SHADER ) - .writeMaskState( DEPTH_MASK ) - .build( false ) ); + static final RenderType BLOCKER = RenderType.create( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting + RenderType.CompositeState.builder() + .setTextureState( TERM_FONT_TEXTURE ) + .setShaderState( TERM_SHADER ) + .setWriteMaskState( DEPTH_WRITE ) + .createCompositeState( false ) ); - static final RenderLayer TERMINAL_WITH_DEPTH = RenderLayer.of( + static final RenderType TERMINAL_WITH_DEPTH = RenderType.create( "terminal_with_depth", FORMAT, GL_MODE, 1024, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .texture( TERM_FONT_TEXTURE ) - .shader( TERM_SHADER ) - .build( false ) + RenderType.CompositeState.builder() + .setTextureState( TERM_FONT_TEXTURE ) + .setShaderState( TERM_SHADER ) + .createCompositeState( false ) ); - static final RenderLayer PRINTOUT_TEXT = RenderLayer.of( - "printout_text", VertexFormats.POSITION_COLOR_TEXTURE_LIGHT, GL_MODE, 1024, + static final RenderType PRINTOUT_TEXT = RenderType.create( + "printout_text", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, GL_MODE, 1024, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .texture( TERM_FONT_TEXTURE ) - .shader( RenderPhase.TEXT_SHADER ) - .lightmap( RenderPhase.ENABLE_LIGHTMAP ) - .build( false ) + RenderType.CompositeState.builder() + .setTextureState( TERM_FONT_TEXTURE ) + .setShaderState( RenderStateShard.RENDERTYPE_TEXT_SHADER ) + .setLightmapState( RenderStateShard.LIGHTMAP ) + .createCompositeState( false ) ); - static final RenderLayer POSITION_COLOR = RenderLayer.of( - "position_color", VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.QUADS, 128, + static final RenderType POSITION_COLOR = RenderType.create( + "position_color", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 128, false, false, // useDelegate, needsSorting - RenderLayer.MultiPhaseParameters.builder() - .shader( COLOR_SHADER ) - .build( false ) + RenderType.CompositeState.builder() + .setShaderState( POSITION_COLOR_SHADER ) + .createCompositeState( false ) ); private Types( String name, Runnable setup, Runnable destroy ) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 6c8c0ab74..b8324055a 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,6 +8,14 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexBuffer; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; @@ -18,11 +26,13 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.client.gl.VertexBuffer; import net.minecraft.client.render.*; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.util.math.*; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; @@ -32,7 +42,7 @@ import javax.annotation.Nonnull; import java.nio.ByteBuffer; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; -import static net.minecraft.client.util.GlAllocationUtils.allocateByteBuffer; +import static com.mojang.blaze3d.platform.MemoryTracker.create; public class TileEntityMonitorRenderer implements BlockEntityRenderer { @@ -40,16 +50,16 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer { - private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" ); - private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" ); - private static final ModelIdentifier COLOUR_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_colour", "inventory" ); - private static final ModelIdentifier ELF_OVERLAY_MODEL = new ModelIdentifier( "computercraft:turtle_elf_overlay", "inventory" ); + private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_normal", "inventory" ); + private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" ); + private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" ); + private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); private final Random random = new Random( 0 ); BlockEntityRenderDispatcher renderer; - public TileEntityTurtleRenderer( BlockEntityRendererFactory.Context context ) + public TileEntityTurtleRenderer( BlockEntityRendererProvider.Context context ) { - renderer = context.getRenderDispatcher(); + renderer = context.getBlockEntityRenderDispatcher(); } - public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured ) + public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured ) { switch( family ) { @@ -66,11 +65,11 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer } } - public static ModelIdentifier getTurtleOverlayModel( Identifier overlay, boolean christmas ) + public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas ) { if( overlay != null ) { - return new ModelIdentifier( overlay, "inventory" ); + return new ModelResourceLocation( overlay, "inventory" ); } if( christmas ) { @@ -80,44 +79,44 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer } @Override - public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider buffers, + public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffers, int lightmapCoord, int overlayLight ) { // Render the label String label = turtle.createProxy() .getLabel(); - HitResult hit = renderer.crosshairTarget; - if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos() + HitResult hit = renderer.cameraHitResult; + if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos() .equals( ((BlockHitResult) hit).getBlockPos() ) ) { - MinecraftClient mc = MinecraftClient.getInstance(); - TextRenderer font = mc.textRenderer; + Minecraft mc = Minecraft.getInstance(); + Font font = mc.font; - transform.push(); + transform.pushPose(); transform.translate( 0.5, 1.2, 0.5 ); - transform.multiply( mc.getEntityRenderDispatcher() - .getRotation() ); + transform.mulPose( mc.getEntityRenderDispatcher() + .cameraOrientation() ); transform.scale( -0.025f, -0.025f, 0.025f ); - Matrix4f matrix = transform.peek() - .getModel(); - int opacity = (int) (mc.options.getTextBackgroundOpacity( 0.25f ) * 255) << 24; - float width = -font.getWidth( label ) / 2.0f; - font.draw( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord ); - font.draw( label, width, (float) 0, 0xffffffff, false, matrix, buffers, false, 0, lightmapCoord ); + Matrix4f matrix = transform.last() + .pose(); + int opacity = (int) (mc.options.getBackgroundOpacity( 0.25f ) * 255) << 24; + float width = -font.width( label ) / 2.0f; + font.drawInBatch( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord ); + font.drawInBatch( label, width, (float) 0, 0xffffffff, false, matrix, buffers, false, 0, lightmapCoord ); - transform.pop(); + transform.popPose(); } - transform.push(); + transform.pushPose(); // Setup the transform. - Vec3d offset = turtle.getRenderOffset( partialTicks ); + Vec3 offset = turtle.getRenderOffset( partialTicks ); float yaw = turtle.getRenderYaw( partialTicks ); transform.translate( offset.x, offset.y, offset.z ); transform.translate( 0.5f, 0.5f, 0.5f ); - transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) ); + transform.mulPose( Vector3f.YP.rotationDegrees( 180.0f - yaw ) ); if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) { // Flip the model @@ -128,13 +127,13 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer // Render the turtle int colour = turtle.getColour(); ComputerFamily family = turtle.getFamily(); - Identifier overlay = turtle.getOverlay(); + ResourceLocation overlay = turtle.getOverlay(); - VertexConsumer buffer = buffers.getBuffer( TexturedRenderLayers.getEntityTranslucentCull() ); + VertexConsumer buffer = buffers.getBuffer( Sheets.translucentCullBlockSheet() ); renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); // Render the overlay - ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); + ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); if( overlayModel != null ) { renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); @@ -144,10 +143,10 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks ); renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks ); - transform.pop(); + transform.popPose(); } - private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, + private void renderUpgrade( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); @@ -155,32 +154,32 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer { return; } - transform.push(); + transform.pushPose(); float toolAngle = turtle.getToolRenderAngle( side, f ); transform.translate( 0.0f, 0.5f, 0.5f ); - transform.multiply( Vec3f.NEGATIVE_X.getDegreesQuaternion( toolAngle ) ); + transform.mulPose( Vector3f.XN.rotationDegrees( toolAngle ) ); transform.translate( 0.0f, -0.5f, -0.5f ); TransformedModel model = upgrade.getModel( turtle.getAccess(), side ); model.push( transform ); renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null ); - transform.pop(); + transform.popPose(); - transform.pop(); + transform.popPose(); } - private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, - ModelIdentifier modelLocation, int[] tints ) + private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, + ModelResourceLocation modelLocation, int[] tints ) { - BakedModelManager modelManager = MinecraftClient.getInstance() + ModelManager modelManager = Minecraft.getInstance() .getItemRenderer() - .getModels() + .getItemModelShaper() .getModelManager(); renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); } - private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, + private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, int[] tints ) { random.setSeed( 0 ); @@ -191,27 +190,27 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer } } - private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, + private static void renderQuads( @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, List quads, int[] tints ) { - MatrixStack.Entry matrix = transform.peek(); + PoseStack.Pose matrix = transform.last(); for( BakedQuad bakedquad : quads ) { int tint = -1; - if( tints != null && bakedquad.hasColor() ) + if( tints != null && bakedquad.isTinted() ) { - int idx = bakedquad.getColorIndex(); + int idx = bakedquad.getTintIndex(); if( idx >= 0 && idx < tints.length ) { - tint = tints[bakedquad.getColorIndex()]; + tint = tints[bakedquad.getTintIndex()]; } } float f = (float) (tint >> 16 & 255) / 255.0F; float f1 = (float) (tint >> 8 & 255) / 255.0F; float f2 = (float) (tint & 255) / 255.0F; - buffer.quad( matrix, + buffer.putBulkData( matrix, bakedquad, new float[] { 1.0F, 1.0F, 1.0F, 1.0F }, f, diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index 1882ac2bd..194f43f66 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -10,14 +10,13 @@ import com.mojang.datafixers.util.Pair; import dan200.computercraft.ComputerCraft; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.ModelBakeSettings; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.util.Identifier; - +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; import javax.annotation.Nonnull; import java.util.Arrays; import java.util.Collection; @@ -29,15 +28,15 @@ import java.util.stream.Collectors; public final class TurtleModelLoader { public static final TurtleModelLoader INSTANCE = new TurtleModelLoader(); - private static final Identifier NORMAL_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_normal" ); - private static final Identifier ADVANCED_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_advanced" ); - private static final Identifier COLOUR_TURTLE_MODEL = new Identifier( ComputerCraft.MOD_ID, "block/turtle_colour" ); + private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_normal" ); + private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_advanced" ); + private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" ); private TurtleModelLoader() { } - public boolean accepts( @Nonnull Identifier name ) + public boolean accepts( @Nonnull ResourceLocation name ) { return name.getNamespace() .equals( ComputerCraft.MOD_ID ) && (name.getPath() @@ -46,7 +45,7 @@ public final class TurtleModelLoader } @Nonnull - public UnbakedModel loadModel( @Nonnull Identifier name ) + public UnbakedModel loadModel( @Nonnull ResourceLocation name ) { if( name.getNamespace() .equals( ComputerCraft.MOD_ID ) ) @@ -65,39 +64,39 @@ public final class TurtleModelLoader private static final class TurtleModel implements UnbakedModel { - private final Identifier family; + private final ResourceLocation family; - private TurtleModel( Identifier family ) + private TurtleModel( ResourceLocation family ) { this.family = family; } @Override - public Collection getTextureDependencies( Function modelGetter, + public Collection getMaterials( Function modelGetter, Set> missingTextureErrors ) { - return getModelDependencies() + return getDependencies() .stream() .flatMap( x -> modelGetter.apply( x ) - .getTextureDependencies( modelGetter, missingTextureErrors ) + .getMaterials( modelGetter, missingTextureErrors ) .stream() ) .collect( Collectors.toSet() ); } @Nonnull @Override - public Collection getModelDependencies() + public Collection getDependencies() { return Arrays.asList( family, COLOUR_TURTLE_MODEL ); } @Override - public BakedModel bake( @Nonnull ModelLoader loader, @Nonnull Function spriteGetter, @Nonnull ModelBakeSettings state, - Identifier modelId ) + public BakedModel bake( @Nonnull ModelBakery loader, @Nonnull Function spriteGetter, @Nonnull ModelState state, + ResourceLocation modelId ) { - return new TurtleSmartItemModel( loader.getOrLoadModel( family ) + return new TurtleSmartItemModel( loader.getModel( family ) .bake( loader, spriteGetter, state, modelId ), - loader.getOrLoadModel( COLOUR_TURTLE_MODEL ) + loader.getModel( COLOUR_TURTLE_MODEL ) .bake( loader, spriteGetter, state, modelId ) ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index bc7a6e46b..9db354a9b 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -6,18 +6,17 @@ package dan200.computercraft.client.render; +import com.mojang.math.Transformation; import dan200.computercraft.api.client.TransformedModel; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.json.ModelOverrideList; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.AffineTransformation; -import net.minecraft.util.math.Direction; - +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; import javax.annotation.Nonnull; import java.util.*; @@ -26,13 +25,13 @@ public class TurtleMultiModel implements BakedModel { private final BakedModel baseModel; private final BakedModel overlayModel; - private final AffineTransformation generalTransform; + private final Transformation generalTransform; private final TransformedModel leftUpgradeModel; private final TransformedModel rightUpgradeModel; private List generalQuads = null; private final Map> faceQuads = new EnumMap<>( Direction.class ); - public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel, + public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, Transformation generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel ) { // Get the models @@ -77,14 +76,14 @@ public class TurtleMultiModel implements BakedModel } if( leftUpgradeModel != null ) { - AffineTransformation upgradeTransform = generalTransform.multiply( leftUpgradeModel.getMatrix() ); + Transformation upgradeTransform = generalTransform.compose( leftUpgradeModel.getMatrix() ); ModelTransformer.transformQuadsTo( quads, leftUpgradeModel.getModel() .getQuads( state, side, rand ), upgradeTransform.getMatrix() ); } if( rightUpgradeModel != null ) { - AffineTransformation upgradeTransform = generalTransform.multiply( rightUpgradeModel.getMatrix() ); + Transformation upgradeTransform = generalTransform.compose( rightUpgradeModel.getMatrix() ); ModelTransformer.transformQuadsTo( quads, rightUpgradeModel.getModel() .getQuads( state, side, rand ), upgradeTransform.getMatrix() ); @@ -100,43 +99,43 @@ public class TurtleMultiModel implements BakedModel } @Override - public boolean hasDepth() + public boolean isGui3d() { - return baseModel.hasDepth(); + return baseModel.isGui3d(); } @Override - public boolean isSideLit() + public boolean usesBlockLight() { - return baseModel.isSideLit(); + return baseModel.usesBlockLight(); } @Override - public boolean isBuiltin() + public boolean isCustomRenderer() { - return baseModel.isBuiltin(); + return baseModel.isCustomRenderer(); } @Nonnull @Override @Deprecated - public Sprite getParticleSprite() + public TextureAtlasSprite getParticleIcon() { - return baseModel.getParticleSprite(); + return baseModel.getParticleIcon(); } @Nonnull @Override @Deprecated - public ModelTransformation getTransformation() + public ItemTransforms getTransforms() { - return baseModel.getTransformation(); + return baseModel.getTransforms(); } @Nonnull @Override - public ModelOverrideList getOverrides() + public ItemOverrides getOverrides() { - return ModelOverrideList.EMPTY; + return ItemOverrides.EMPTY; } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java index 5b113f97a..914a5e752 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -5,31 +5,30 @@ */ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderer; -import net.minecraft.client.render.entity.EntityRendererFactory; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; public class TurtlePlayerRenderer extends EntityRenderer { //FIXME Make sure this isn't an issue. Context was EntityRenderDispatcher. - public TurtlePlayerRenderer( EntityRendererFactory.Context context ) + public TurtlePlayerRenderer( EntityRendererProvider.Context context ) { super( context ); } @Override - public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform, - @Nonnull VertexConsumerProvider buffer, int packedLightIn ) + public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull PoseStack transform, + @Nonnull MultiBufferSource buffer, int packedLightIn ) { } @Nonnull @Override - public Identifier getTexture( @Nonnull TurtlePlayer entity ) + public ResourceLocation getTexture( @Nonnull TurtlePlayer entity ) { return ComputerBorderRenderer.BACKGROUND_NORMAL; } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 077e78ad7..706d46f2d 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -6,6 +6,8 @@ package dan200.computercraft.client.render; import com.google.common.base.Objects; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Transformation; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; @@ -14,23 +16,20 @@ import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedModelManager; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.json.ModelOverrideList; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.LivingEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.AffineTransformation; -import net.minecraft.util.math.Direction; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collections; @@ -41,17 +40,17 @@ import java.util.Random; @Environment( EnvType.CLIENT ) public class TurtleSmartItemModel implements BakedModel { - private static final AffineTransformation identity, flip; + private static final Transformation identity, flip; static { - MatrixStack stack = new MatrixStack(); + PoseStack stack = new PoseStack(); stack.scale( 0, -1, 0 ); stack.translate( 0, 0, 1 ); - identity = AffineTransformation.identity(); - flip = new AffineTransformation( stack.peek() - .getModel() ); + identity = Transformation.identity(); + flip = new Transformation( stack.last() + .pose() ); } private static class TurtleModelCombination @@ -59,11 +58,11 @@ public class TurtleSmartItemModel implements BakedModel final boolean colour; final ITurtleUpgrade leftUpgrade; final ITurtleUpgrade rightUpgrade; - final Identifier overlay; + final ResourceLocation overlay; final boolean christmas; final boolean flip; - TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas, + TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip ) { this.colour = colour; @@ -109,7 +108,7 @@ public class TurtleSmartItemModel implements BakedModel private final BakedModel colourModel; private final HashMap cachedModels = new HashMap<>(); - private final ModelOverrideList overrides; + private final ItemOverrides overrides; public TurtleSmartItemModel( BakedModel familyModel, BakedModel colourModel ) { @@ -117,17 +116,17 @@ public class TurtleSmartItemModel implements BakedModel this.colourModel = colourModel; // this actually works I think, trust me - overrides = new ModelOverrideList( null, null, null, Collections.emptyList() ) + overrides = new ItemOverrides( null, null, null, Collections.emptyList() ) { @Nonnull @Override - public BakedModel apply( BakedModel originalModel, ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity, int seed ) + public BakedModel resolve( BakedModel originalModel, ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int seed ) { ItemTurtle turtle = (ItemTurtle) stack.getItem(); int colour = turtle.getColour( stack ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT ); ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT ); - Identifier overlay = turtle.getOverlay( stack ); + ResourceLocation overlay = turtle.getOverlay( stack ); boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS; String label = turtle.getLabel( stack ); boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); @@ -145,15 +144,15 @@ public class TurtleSmartItemModel implements BakedModel private BakedModel buildModel( TurtleModelCombination combo ) { - MinecraftClient mc = MinecraftClient.getInstance(); - BakedModelManager modelManager = mc.getItemRenderer() - .getModels() + Minecraft mc = Minecraft.getInstance(); + ModelManager modelManager = mc.getItemRenderer() + .getItemModelShaper() .getModelManager(); - ModelIdentifier overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas ); + ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas ); BakedModel baseModel = combo.colour ? colourModel : familyModel; BakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; - AffineTransformation transform = combo.flip ? flip : identity; + Transformation transform = combo.flip ? flip : identity; TransformedModel leftModel = combo.leftUpgrade != null ? combo.leftUpgrade.getModel( null, TurtleSide.LEFT ) : null; TransformedModel rightModel = combo.rightUpgrade != null ? combo.rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null; return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel ); @@ -174,33 +173,33 @@ public class TurtleSmartItemModel implements BakedModel } @Override - public boolean hasDepth() + public boolean isGui3d() { - return familyModel.hasDepth(); + return familyModel.isGui3d(); } @Override - public boolean isSideLit() + public boolean usesBlockLight() { - return familyModel.isSideLit(); + return familyModel.usesBlockLight(); } @Override - public boolean isBuiltin() + public boolean isCustomRenderer() { - return familyModel.isBuiltin(); + return familyModel.isCustomRenderer(); } @Override @Deprecated - public Sprite getParticleSprite() + public TextureAtlasSprite getParticleIcon() { - return familyModel.getParticleSprite(); + return familyModel.getParticleIcon(); } @Nonnull @Override - public ModelOverrideList getOverrides() + public ItemOverrides getOverrides() { return overrides; } @@ -208,9 +207,9 @@ public class TurtleSmartItemModel implements BakedModel @Nonnull @Override @Deprecated - public ModelTransformation getTransformation() + public ItemTransforms getTransforms() { - return familyModel.getTransformation(); + return familyModel.getTransforms(); } } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index dd925b324..8f8d495af 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -5,10 +5,9 @@ */ package dan200.computercraft.core.computer; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.Direction; /** * A side on a computer. Unlike {@link Direction}, this is relative to the direction the computer is diff --git a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java index 07737c4c2..b0267d5bd 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java @@ -9,9 +9,8 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.turtle.core.TurtleBrain; -import net.minecraft.block.entity.BlockEntity; - import javax.annotation.Nonnull; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index b46fc0dcd..31c81095e 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -13,15 +13,14 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.shared.util.IoUtil; -import net.minecraft.resource.ReloadableResourceManager; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceManager; -import net.minecraft.resource.SynchronousResourceReloader; -import net.minecraft.util.Identifier; -import net.minecraft.util.InvalidIdentifierException; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.ResourceLocationException; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -61,7 +60,7 @@ public final class ResourceMount implements IMount /** * Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes. */ - private static final Map> MOUNT_CACHE = new WeakHashMap<>( 2 ); + private static final Map> MOUNT_CACHE = new WeakHashMap<>( 2 ); private final String namespace; private final String subPath; @@ -72,7 +71,7 @@ public final class ResourceMount implements IMount public static ResourceMount get( String namespace, String subPath, ReloadableResourceManager manager ) { - Map cache; + Map cache; synchronized( MOUNT_CACHE ) { @@ -80,7 +79,7 @@ public final class ResourceMount implements IMount if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() ); } - Identifier path = new Identifier( namespace, subPath ); + ResourceLocation path = new ResourceLocation( namespace, subPath ); synchronized( cache ) { ResourceMount mount = cache.get( path ); @@ -104,8 +103,8 @@ public final class ResourceMount implements IMount boolean hasAny = false; String existingNamespace = null; - FileEntry newRoot = new FileEntry( new Identifier( namespace, subPath ) ); - for( Identifier file : manager.findResources( subPath, s -> true ) ) + FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) ); + for( ResourceLocation file : manager.listResources( subPath, s -> true ) ) { existingNamespace = file.getNamespace(); @@ -160,12 +159,12 @@ public final class ResourceMount implements IMount FileEntry nextEntry = lastEntry.children.get( part ); if( nextEntry == null ) { - Identifier childPath; + ResourceLocation childPath; try { - childPath = new Identifier( namespace, subPath + "/" + path ); + childPath = new ResourceLocation( namespace, subPath + "/" + path ); } - catch( InvalidIdentifierException e ) + catch( ResourceLocationException e ) { ComputerCraft.log.warn( "Cannot create resource location for {} ({})", part, e.getMessage() ); return; @@ -271,11 +270,11 @@ public final class ResourceMount implements IMount private static class FileEntry { - final Identifier identifier; + final ResourceLocation identifier; Map children; long size = -1; - FileEntry( Identifier identifier ) + FileEntry( ResourceLocation identifier ) { this.identifier = identifier; } @@ -297,7 +296,7 @@ public final class ResourceMount implements IMount * While people should really be keeping a permanent reference to this, some people construct it every * method call, so let's make this as small as possible. */ - static class Listener implements SynchronousResourceReloader + static class Listener implements ResourceManagerReloadListener { private static final Listener INSTANCE = new Listener(); @@ -305,14 +304,14 @@ public final class ResourceMount implements IMount private final Set managers = Collections.newSetFromMap( new WeakHashMap<>() ); @Override - public void reload( @Nonnull ResourceManager manager ) + public void onResourceManagerReload( @Nonnull ResourceManager manager ) { for( ResourceMount mount : mounts ) mount.load(); } synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) { - if( managers.add( manager ) ) manager.registerReloader( this ); + if( managers.add( manager ) ) manager.registerReloadListener( this ); mounts.add( mount ); } } diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 56a7dc3e2..dc0556235 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -7,10 +7,9 @@ package dan200.computercraft.core.terminal; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; - import javax.annotation.Nonnull; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; public class Terminal { @@ -310,7 +309,7 @@ public class Terminal if( onChanged != null ) onChanged.run(); } - public synchronized void write( PacketByteBuf buffer ) + public synchronized void write( FriendlyByteBuf buffer ) { buffer.writeInt( cursorX ); buffer.writeInt( cursorY ); @@ -336,7 +335,7 @@ public class Terminal palette.write( buffer ); } - public synchronized void read( PacketByteBuf buffer ) + public synchronized void read( FriendlyByteBuf buffer ) { cursorX = buffer.readInt(); cursorY = buffer.readInt(); @@ -366,7 +365,7 @@ public class Terminal setChanged(); } - public synchronized NbtCompound writeToNBT( NbtCompound nbt ) + public synchronized CompoundTag writeToNBT( CompoundTag nbt ) { nbt.putInt( "term_cursorX", cursorX ); nbt.putInt( "term_cursorY", cursorY ); @@ -384,7 +383,7 @@ public class Terminal return nbt; } - public synchronized void readFromNBT( NbtCompound nbt ) + public synchronized void readFromNBT( CompoundTag nbt ) { cursorX = nbt.getInt( "term_cursorX" ); cursorY = nbt.getInt( "term_cursorY" ); diff --git a/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java index 9d86ea657..9e5b48868 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java @@ -5,16 +5,16 @@ */ package dan200.computercraft.fabric.mixin; -import net.minecraft.client.gui.hud.ChatHud; -import net.minecraft.text.Text; +import net.minecraft.client.gui.components.ChatComponent; +import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( ChatHud.class ) +@Mixin( ChatComponent.class ) public interface ChatHudAccess { @Invoker - void callAddMessage( Text text, int messageId ); + void callAddMessage( Component text, int messageId ); @Invoker void callRemoveMessage( int messageId ); diff --git a/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java index a799fdf3a..056214624 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java @@ -5,22 +5,22 @@ */ package dan200.computercraft.fabric.mixin; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.item.HeldItemRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Arm; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.entity.HumanoidArm; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( HeldItemRenderer.class ) +@Mixin( ItemInHandRenderer.class ) public interface HeldItemRendererAccess { @Invoker float callGetMapAngle( float tickDelta ); @Invoker - void callRenderArm( MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, Arm arm ); + void callRenderArm( PoseStack matrices, MultiBufferSource vertexConsumers, int light, HumanoidArm arm ); @Invoker - void callRenderArmHoldingItem( MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, float swingProgress, Arm arm ); + void callRenderArmHoldingItem( PoseStack matrices, MultiBufferSource vertexConsumers, int light, float equipProgress, float swingProgress, HumanoidArm arm ); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java index 8ce40b911..ed063d9f3 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.fabric.mixin; -import net.minecraft.resource.ServerResourceManager; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerResources; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -14,5 +14,5 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface MinecraftServerAccess { @Accessor - ServerResourceManager getServerResourceManager(); + ServerResources getServerResourceManager(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java index 559c8faf7..3f5937fb2 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java @@ -6,14 +6,12 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.util.DropConsumer; -import net.minecraft.block.Block; -import net.minecraft.entity.ItemEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - import java.util.function.Supplier; - +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -23,7 +21,7 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; /** * Captures block drops. * - * @see Block#dropStack(World, BlockPos, ItemStack) + * @see Block#popResource(Level, BlockPos, ItemStack) */ @Mixin( Block.class ) public class MixinBlock @@ -35,9 +33,9 @@ public class MixinBlock ), locals = LocalCapture.CAPTURE_FAILSOFT, cancellable = true ) - private static void dropStack( World world, Supplier itemEntitySupplier, ItemStack stack, CallbackInfo callbackInfo, ItemEntity itemEntity ) + private static void dropStack( Level world, Supplier itemEntitySupplier, ItemStack stack, CallbackInfo callbackInfo, ItemEntity itemEntity ) { - if( DropConsumer.onHarvestDrops( world, itemEntity.getBlockPos(), stack ) ) + if( DropConsumer.onHarvestDrops( world, itemEntity.blockPosition(), stack ) ) { callbackInfo.cancel(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java index 5bb1671b9..c6ea58992 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java @@ -6,9 +6,9 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.util.DropConsumer; -import net.minecraft.entity.Entity; -import net.minecraft.entity.ItemEntity; -import net.minecraft.item.ItemStack; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -17,7 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Captures entities. * - * @see Entity#dropStack(ItemStack, float) + * @see Entity#spawnAtLocation(ItemStack, float) */ @Mixin( Entity.class ) public class MixinEntity diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java index 7bb875fc3..85563c4ac 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java @@ -6,13 +6,10 @@ package dan200.computercraft.fabric.mixin; +import com.mojang.blaze3d.shaders.Program; import com.mojang.datafixers.util.Pair; import dan200.computercraft.client.render.MonitorTextureBufferShader; import dan200.computercraft.client.render.RenderTypes; -import net.minecraft.client.gl.Program; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Shader; -import net.minecraft.resource.ResourceManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -22,22 +19,25 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.io.IOException; import java.util.List; import java.util.function.Consumer; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.server.packs.resources.ResourceManager; @Mixin( GameRenderer.class ) public class MixinGameRenderer { @Inject( method = "loadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT ) - private void loadShaders( ResourceManager manager, CallbackInfo info, List list, List>> list2 ) throws IOException + private void loadShaders( ResourceManager manager, CallbackInfo info, List list, List>> list2 ) throws IOException { - list2.add( Pair.of( new Shader( + list2.add( Pair.of( new ShaderInstance( manager, "terminal", - RenderTypes.TERMINAL_WITHOUT_DEPTH.getVertexFormat() + RenderTypes.TERMINAL_WITHOUT_DEPTH.format() ), shader -> RenderTypes.terminalShader = shader ) ); list2.add( Pair.of( new MonitorTextureBufferShader( manager, "monitor_tbo", - RenderTypes.MONITOR_TBO.getVertexFormat() + RenderTypes.MONITOR_TBO.format() ), shader -> RenderTypes.monitorTboShader = (MonitorTextureBufferShader) shader ) ); } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java index 34eca48ca..f716eabd2 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java @@ -6,20 +6,20 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.client.gui.widgets.WidgetTerminal; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.text.Text; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.inventory.AbstractContainerMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin( HandledScreen.class ) -public class MixinHandledScreen extends Screen +@Mixin( AbstractContainerScreen.class ) +public class MixinHandledScreen extends Screen { - protected MixinHandledScreen( Text title ) + protected MixinHandledScreen( Component title ) { super( title ); } @@ -27,7 +27,7 @@ public class MixinHandledScreen extends Screen @Inject( method = "mouseReleased", at = @At ( "HEAD" ) ) public void mouseReleased( double mouseX, double mouseY, int button, CallbackInfoReturnable cir ) { - for ( Element child : this.children() ) + for ( GuiEventListener child : this.children() ) { if ( child instanceof WidgetTerminal ) { diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java index 4573b1bd2..f521182c5 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java @@ -5,32 +5,32 @@ */ package dan200.computercraft.fabric.mixin; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.client.render.ItemPocketRenderer; import dan200.computercraft.client.render.ItemPrintoutRenderer; import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.item.HeldItemRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; -import net.minecraft.util.Hand; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin( HeldItemRenderer.class ) +@Mixin( ItemInHandRenderer.class ) @Environment( EnvType.CLIENT ) public class MixinHeldItemRenderer { @Shadow - private void renderArmHoldingItem( MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, float swingProgress, - Arm arm ) + private void renderArmHoldingItem( PoseStack matrices, MultiBufferSource vertexConsumers, int light, float equipProgress, float swingProgress, + HumanoidArm arm ) { } @@ -46,8 +46,8 @@ public class MixinHeldItemRenderer at = @At( "HEAD" ), cancellable = true ) public void renderFirstPersonItem( - AbstractClientPlayerEntity player, float var2, float pitch, Hand hand, float swingProgress, - ItemStack stack, float equipProgress, MatrixStack matrixStack, VertexConsumerProvider provider, int light, + AbstractClientPlayer player, float var2, float pitch, InteractionHand hand, float swingProgress, + ItemStack stack, float equipProgress, PoseStack matrixStack, MultiBufferSource provider, int light, CallbackInfo callback ) { diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java index 92ba04c51..5fe83f6a1 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java @@ -5,22 +5,22 @@ */ package dan200.computercraft.fabric.mixin; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.client.render.ItemPrintoutRenderer; import dan200.computercraft.shared.media.items.ItemPrintout; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.ItemFrameEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.decoration.ItemFrameEntity; -import net.minecraft.item.ItemStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemFrameRenderer; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin( ItemFrameEntityRenderer.class ) +@Mixin( ItemFrameRenderer.class ) @Environment( EnvType.CLIENT ) public class MixinItemFrameEntityRenderer { @@ -34,17 +34,17 @@ public class MixinItemFrameEntityRenderer ), cancellable = true ) private void renderItem( - ItemFrameEntity itemFrameEntity, float f, float g, MatrixStack matrixStack, - VertexConsumerProvider vertexConsumerProvider, int itemFrameEntityLight, CallbackInfo info + ItemFrame itemFrameEntity, float f, float g, PoseStack matrixStack, + MultiBufferSource vertexConsumerProvider, int itemFrameEntityLight, CallbackInfo info ) { - ItemStack stack = itemFrameEntity.getHeldItemStack(); + ItemStack stack = itemFrameEntity.getItem(); if( stack.getItem() instanceof ItemPrintout ) { int light = itemFrameEntity.getType() == EntityType.GLOW_ITEM_FRAME ? 0xf000d2 : itemFrameEntityLight; // See getLightVal. ItemPrintoutRenderer.INSTANCE.renderInFrame( matrixStack, vertexConsumerProvider, stack, light ); // TODO: need to find how to make if statement instead return, like it doing Forge - matrixStack.pop(); + matrixStack.popPose(); info.cancel(); } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java index cd053439c..1e5723e6d 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java @@ -10,7 +10,7 @@ import com.google.common.collect.ImmutableMap; import com.google.gson.JsonParseException; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.util.Language; +import net.minecraft.locale.Language; import org.apache.logging.log4j.Logger; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java index 247151863..38b36449c 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.fabric.mixin; +import com.mojang.math.Matrix4f; import dan200.computercraft.fabric.mixininterface.IMatrix4f; -import net.minecraft.util.math.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java index 8539fc6b9..30a5f2919 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java @@ -7,15 +7,15 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.fabric.events.ClientUnloadWorldEvent; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.multiplayer.ClientLevel; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin( MinecraftClient.class ) +@Mixin( Minecraft.class ) public abstract class MixinMinecraftClient { @Inject( method = "render", at = @At( "HEAD" ) ) @@ -31,7 +31,7 @@ public abstract class MixinMinecraftClient } @Inject( method = "joinWorld", at = @At( "RETURN" ) ) - private void joinWorldAfter( ClientWorld world, CallbackInfo info ) + private void joinWorldAfter( ClientLevel world, CallbackInfo info ) { ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinScreen.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinScreen.java index d53ba9939..d06ce67dd 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinScreen.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinScreen.java @@ -8,7 +8,7 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.command.ClientCommands; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screens.Screen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java index c714c2346..227a62e57 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java @@ -6,35 +6,35 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.ComputerCraftRegistry; -import net.minecraft.advancement.criterion.Criteria; -import net.minecraft.block.BlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.network.ServerPlayerInteractionManager; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin( ServerPlayerInteractionManager.class ) +@Mixin( ServerPlayerGameMode.class ) public class MixinServerPlayerInteractionManager { @Inject( at = @At( value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;copy()Lnet/minecraft/item/ItemStack;", ordinal = 0 ), method = "interactBlock(Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", cancellable = true ) - private void interact( ServerPlayerEntity player, World world, ItemStack stack, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir ) + private void interact( ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable cir ) { BlockPos pos = hitResult.getBlockPos(); BlockState state = world.getBlockState( pos ); - if( player.getMainHandStack().getItem() == ComputerCraftRegistry.ModItems.DISK && state.getBlock() == ComputerCraftRegistry.ModBlocks.DISK_DRIVE ) + if( player.getMainHandItem().getItem() == ComputerCraftRegistry.ModItems.DISK && state.getBlock() == ComputerCraftRegistry.ModBlocks.DISK_DRIVE ) { - ActionResult actionResult = state.onUse( world, player, hand, hitResult ); - if( actionResult.isAccepted() ) + InteractionResult actionResult = state.use( world, player, hand, hitResult ); + if( actionResult.consumesAction() ) { - Criteria.ITEM_USED_ON_BLOCK.trigger( player, pos, stack ); + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger( player, pos, stack ); cir.setReturnValue( actionResult ); } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java index 8d1d79e37..7a0255f5f 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java @@ -6,8 +6,8 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.util.DropConsumer; -import net.minecraft.entity.Entity; -import net.minecraft.server.world.ServerWorld; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,9 +16,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Captures item stacks spawned into the world. * - * @see ServerWorld#spawnEntity(Entity) + * @see ServerLevel#addFreshEntity(Entity) */ -@Mixin( ServerWorld.class ) +@Mixin( ServerLevel.class ) public class MixinServerWorld { @Inject( method = "spawnEntity", at = @At( "HEAD" ), cancellable = true ) diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java index be1e1a8ba..b2e72057f 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java @@ -6,9 +6,6 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -16,6 +13,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.Collection; /** @@ -23,7 +23,7 @@ import java.util.Collection; * * Forge does this, this is just a bodge to get Fabric in line with that behaviour. */ -@Mixin( World.class ) +@Mixin( Level.class ) public class MixinWorld { @Shadow @@ -38,7 +38,7 @@ public class MixinWorld @Inject( method = "addBlockEntity", at = @At( "HEAD" ) ) public void addBlockEntity( @Nullable BlockEntity entity, CallbackInfo info ) { - if( entity != null && !entity.isRemoved() && this.isInBuildLimit( entity.getPos() ) && iteratingTickingBlockEntities ) + if( entity != null && !entity.isRemoved() && this.isInBuildLimit( entity.getBlockPos() ) && iteratingTickingBlockEntities ) { setWorld( entity, this ); } @@ -46,9 +46,9 @@ public class MixinWorld private static void setWorld( BlockEntity entity, Object world ) { - if( entity.getWorld() != world && entity instanceof TileGeneric ) + if( entity.getLevel() != world && entity instanceof TileGeneric ) { - entity.setWorld( (World) world ); + entity.setLevel( (Level) world ); } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java index fc16eb218..d88bab4eb 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java @@ -5,27 +5,27 @@ */ package dan200.computercraft.fabric.mixin; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import dan200.computercraft.client.render.CableHighlightRenderer; import dan200.computercraft.client.render.MonitorHighlightRenderer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin( WorldRenderer.class ) +@Mixin( LevelRenderer.class ) @Environment( EnvType.CLIENT ) public class MixinWorldRenderer { @Inject( method = "drawBlockOutline", cancellable = true, at = @At( "HEAD" ) ) - public void drawBlockOutline( MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, + public void drawBlockOutline( PoseStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, BlockState blockState, CallbackInfo info ) { if( CableHighlightRenderer.drawHighlight( matrixStack, diff --git a/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java index 10e381803..979211e8b 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.fabric.mixin; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.SignBlockEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -14,5 +14,5 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface SignBlockEntityAccess { @Accessor - Text[] getTexts(); + Component[] getTexts(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java index fcaff65cf..d706e3545 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java @@ -5,15 +5,15 @@ */ package dan200.computercraft.fabric.mixin; -import net.minecraft.util.WorldSavePath; +import net.minecraft.world.level.storage.LevelResource; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( WorldSavePath.class ) +@Mixin( LevelResource.class ) public interface WorldSavePathAccess { @Invoker( "" ) - static WorldSavePath createWorldSavePath( String relativePath ) + static LevelResource createWorldSavePath( String relativePath ) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index 656ffafab..9e9eebf64 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -9,11 +9,10 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; import java.util.ArrayList; import java.util.Objects; @@ -29,20 +28,20 @@ public final class BundledRedstone if( !providers.contains( provider ) ) providers.add( provider ); } - public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public static int getDefaultOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) { - return world.isInBuildLimit( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; + return world.isInWorldBounds( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; } - public static int getOutput( World world, BlockPos pos, Direction side ) + public static int getOutput( Level world, BlockPos pos, Direction side ) { int signal = getUnmaskedOutput( world, pos, side ); return signal >= 0 ? signal : 0; } - private static int getUnmaskedOutput( World world, BlockPos pos, Direction side ) + private static int getUnmaskedOutput( Level world, BlockPos pos, Direction side ) { - if( !world.isInBuildLimit( pos ) ) + if( !world.isInWorldBounds( pos ) ) { return -1; } diff --git a/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java b/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java index f1cda3e78..9aaef9b57 100644 --- a/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java +++ b/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java @@ -51,24 +51,28 @@ import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityT import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.block.*; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.SpawnGroup; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.Items; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.sound.BlockSoundGroup; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; - +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; import java.util.function.BiFunction; -import static net.minecraft.util.registry.Registry.BLOCK_ENTITY_TYPE; +import static net.minecraft.core.Registry.BLOCK_ENTITY_TYPE; public final class ComputerCraftRegistry { @@ -122,10 +126,10 @@ public final class ComputerCraftRegistry { //return FabricBlockSettings.copyOf(Blocks.GLASS) // .strength(2); - return AbstractBlock.Settings.of( Material.GLASS ) + return BlockBehaviour.Properties.of( Material.GLASS ) .strength( 2F ) - .sounds( BlockSoundGroup.STONE ) - .nonOpaque(); + .sound( SoundType.STONE ) + .noOcclusion(); } private static Block.Settings turtleProperties() @@ -144,7 +148,7 @@ public final class ComputerCraftRegistry public static T register( String id, T value ) { - return Registry.register( Registry.BLOCK, new Identifier( MOD_ID, id ), value ); + return Registry.register( Registry.BLOCK, new ResourceLocation( MOD_ID, id ), value ); } } @@ -194,7 +198,7 @@ public final class ComputerCraftRegistry { BlockEntityType blockEntityType = FabricBlockEntityTypeBuilder.create( factory::apply, block ).build(); return Registry.register( BLOCK_ENTITY_TYPE, - new Identifier( MOD_ID, id ), + new ResourceLocation( MOD_ID, id ), blockEntityType ); } @@ -202,22 +206,22 @@ public final class ComputerCraftRegistry public static final class ModItems { - private static final ItemGroup mainItemGroup = ComputerCraft.MAIN_GROUP; + private static final CreativeModeTab mainItemGroup = ComputerCraft.MAIN_GROUP; public static final ItemComputer COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL, ItemComputer::new ); public static final ItemComputer COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED, ItemComputer::new ); public static final ItemComputer COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND, ItemComputer::new ); public static final ItemPocketComputer POCKET_COMPUTER_NORMAL = register( "pocket_computer_normal", - new ItemPocketComputer( properties().maxCount( 1 ), ComputerFamily.NORMAL ) ); + new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.NORMAL ) ); public static final ItemPocketComputer POCKET_COMPUTER_ADVANCED = register( "pocket_computer_advanced", - new ItemPocketComputer( properties().maxCount( 1 ), + new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.ADVANCED ) ); public static final ItemTurtle TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL, ItemTurtle::new ); public static final ItemTurtle TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED, ItemTurtle::new ); - public static final ItemDisk DISK = register( "disk", new ItemDisk( properties().maxCount( 1 ) ) ); - public static final ItemTreasureDisk TREASURE_DISK = register( "treasure_disk", new ItemTreasureDisk( properties().maxCount( 1 ) ) ); - public static final ItemPrintout PRINTED_PAGE = register( "printed_page", new ItemPrintout( properties().maxCount( 1 ), ItemPrintout.Type.PAGE ) ); - public static final ItemPrintout PRINTED_PAGES = register( "printed_pages", new ItemPrintout( properties().maxCount( 1 ), ItemPrintout.Type.PAGES ) ); - public static final ItemPrintout PRINTED_BOOK = register( "printed_book", new ItemPrintout( properties().maxCount( 1 ), ItemPrintout.Type.BOOK ) ); + public static final ItemDisk DISK = register( "disk", new ItemDisk( properties().stacksTo( 1 ) ) ); + public static final ItemTreasureDisk TREASURE_DISK = register( "treasure_disk", new ItemTreasureDisk( properties().stacksTo( 1 ) ) ); + public static final ItemPrintout PRINTED_PAGE = register( "printed_page", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGE ) ); + public static final ItemPrintout PRINTED_PAGES = register( "printed_pages", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGES ) ); + public static final ItemPrintout PRINTED_BOOK = register( "printed_book", new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.BOOK ) ); public static final BlockItem SPEAKER = ofBlock( ModBlocks.SPEAKER, BlockItem::new ); public static final BlockItem DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, BlockItem::new ); public static final BlockItem PRINTER = ofBlock( ModBlocks.PRINTER, BlockItem::new ); @@ -229,29 +233,29 @@ public final class ComputerCraftRegistry public static final ItemBlockCable.Cable CABLE = register( "cable", new ItemBlockCable.Cable( ModBlocks.CABLE, properties() ) ); public static final ItemBlockCable.WiredModem WIRED_MODEM = register( "wired_modem", new ItemBlockCable.WiredModem( ModBlocks.CABLE, properties() ) ); - private static I ofBlock( B parent, BiFunction supplier ) + private static I ofBlock( B parent, BiFunction supplier ) { - return Registry.register( Registry.ITEM, Registry.BLOCK.getId( parent ), supplier.apply( parent, properties() ) ); + return Registry.register( Registry.ITEM, Registry.BLOCK.getKey( parent ), supplier.apply( parent, properties() ) ); } - private static Item.Settings properties() + private static Item.Properties properties() { - return new Item.Settings().group( mainItemGroup ); + return new Item.Properties().tab( mainItemGroup ); } private static T register( String id, T item ) { - return Registry.register( Registry.ITEM, new Identifier( MOD_ID, id ), item ); + return Registry.register( Registry.ITEM, new ResourceLocation( MOD_ID, id ), item ); } } public static class ModEntities { public static final EntityType TURTLE_PLAYER = Registry.register( Registry.ENTITY_TYPE, - new Identifier( MOD_ID, "turtle_player" ), - EntityType.Builder.create( SpawnGroup.MISC ).disableSaving() - .disableSummon() - .setDimensions( + new ResourceLocation( MOD_ID, "turtle_player" ), + EntityType.Builder.createNothing( MobCategory.MISC ).noSave() + .noSummon() + .sized( 0, 0 ) .build( @@ -260,36 +264,36 @@ public final class ComputerCraftRegistry public static class ModContainers { - public static final ScreenHandlerType COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); - public static final ScreenHandlerType POCKET_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); - public static final ScreenHandlerType POCKET_COMPUTER_NO_TERM = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); - public static final ScreenHandlerType TURTLE = ContainerData.toType( new Identifier( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new ); - public static final ScreenHandlerType DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new ); - public static final ScreenHandlerType PRINTER = registerSimple( "printer", ContainerPrinter::new ); - public static final ScreenHandlerType PRINTOUT = ContainerData.toType( new Identifier( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout ); - public static final ScreenHandlerType VIEW_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new ); + public static final MenuType COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); + public static final MenuType POCKET_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); + public static final MenuType POCKET_COMPUTER_NO_TERM = ContainerData.toType( new ResourceLocation( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new ); + public static final MenuType TURTLE = ContainerData.toType( new ResourceLocation( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new ); + public static final MenuType DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new ); + public static final MenuType PRINTER = registerSimple( "printer", ContainerPrinter::new ); + public static final MenuType PRINTOUT = ContainerData.toType( new ResourceLocation( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout ); + public static final MenuType VIEW_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new ); - private static ScreenHandlerType registerSimple( String id, + private static MenuType registerSimple( String id, ScreenHandlerRegistry.SimpleClientHandlerFactory function ) { - return ScreenHandlerRegistry.registerSimple( new Identifier( MOD_ID, id ), function ); + return ScreenHandlerRegistry.registerSimple( new ResourceLocation( MOD_ID, id ), function ); } } public static final class TurtleUpgrades { - public static TurtleModem wirelessModemNormal = new TurtleModem( false, new Identifier( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ); - public static TurtleModem wirelessModemAdvanced = new TurtleModem( true, new Identifier( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ); - public static TurtleSpeaker speaker = new TurtleSpeaker( new Identifier( ComputerCraft.MOD_ID, "speaker" ) ); + public static TurtleModem wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ); + public static TurtleModem wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ); + public static TurtleSpeaker speaker = new TurtleSpeaker( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ); - public static TurtleCraftingTable craftingTable = new TurtleCraftingTable( new Identifier( "minecraft", "crafting_table" ) ); - public static TurtleSword diamondSword = new TurtleSword( new Identifier( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD ); - public static TurtleShovel diamondShovel = new TurtleShovel( new Identifier( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL ); - public static TurtleTool diamondPickaxe = new TurtleTool( new Identifier( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE ); - public static TurtleAxe diamondAxe = new TurtleAxe( new Identifier( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE ); - public static TurtleHoe diamondHoe = new TurtleHoe( new Identifier( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE ); + public static TurtleCraftingTable craftingTable = new TurtleCraftingTable( new ResourceLocation( "minecraft", "crafting_table" ) ); + public static TurtleSword diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD ); + public static TurtleShovel diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL ); + public static TurtleTool diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE ); + public static TurtleAxe diamondAxe = new TurtleAxe( new ResourceLocation( "minecraft", "diamond_axe" ), Items.DIAMOND_AXE ); + public static TurtleHoe diamondHoe = new TurtleHoe( new ResourceLocation( "minecraft", "diamond_hoe" ), Items.DIAMOND_HOE ); - public static TurtleTool netheritePickaxe = new TurtleTool( new Identifier( "minecraft", "netherite_pickaxe" ), Items.NETHERITE_PICKAXE ); + public static TurtleTool netheritePickaxe = new TurtleTool( new ResourceLocation( "minecraft", "netherite_pickaxe" ), Items.NETHERITE_PICKAXE ); public static void registerTurtleUpgrades() { diff --git a/src/main/java/dan200/computercraft/shared/MediaProviders.java b/src/main/java/dan200/computercraft/shared/MediaProviders.java index a76eef0be..9ec54354d 100644 --- a/src/main/java/dan200/computercraft/shared/MediaProviders.java +++ b/src/main/java/dan200/computercraft/shared/MediaProviders.java @@ -9,9 +9,8 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 4cab4a12a..3bc7570b7 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -10,12 +10,11 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Objects; @@ -33,13 +32,13 @@ public final class Peripherals } @Nullable - public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side ) + public static IPeripheral getPeripheral( Level world, BlockPos pos, Direction side ) { - return world.isInBuildLimit( pos ) && !world.isClient ? getPeripheralAt( world, pos, side ) : null; + return world.isInWorldBounds( pos ) && !world.isClientSide ? getPeripheralAt( world, pos, side ) : null; } @Nullable - private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side ) + private static IPeripheral getPeripheralAt( Level world, BlockPos pos, Direction side ) { // Try the handlers in order: for( IPeripheralProvider peripheralProvider : providers ) diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index 0c5820bea..249e493a6 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -9,9 +9,8 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Util; - +import net.minecraft.Util; +import net.minecraft.world.item.ItemStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; @@ -19,7 +18,7 @@ import java.util.*; public final class PocketUpgrades { private static final Map upgrades = new HashMap<>(); - private static final Map upgradeOwners = new Object2ObjectLinkedOpenCustomHashMap<>( Util.identityHashStrategy() ); + private static final Map upgradeOwners = new Object2ObjectLinkedOpenCustomHashMap<>( Util.identityStrategy() ); private PocketUpgrades() {} diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 19d336d06..38659c400 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -5,21 +5,21 @@ */ package dan200.computercraft.shared; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.core.BlockPos; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; public final class TurtlePermissions { - public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player ) + public static boolean isBlockEnterable( Level world, BlockPos pos, Player player ) { MinecraftServer server = world.getServer(); - return server == null || world.isClient || world instanceof ServerWorld && !server.isSpawnProtected( (ServerWorld) world, pos, player ); + return server == null || world.isClientSide || world instanceof ServerLevel && !server.isUnderSpawnProtection( (ServerLevel) world, pos, player ); } - public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) + public static boolean isBlockEditable( Level world, BlockPos pos, Player player ) { return isBlockEnterable( world, pos, player ); } diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index f59b40577..6b3e7ae62 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -8,10 +8,9 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.item.ItemStack; import java.util.*; import java.util.stream.Stream; diff --git a/src/main/java/dan200/computercraft/shared/command/ClientCommands.java b/src/main/java/dan200/computercraft/shared/command/ClientCommands.java index 6845f2815..0bfdc4205 100644 --- a/src/main/java/dan200/computercraft/shared/command/ClientCommands.java +++ b/src/main/java/dan200/computercraft/shared/command/ClientCommands.java @@ -6,9 +6,8 @@ package dan200.computercraft.shared.command; import dan200.computercraft.shared.util.IDAssigner; -import net.minecraft.util.Util; - import java.io.File; +import net.minecraft.Util; /** * Basic client-side commands. @@ -42,7 +41,7 @@ public final class ClientCommands File file = new File( IDAssigner.getDir(), "computer/" + id ); if( !file.isDirectory() ) return true; - Util.getOperatingSystem().open( file ); + Util.getPlatform().openFile( file ); return true; } return false; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index c225b7c59..9808d6345 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -23,21 +23,20 @@ import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.network.container.ViewComputerContainerData; import dan200.computercraft.shared.util.IDAssigner; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.Level; import javax.annotation.Nonnull; import java.io.File; import java.util.*; @@ -52,7 +51,7 @@ import static dan200.computercraft.shared.command.builder.CommandBuilder.args; import static dan200.computercraft.shared.command.builder.CommandBuilder.command; import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice; import static dan200.computercraft.shared.command.text.ChatHelpers.*; -import static net.minecraft.server.command.CommandManager.literal; +import static net.minecraft.commands.Commands.literal; public final class CommandComputerCraft { @@ -66,7 +65,7 @@ public final class CommandComputerCraft { } - public static void register( CommandDispatcher dispatcher, Boolean dedicated ) + public static void register( CommandDispatcher dispatcher, Boolean dedicated ) { dispatcher.register( choice( "computercraft" ) .then( literal( "dump" ) @@ -74,17 +73,17 @@ public final class CommandComputerCraft .executes( context -> { TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" ); - ServerCommandSource source = context.getSource(); + CommandSourceStack source = context.getSource(); List computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); // Unless we're on a server, limit the number of rows we can send. - World world = source.getWorld(); + Level world = source.getLevel(); BlockPos pos = new BlockPos( source.getPosition() ); computers.sort( ( a, b ) -> { if( a.getWorld() == b.getWorld() && a.getWorld() == world ) { - return Double.compare( a.getPosition().getSquaredDistance( pos ), b.getPosition().getSquaredDistance( pos ) ); + return Double.compare( a.getPosition().distSqr( pos ), b.getPosition().distSqr( pos ) ); } else if( a.getWorld() == world ) { @@ -148,7 +147,7 @@ public final class CommandComputerCraft if( computer.isOn() ) shutdown++; computer.shutdown(); } - context.getSource().sendFeedback( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false ); + context.getSource().sendSuccess( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false ); return shutdown; } ) ) @@ -162,7 +161,7 @@ public final class CommandComputerCraft if( !computer.isOn() ) on++; computer.turnOn(); } - context.getSource().sendFeedback( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false ); + context.getSource().sendSuccess( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false ); return on; } ) ) @@ -171,25 +170,25 @@ public final class CommandComputerCraft .arg( "computer", oneComputer() ) .executes( context -> { ServerComputer computer = getComputerArgument( context, "computer" ); - World world = computer.getWorld(); + Level world = computer.getWorld(); BlockPos pos = computer.getPosition(); if( world == null || pos == null ) throw TP_NOT_THERE.create(); - Entity entity = context.getSource().getEntityOrThrow(); - if( !(entity instanceof ServerPlayerEntity) ) throw TP_NOT_PLAYER.create(); + Entity entity = context.getSource().getEntityOrException(); + if( !(entity instanceof ServerPlayer) ) throw TP_NOT_PLAYER.create(); - ServerPlayerEntity player = (ServerPlayerEntity) entity; - if( player.getEntityWorld() == world ) + ServerPlayer player = (ServerPlayer) entity; + if( player.getCommandSenderWorld() == world ) { - player.networkHandler.requestTeleport( + player.connection.teleport( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0, - EnumSet.noneOf( PlayerPositionLookS2CPacket.Flag.class ) + EnumSet.noneOf( ClientboundPlayerPositionPacket.RelativeArgument.class ) ); } else { - player.teleport( (ServerWorld) world, + player.teleportTo( (ServerLevel) world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0 ); } @@ -222,28 +221,28 @@ public final class CommandComputerCraft .requires( UserLevel.OP ) .arg( "computer", oneComputer() ) .executes( context -> { - ServerPlayerEntity player = context.getSource().getPlayer(); + ServerPlayer player = context.getSource().getPlayerOrException(); ServerComputer computer = getComputerArgument( context, "computer" ); computer.sendTerminalState( player ); ViewComputerContainerData container = new ViewComputerContainerData( computer ); container.open( player, new ExtendedScreenHandlerFactory() { @Override - public void writeScreenOpeningData( ServerPlayerEntity player, PacketByteBuf buf ) + public void writeScreenOpeningData( ServerPlayer player, FriendlyByteBuf buf ) { container.toBytes( buf ); } @Nonnull @Override - public MutableText getDisplayName() + public MutableComponent getDisplayName() { - return new TranslatableText( "gui.computercraft.view_computer" ); + return new TranslatableComponent( "gui.computercraft.view_computer" ); } @Nonnull @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory player, @Nonnull Player entity ) { return new ContainerViewComputer( id, player, computer ); } @@ -258,7 +257,7 @@ public final class CommandComputerCraft getTimingContext( context.getSource() ).start(); String stopCommand = "/computercraft track stop"; - context.getSource().sendFeedback( translate( "commands.computercraft.track.start.stop", + context.getSource().sendSuccess( translate( "commands.computercraft.track.start.stop", link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ), false ); return 1; } ) ) @@ -292,9 +291,9 @@ public final class CommandComputerCraft ); } - private static MutableText linkComputer( ServerCommandSource source, ServerComputer serverComputer, int computerId ) + private static MutableComponent linkComputer( CommandSourceStack source, ServerComputer serverComputer, int computerId ) { - MutableText out = new LiteralText( "" ); + MutableComponent out = new TextComponent( "" ); // Append the computer instance if( serverComputer == null ) @@ -333,14 +332,14 @@ public final class CommandComputerCraft if( UserLevel.OWNER.test( source ) && isPlayer( source ) ) { - MutableText linkPath = linkStorage( computerId ); + MutableComponent linkPath = linkStorage( computerId ); if( linkPath != null ) out.append( " " ).append( linkPath ); } return out; } - private static MutableText linkPosition( ServerCommandSource context, ServerComputer computer ) + private static MutableComponent linkPosition( CommandSourceStack context, ServerComputer computer ) { if( UserLevel.OP.test( context ) ) { @@ -356,7 +355,7 @@ public final class CommandComputerCraft } } - private static MutableText linkStorage( int id ) + private static MutableComponent linkStorage( int id ) { File file = new File( IDAssigner.getDir(), "computer/" + id ); if( !file.isDirectory() ) return null; @@ -369,20 +368,20 @@ public final class CommandComputerCraft } @Nonnull - private static TrackingContext getTimingContext( ServerCommandSource source ) + private static TrackingContext getTimingContext( CommandSourceStack source ) { Entity entity = source.getEntity(); - return entity instanceof PlayerEntity ? Tracking.getContext( entity.getUuid() ) : Tracking.getContext( SYSTEM_UUID ); + return entity instanceof Player ? Tracking.getContext( entity.getUUID() ) : Tracking.getContext( SYSTEM_UUID ); } private static final List DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME ); - private static int displayTimings( ServerCommandSource source, TrackingField sortField, List fields ) throws CommandSyntaxException + private static int displayTimings( CommandSourceStack source, TrackingField sortField, List fields ) throws CommandSyntaxException { return displayTimings( source, getTimingContext( source ).getTimings(), sortField, fields ); } - private static int displayTimings( ServerCommandSource source, @Nonnull List timings, @Nonnull TrackingField sortField, @Nonnull List fields ) throws CommandSyntaxException + private static int displayTimings( CommandSourceStack source, @Nonnull List timings, @Nonnull TrackingField sortField, @Nonnull List fields ) throws CommandSyntaxException { if( timings.isEmpty() ) throw NO_TIMINGS_EXCEPTION.create(); @@ -398,7 +397,7 @@ public final class CommandComputerCraft timings.sort( Comparator.comparing( x -> x.get( sortField ) ).reversed() ); - MutableText[] headers = new MutableText[1 + fields.size()]; + MutableComponent[] headers = new MutableComponent[1 + fields.size()]; headers[0] = translate( "commands.computercraft.track.dump.computer" ); for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() ); TableBuilder table = new TableBuilder( TRACK_ID, headers ); @@ -408,9 +407,9 @@ public final class CommandComputerCraft Computer computer = entry.getComputer(); ServerComputer serverComputer = computer == null ? null : lookup.get( computer ); - MutableText computerComponent = linkComputer( source, serverComputer, entry.getComputerId() ); + MutableComponent computerComponent = linkComputer( source, serverComputer, entry.getComputerId() ); - MutableText[] row = new MutableText[1 + fields.size()]; + MutableComponent[] row = new MutableComponent[1 + fields.size()]; row[0] = computerComponent; for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) ); table.row( row ); diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index d64a7935d..322339ebc 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -10,42 +10,41 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dan200.computercraft.api.turtle.FakePlayer; -import net.minecraft.command.CommandSource; -import net.minecraft.entity.Entity; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; - import java.util.Arrays; import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.function.Function; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; public final class CommandUtils { private CommandUtils() {} - public static boolean isPlayer( ServerCommandSource output ) + public static boolean isPlayer( CommandSourceStack output ) { Entity sender = output.getEntity(); - return sender instanceof ServerPlayerEntity && !(sender instanceof FakePlayer) && ((ServerPlayerEntity) sender).networkHandler != null; + return sender instanceof ServerPlayer && !(sender instanceof FakePlayer) && ((ServerPlayer) sender).connection != null; } @SuppressWarnings( "unchecked" ) public static CompletableFuture suggestOnServer( CommandContext context, SuggestionsBuilder builder, - Function, CompletableFuture> supplier ) + Function, CompletableFuture> supplier ) { Object source = context.getSource(); - if( !(source instanceof CommandSource) ) + if( !(source instanceof SharedSuggestionProvider) ) { return Suggestions.empty(); } - else if( source instanceof ServerCommandSource ) + else if( source instanceof CommandSourceStack ) { - return supplier.apply( (CommandContext) context ); + return supplier.apply( (CommandContext) context ); } else { - return ((CommandSource) source).getCompletions( (CommandContext) context, builder ); + return ((SharedSuggestionProvider) source).customSuggestion( (CommandContext) context, builder ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java index 88f173093..bf077b239 100644 --- a/src/main/java/dan200/computercraft/shared/command/Exceptions.java +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared.command; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import net.minecraft.text.TranslatableText; +import net.minecraft.network.chat.TranslatableComponent; public final class Exceptions { @@ -25,16 +25,16 @@ public final class Exceptions private static SimpleCommandExceptionType translated( String key ) { - return new SimpleCommandExceptionType( new TranslatableText( key ) ); + return new SimpleCommandExceptionType( new TranslatableComponent( key ) ); } private static DynamicCommandExceptionType translated1( String key ) { - return new DynamicCommandExceptionType( x -> new TranslatableText( key, x ) ); + return new DynamicCommandExceptionType( x -> new TranslatableComponent( key, x ) ); } private static Dynamic2CommandExceptionType translated2( String key ) { - return new Dynamic2CommandExceptionType( ( x, y ) -> new TranslatableText( key, x, y ) ); + return new Dynamic2CommandExceptionType( ( x, y ) -> new TranslatableComponent( key, x, y ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 1f24c7a82..3aa86dc1a 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -5,17 +5,16 @@ */ package dan200.computercraft.shared.command; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.ServerCommandSource; - +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import java.util.function.Predicate; /** * The level a user must be at in order to execute a command. */ -public enum UserLevel implements Predicate +public enum UserLevel implements Predicate { /** * Only can be used by the owner of the server: namely the server console or the player in SSP. @@ -53,20 +52,20 @@ public enum UserLevel implements Predicate } @Override - public boolean test( ServerCommandSource source ) + public boolean test( CommandSourceStack source ) { if( this == ANYONE ) return true; if( this == OWNER ) return isOwner( source ); if( this == OWNER_OP && isOwner( source ) ) return true; - return source.hasPermissionLevel( toLevel() ); + return source.hasPermission( toLevel() ); } - private static boolean isOwner( ServerCommandSource source ) + private static boolean isOwner( CommandSourceStack source ) { MinecraftServer server = source.getServer(); Entity sender = source.getEntity(); - return server.isDedicated() - ? source.getEntity() == null && source.hasPermissionLevel( 4 ) && source.getName().equals( "Server" ) - : sender instanceof PlayerEntity && ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ); + return server.isDedicatedServer() + ? source.getEntity() == null && source.hasPermission( 4 ) && source.getTextName().equals( "Server" ) + : sender instanceof Player && ((Player) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java index a8520734d..afacc524e 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -8,33 +8,33 @@ package dan200.computercraft.shared.command.arguments; import com.mojang.brigadier.arguments.ArgumentType; import dan200.computercraft.ComputerCraft; -import net.minecraft.command.argument.ArgumentTypes; -import net.minecraft.command.argument.serialize.ArgumentSerializer; -import net.minecraft.command.argument.serialize.ConstantArgumentSerializer; -import net.minecraft.util.Identifier; +import net.minecraft.commands.synchronization.ArgumentSerializer; +import net.minecraft.commands.synchronization.ArgumentTypes; +import net.minecraft.commands.synchronization.EmptyArgumentSerializer; +import net.minecraft.resources.ResourceLocation; public final class ArgumentSerializers { public static void register() { - register( new Identifier( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() ); - register( new Identifier( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() ); - register( new Identifier( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() ); - registerUnsafe( new Identifier( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() ); + register( new ResourceLocation( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() ); + register( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() ); + register( new ResourceLocation( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() ); + registerUnsafe( new ResourceLocation( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() ); } - private static > void register( Identifier id, T instance ) + private static > void register( ResourceLocation id, T instance ) { - registerUnsafe( id, instance.getClass(), new ConstantArgumentSerializer<>( () -> instance ) ); + registerUnsafe( id, instance.getClass(), new EmptyArgumentSerializer<>( () -> instance ) ); } - private static > void register( Identifier id, Class type, ArgumentSerializer serializer ) + private static > void register( ResourceLocation id, Class type, ArgumentSerializer serializer ) { ArgumentTypes.register( id.toString(), type, serializer ); } @SuppressWarnings( "unchecked" ) - private static > void registerUnsafe( Identifier id, Class type, ArgumentSerializer serializer ) + private static > void registerUnsafe( ResourceLocation id, Class type, ArgumentSerializer serializer ) { ArgumentTypes.register( id.toString(), type, (ArgumentSerializer) serializer ); } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java index 06840b154..c8cd4f668 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java @@ -14,10 +14,9 @@ import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dan200.computercraft.shared.command.arguments.ComputersArgumentType.ComputersSupplier; import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.server.command.ServerCommandSource; - import java.util.Collection; import java.util.concurrent.CompletableFuture; +import net.minecraft.commands.CommandSourceStack; import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_MANY; @@ -34,7 +33,7 @@ public final class ComputerArgumentType implements ArgumentType context, String name ) throws CommandSyntaxException + public static ServerComputer getComputerArgument( CommandContext context, String name ) throws CommandSyntaxException { return context.getArgument( name, ComputerSupplier.class ) .unwrap( context.getSource() ); @@ -98,6 +97,6 @@ public final class ComputerArgumentType implements ArgumentType getComputersArgument( CommandContext context, String name ) throws CommandSyntaxException + public static Collection getComputersArgument( CommandContext context, String name ) throws CommandSyntaxException { return context.getArgument( name, ComputersSupplier.class ) .unwrap( context.getSource() ); } - public static Set unwrap( ServerCommandSource source, Collection suppliers ) throws CommandSyntaxException + public static Set unwrap( CommandSourceStack source, Collection suppliers ) throws CommandSyntaxException { Set computers = new HashSet<>(); for( ComputersSupplier supplier : suppliers ) @@ -188,21 +187,21 @@ public final class ComputersArgumentType implements ArgumentType unwrap( ServerCommandSource source ) throws CommandSyntaxException; + Collection unwrap( CommandSourceStack source ) throws CommandSyntaxException; } public static class Serializer implements ArgumentSerializer { @Override - public void toPacket( @Nonnull ComputersArgumentType arg, @Nonnull PacketByteBuf buf ) + public void toPacket( @Nonnull ComputersArgumentType arg, @Nonnull FriendlyByteBuf buf ) { buf.writeBoolean( arg.requireSome ); } @Nonnull @Override - public ComputersArgumentType fromPacket( @Nonnull PacketByteBuf buf ) + public ComputersArgumentType deserializeFromNetwork( @Nonnull FriendlyByteBuf buf ) { return buf.readBoolean() ? SOME : MANY; } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java index d38c6b51c..2b8d2f7f4 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -15,13 +15,12 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.command.argument.ArgumentTypes; -import net.minecraft.command.argument.serialize.ArgumentSerializer; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; - import javax.annotation.Nonnull; +import net.minecraft.commands.synchronization.ArgumentSerializer; +import net.minecraft.commands.synchronization.ArgumentTypes; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -138,11 +137,11 @@ public final class RepeatArgumentType implements ArgumentType> public static class Serializer implements ArgumentSerializer> { @Override - public void toPacket( @Nonnull RepeatArgumentType arg, @Nonnull PacketByteBuf buf ) + public void toPacket( @Nonnull RepeatArgumentType arg, @Nonnull FriendlyByteBuf buf ) { buf.writeBoolean( arg.flatten ); - ArgumentTypes.toPacket( buf, arg.child ); - buf.writeText( getMessage( arg ) ); + ArgumentTypes.serialize( buf, arg.child ); + buf.writeComponent( getMessage( arg ) ); } @Nonnull @@ -151,11 +150,11 @@ public final class RepeatArgumentType implements ArgumentType> "unchecked", "rawtypes" } ) - public RepeatArgumentType fromPacket( @Nonnull PacketByteBuf buf ) + public RepeatArgumentType deserializeFromNetwork( @Nonnull FriendlyByteBuf buf ) { boolean isList = buf.readBoolean(); - ArgumentType child = ArgumentTypes.fromPacket( buf ); - Text message = buf.readText(); + ArgumentType child = ArgumentTypes.deserialize( buf ); + Component message = buf.readComponent(); BiConsumer, ?> appender = isList ? ( list, x ) -> list.addAll( (Collection) x ) : List::add; return new RepeatArgumentType( child, appender, isList, new SimpleCommandExceptionType( message ) ); } @@ -165,18 +164,18 @@ public final class RepeatArgumentType implements ArgumentType> { json.addProperty( "flatten", arg.flatten ); json.addProperty( "child", "<>" ); // TODO: Potentially serialize this using reflection. - json.addProperty( "error", Text.Serializer.toJson( getMessage( arg ) ) ); + json.addProperty( "error", Component.Serializer.toJson( getMessage( arg ) ) ); } - private static Text getMessage( RepeatArgumentType arg ) + private static Component getMessage( RepeatArgumentType arg ) { Message message = arg.some.create() .getRawMessage(); - if( message instanceof Text ) + if( message instanceof Component ) { - return (Text) message; + return (Component) message; } - return new LiteralText( message.getString() ); + return new TextComponent( message.getString() ); } } } diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java index 72233bd69..d4d779c60 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -13,13 +13,12 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import dan200.computercraft.shared.command.arguments.RepeatArgumentType; -import net.minecraft.server.command.ServerCommandSource; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Predicate; import java.util.function.Supplier; +import net.minecraft.commands.CommandSourceStack; import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED; import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal; @@ -34,14 +33,14 @@ public class CommandBuilder implements CommandNodeBuilder> private List> args = new ArrayList<>(); private Predicate requires; - public static CommandBuilder args() + public static CommandBuilder args() { return new CommandBuilder<>(); } - public static CommandBuilder command( String literal ) + public static CommandBuilder command( String literal ) { - CommandBuilder builder = new CommandBuilder<>(); + CommandBuilder builder = new CommandBuilder<>(); builder.args.add( literal( literal ) ); return builder; } diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index c7bd1248e..9ec64900b 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -13,14 +13,13 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - import javax.annotation.Nonnull; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; import java.util.ArrayList; import java.util.Collection; @@ -31,11 +30,11 @@ import static dan200.computercraft.shared.command.text.ChatHelpers.translate; * An alternative to {@link LiteralArgumentBuilder} which also provides a {@code /... help} command, and defaults to that command when no arguments are * given. */ -public final class HelpingArgumentBuilder extends LiteralArgumentBuilder +public final class HelpingArgumentBuilder extends LiteralArgumentBuilder { - private static final Formatting HEADER = Formatting.LIGHT_PURPLE; - private static final Formatting SYNOPSIS = Formatting.AQUA; - private static final Formatting NAME = Formatting.GREEN; + private static final ChatFormatting HEADER = ChatFormatting.LIGHT_PURPLE; + private static final ChatFormatting SYNOPSIS = ChatFormatting.AQUA; + private static final ChatFormatting NAME = ChatFormatting.GREEN; private final Collection children = new ArrayList<>(); private HelpingArgumentBuilder( String literal ) @@ -48,11 +47,11 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder helpForChild( CommandNode node, String id, String command ) + private static Command helpForChild( CommandNode node, String id, String command ) { return context -> { context.getSource() - .sendFeedback( getHelp( context, + .sendSuccess( getHelp( context, node, id + "." + node.getName() .replace( '-', '_' ), @@ -61,28 +60,28 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder context, CommandNode node, String id, String command ) + private static Component getHelp( CommandContext context, CommandNode node, String id, String command ) { // An ugly hack to extract usage information from the dispatcher. We generate a temporary node, generate // the shorthand usage, and emit that. - CommandDispatcher dispatcher = context.getSource() + CommandDispatcher dispatcher = context.getSource() .getServer() - .getCommandManager() + .getCommands() .getDispatcher(); - CommandNode temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false ); + CommandNode temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false ); temp.addChild( node ); String usage = dispatcher.getSmartUsage( temp, context.getSource() ) .get( node ) .substring( node.getName() .length() ); - MutableText output = new LiteralText( "" ).append( coloured( "/" + command + usage, HEADER ) ) + MutableComponent output = new TextComponent( "" ).append( coloured( "/" + command + usage, HEADER ) ) .append( " " ) .append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) ) .append( "\n" ) .append( translate( "commands." + id + ".desc" ) ); - for( CommandNode child : node.getChildren() ) + for( CommandNode child : node.getChildren() ) { if( !child.getRequirement() .test( context.getSource() ) || !(child instanceof LiteralCommandNode) ) @@ -92,7 +91,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder then( final ArgumentBuilder argument ) + public LiteralArgumentBuilder then( final ArgumentBuilder argument ) { if( getRedirect() != null ) { @@ -129,7 +128,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder then( CommandNode argument ) + public LiteralArgumentBuilder then( CommandNode argument ) { if( !(argument instanceof LiteralCommandNode) ) { @@ -139,33 +138,33 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder executes( final Command command ) + public LiteralArgumentBuilder executes( final Command command ) { throw new IllegalStateException( "Cannot use executes on a HelpingArgumentBuilder" ); } @Override - public LiteralCommandNode build() + public LiteralCommandNode build() { return buildImpl( getLiteral().replace( '-', '_' ), getLiteral() ); } - private LiteralCommandNode build( @Nonnull String id, @Nonnull String command ) + private LiteralCommandNode build( @Nonnull String id, @Nonnull String command ) { return buildImpl( id + "." + getLiteral().replace( '-', '_' ), command + " " + getLiteral() ); } - private LiteralCommandNode buildImpl( String id, String command ) + private LiteralCommandNode buildImpl( String id, String command ) { HelpCommand helpCommand = new HelpCommand( id, command ); - LiteralCommandNode node = new LiteralCommandNode<>( getLiteral(), + LiteralCommandNode node = new LiteralCommandNode<>( getLiteral(), helpCommand, getRequirement(), getRedirect(), getRedirectModifier(), isFork() ); helpCommand.node = node; // Set up a /... help command - LiteralArgumentBuilder helpNode = - LiteralArgumentBuilder.literal( "help" ).requires( x -> getArguments().stream() + LiteralArgumentBuilder helpNode = + LiteralArgumentBuilder.literal( "help" ).requires( x -> getArguments().stream() .anyMatch( y -> y.getRequirement() .test( @@ -173,11 +172,11 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder child : getArguments() ) + for( CommandNode child : getArguments() ) { node.addChild( child ); - helpNode.then( LiteralArgumentBuilder.literal( child.getName() ).requires( child.getRequirement() ) + helpNode.then( LiteralArgumentBuilder.literal( child.getName() ).requires( child.getRequirement() ) .executes( helpForChild( child, id, command ) ) .build() ); } @@ -185,9 +184,9 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder child = childBuilder.build( id, command ); + LiteralCommandNode child = childBuilder.build( id, command ); node.addChild( child ); - helpNode.then( LiteralArgumentBuilder.literal( child.getName() ).requires( child.getRequirement() ) + helpNode.then( LiteralArgumentBuilder.literal( child.getName() ).requires( child.getRequirement() ) .executes( helpForChild( child, id, command ) ) .redirect( child.getChild( "help" ) ) .build() ); @@ -198,11 +197,11 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder + private static final class HelpCommand implements Command { private final String id; private final String command; - LiteralCommandNode node; + LiteralCommandNode node; private HelpCommand( String id, String command ) { @@ -211,10 +210,10 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder context ) + public int run( CommandContext context ) { context.getSource() - .sendFeedback( getHelp( context, node, id, command ), false ); + .sendSuccess( getHelp( context, node, id, command ), false ); return 0; } } diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index 03a8deae0..470f38618 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -5,80 +5,86 @@ */ package dan200.computercraft.shared.command.text; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.text.*; -import net.minecraft.util.Formatting; -import net.minecraft.util.math.BlockPos; /** * Various helpers for building chat messages. */ public final class ChatHelpers { - private static final Formatting HEADER = Formatting.LIGHT_PURPLE; + private static final ChatFormatting HEADER = ChatFormatting.LIGHT_PURPLE; private ChatHelpers() {} - public static MutableText coloured( String text, Formatting colour ) + public static MutableComponent coloured( String text, ChatFormatting colour ) { - MutableText component = new LiteralText( text == null ? "" : text ); + MutableComponent component = new TextComponent( text == null ? "" : text ); component.setStyle( component.getStyle().withColor( colour ) ); return component; } - public static T coloured( T component, Formatting colour ) + public static T coloured( T component, ChatFormatting colour ) { component.setStyle( component.getStyle().withColor( colour ) ); return component; } - public static MutableText text( String text ) + public static MutableComponent text( String text ) { - return new LiteralText( text == null ? "" : text ); + return new TextComponent( text == null ? "" : text ); } - public static MutableText translate( String text ) + public static MutableComponent translate( String text ) { - return new TranslatableText( text == null ? "" : text ); + return new TranslatableComponent( text == null ? "" : text ); } - public static MutableText translate( String text, Object... args ) + public static MutableComponent translate( String text, Object... args ) { - return new TranslatableText( text == null ? "" : text, args ); + return new TranslatableComponent( text == null ? "" : text, args ); } - public static MutableText list( MutableText... children ) + public static MutableComponent list( MutableComponent... children ) { - MutableText component = new LiteralText( "" ); - for( MutableText child : children ) + MutableComponent component = new TextComponent( "" ); + for( MutableComponent child : children ) { component.append( child ); } return component; } - public static MutableText position( BlockPos pos ) + public static MutableComponent position( BlockPos pos ) { if( pos == null ) return translate( "commands.computercraft.generic.no_position" ); return translate( "commands.computercraft.generic.position", pos.getX(), pos.getY(), pos.getZ() ); } - public static MutableText bool( boolean value ) + public static MutableComponent bool( boolean value ) { return value - ? coloured( translate( "commands.computercraft.generic.yes" ), Formatting.GREEN ) - : coloured( translate( "commands.computercraft.generic.no" ), Formatting.RED ); + ? coloured( translate( "commands.computercraft.generic.yes" ), ChatFormatting.GREEN ) + : coloured( translate( "commands.computercraft.generic.no" ), ChatFormatting.RED ); } - public static MutableText link( MutableText component, String command, MutableText toolTip ) + public static MutableComponent link( MutableComponent component, String command, MutableComponent toolTip ) { return link( component, new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ), toolTip ); } - public static MutableText link( MutableText component, ClickEvent click, MutableText toolTip ) + public static MutableComponent link( MutableComponent component, ClickEvent click, MutableComponent toolTip ) { Style style = component.getStyle(); - if( style.getColor() == null ) style = style.withColor( Formatting.YELLOW ); + if( style.getColor() == null ) style = style.withColor( ChatFormatting.YELLOW ); style = style.withClickEvent( click ); style = style.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); @@ -87,17 +93,17 @@ public final class ChatHelpers return component; } - public static MutableText header( String text ) + public static MutableComponent header( String text ) { return coloured( text, HEADER ); } - public static MutableText copy( String text ) + public static MutableComponent copy( String text ) { - LiteralText name = new LiteralText( text ); + TextComponent name = new TextComponent( text ); name.setStyle( name.getStyle() .withClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) ) - .withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslatableText( "gui.computercraft.tooltip.copy" ) ) ) ); + .withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslatableComponent( "gui.computercraft.tooltip.copy" ) ) ) ); return name; } } diff --git a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java index fe8ee5b7c..61e9e2b41 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java @@ -6,32 +6,32 @@ package dan200.computercraft.shared.command.text; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; public class ServerTableFormatter implements TableFormatter { - private final ServerCommandSource source; + private final CommandSourceStack source; - public ServerTableFormatter( ServerCommandSource source ) + public ServerTableFormatter( CommandSourceStack source ) { this.source = source; } @Override @Nullable - public Text getPadding( Text component, int width ) + public Component getPadding( Component component, int width ) { int extraWidth = width - getWidth( component ); if( extraWidth <= 0 ) { return null; } - return new LiteralText( StringUtils.repeat( ' ', extraWidth ) ); + return new TextComponent( StringUtils.repeat( ' ', extraWidth ) ); } @Override @@ -41,15 +41,15 @@ public class ServerTableFormatter implements TableFormatter } @Override - public int getWidth( Text component ) + public int getWidth( Component component ) { return component.getString() .length(); } @Override - public void writeLine( int id, Text component ) + public void writeLine( int id, Component component ) { - source.sendFeedback( component, false ); + source.sendSuccess( component, false ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index c65c58294..5808311dd 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -9,24 +9,23 @@ package dan200.computercraft.shared.command.text; import dan200.computercraft.shared.command.CommandUtils; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.ChatTableClientMessage; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import java.util.ArrayList; import java.util.List; public class TableBuilder { private final int id; - private final Text[] headers; - private final ArrayList rows = new ArrayList<>(); + private final Component[] headers; + private final ArrayList rows = new ArrayList<>(); private int columns = -1; private int additional; - public TableBuilder( int id, @Nonnull Text... headers ) + public TableBuilder( int id, @Nonnull Component... headers ) { if( id < 0 ) { @@ -54,7 +53,7 @@ public class TableBuilder throw new IllegalArgumentException( "ID must be positive" ); } this.id = id; - this.headers = new Text[headers.length]; + this.headers = new Component[headers.length]; columns = headers.length; for( int i = 0; i < headers.length; i++ ) @@ -63,7 +62,7 @@ public class TableBuilder } } - public void row( @Nonnull Text... row ) + public void row( @Nonnull Component... row ) { if( columns == -1 ) { @@ -101,13 +100,13 @@ public class TableBuilder } @Nullable - public Text[] getHeaders() + public Component[] getHeaders() { return headers; } @Nonnull - public List getRows() + public List getRows() { return rows; } @@ -122,12 +121,12 @@ public class TableBuilder this.additional = additional; } - public void display( ServerCommandSource source ) + public void display( CommandSourceStack source ) { if( CommandUtils.isPlayer( source ) ) { trim( 18 ); - NetworkHandler.sendToPlayer( (ServerPlayerEntity) source.getEntity(), new ChatTableClientMessage( this ) ); + NetworkHandler.sendToPlayer( (ServerPlayer) source.getEntity(), new ChatTableClientMessage( this ) ); } else { diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 3c942e2d8..a9b2a2a3e 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -6,20 +6,20 @@ package dan200.computercraft.shared.command.text; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; import static dan200.computercraft.shared.command.text.ChatHelpers.coloured; import static dan200.computercraft.shared.command.text.ChatHelpers.translate; public interface TableFormatter { - Text SEPARATOR = coloured( "| ", Formatting.GRAY ); - Text HEADER = coloured( "=", Formatting.GRAY ); + Component SEPARATOR = coloured( "| ", ChatFormatting.GRAY ); + Component HEADER = coloured( "=", ChatFormatting.GRAY ); default int display( TableBuilder table ) { @@ -32,7 +32,7 @@ public interface TableFormatter int columns = table.getColumns(); int[] maxWidths = new int[columns]; - Text[] headers = table.getHeaders(); + Component[] headers = table.getHeaders(); if( headers != null ) { for( int i = 0; i < columns; i++ ) @@ -41,7 +41,7 @@ public interface TableFormatter } } - for( Text[] row : table.getRows() ) + for( Component[] row : table.getRows() ) { for( int i = 0; i < row.length; i++ ) { @@ -71,11 +71,11 @@ public interface TableFormatter if( headers != null ) { - LiteralText line = new LiteralText( "" ); + TextComponent line = new TextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { line.append( headers[i] ); - Text padding = getPadding( headers[i], maxWidths[i] ); + Component padding = getPadding( headers[i], maxWidths[i] ); if( padding != null ) { line.append( padding ); @@ -90,16 +90,16 @@ public interface TableFormatter // it a tad prettier. int rowCharWidth = getWidth( HEADER ); int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1); - writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getString(), rowWidth ), Formatting.GRAY ) ); + writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getString(), rowWidth ), ChatFormatting.GRAY ) ); } - for( Text[] row : table.getRows() ) + for( Component[] row : table.getRows() ) { - LiteralText line = new LiteralText( "" ); + TextComponent line = new TextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { line.append( row[i] ); - Text padding = getPadding( row[i], maxWidths[i] ); + Component padding = getPadding( row[i], maxWidths[i] ); if( padding != null ) { line.append( padding ); @@ -112,13 +112,13 @@ public interface TableFormatter if( table.getAdditional() > 0 ) { - writeLine( rowId++, coloured( translate( "commands.computercraft.generic.additional_rows", table.getAdditional() ), Formatting.AQUA ) ); + writeLine( rowId++, coloured( translate( "commands.computercraft.generic.additional_rows", table.getAdditional() ), ChatFormatting.AQUA ) ); } return rowId - table.getId(); } - int getWidth( Text component ); + int getWidth( Component component ); /** * Get the minimum padding between each column. @@ -135,7 +135,7 @@ public interface TableFormatter * @return The padding for this component, or {@code null} if none is needed. */ @Nullable - Text getPadding( Text component, int width ); + Component getPadding( Component component, int width ); - void writeLine( int id, Text component ); + void writeLine( int id, Component component ); } diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 8150b6ec2..29e071d87 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -6,29 +6,28 @@ package dan200.computercraft.shared.common; -import net.minecraft.block.Block; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.block.BlockWithEntity; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +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.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import java.util.Random; -public abstract class BlockGeneric extends BlockWithEntity +public abstract class BlockGeneric extends BaseEntityBlock { private final BlockEntityType type; - public BlockGeneric( Settings settings, BlockEntityType type ) + public BlockGeneric( Properties settings, BlockEntityType type ) { super( settings ); this.type = type; @@ -40,14 +39,14 @@ public abstract class BlockGeneric extends BlockWithEntity } @Override - public BlockRenderType getRenderType( BlockState state ) + public RenderShape getRenderShape( BlockState state ) { - return BlockRenderType.MODEL; + return RenderShape.MODEL; } @Override @Deprecated - public final void neighborUpdate( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, + public final void neighborChanged( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, @Nonnull BlockPos neighbourPos, boolean isMoving ) { BlockEntity tile = world.getBlockEntity( pos ); @@ -59,7 +58,7 @@ public abstract class BlockGeneric extends BlockWithEntity @Override @Deprecated - public final void onStateReplaced( @Nonnull BlockState block, @Nonnull World world, @Nonnull BlockPos pos, BlockState replace, boolean bool ) + public final void onRemove( @Nonnull BlockState block, @Nonnull Level world, @Nonnull BlockPos pos, BlockState replace, boolean bool ) { if( block.getBlock() == replace.getBlock() ) { @@ -67,7 +66,7 @@ public abstract class BlockGeneric extends BlockWithEntity } BlockEntity tile = world.getBlockEntity( pos ); - super.onStateReplaced( block, world, pos, replace, bool ); + super.onRemove( block, world, pos, replace, bool ); world.removeBlockEntity( pos ); if( tile instanceof TileGeneric ) { @@ -78,16 +77,16 @@ public abstract class BlockGeneric extends BlockWithEntity @Nonnull @Override @Deprecated - public final ActionResult onUse( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull PlayerEntity player, @Nonnull Hand hand, + public final InteractionResult use( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, @Nonnull BlockHitResult hit ) { BlockEntity tile = world.getBlockEntity( pos ); - return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : ActionResult.PASS; + return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : InteractionResult.PASS; } @Override @Deprecated - public void scheduledTick( @Nonnull BlockState state, ServerWorld world, @Nonnull BlockPos pos, @Nonnull Random rand ) + public void tick( @Nonnull BlockState state, ServerLevel world, @Nonnull BlockPos pos, @Nonnull Random rand ) { BlockEntity te = world.getBlockEntity( pos ); if( te instanceof TileGeneric ) @@ -98,11 +97,11 @@ public abstract class BlockGeneric extends BlockWithEntity @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { if ( this.type != null ) { - return type.instantiate( pos, state ); + return type.create( pos, state ); } return null; } diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 45601a8bc..be189e35e 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.network.client.TerminalState; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.CompoundTag; public class ClientTerminal implements ITerminal { @@ -80,12 +80,12 @@ public class ClientTerminal implements ITerminal } } - public void readDescription( NbtCompound nbt ) + public void readDescription( CompoundTag nbt ) { colour = nbt.getBoolean( "colour" ); if( nbt.contains( "terminal" ) ) { - NbtCompound terminal = nbt.getCompound( "terminal" ); + CompoundTag terminal = nbt.getCompound( "terminal" ); resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) ); this.terminal.readFromNBT( terminal ); } diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index 251bb104b..5ea821b69 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -8,34 +8,33 @@ package dan200.computercraft.shared.common; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.SpecialCraftingRecipe; -import net.minecraft.recipe.SpecialRecipeSerializer; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; -public final class ColourableRecipe extends SpecialCraftingRecipe +public final class ColourableRecipe extends CustomRecipe { - public static final RecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( ColourableRecipe::new ); + public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( ColourableRecipe::new ); - private ColourableRecipe( Identifier id ) + private ColourableRecipe( ResourceLocation id ) { super( id ); } @Override - public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inv, @Nonnull Level world ) { boolean hasColourable = false; boolean hasDye = false; - for( int i = 0; i < inv.size(); i++ ) + for( int i = 0; i < inv.getContainerSize(); i++ ) { - ItemStack stack = inv.getStack( i ); + ItemStack stack = inv.getItem( i ); if( stack.isEmpty() ) { continue; @@ -64,15 +63,15 @@ public final class ColourableRecipe extends SpecialCraftingRecipe @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inv ) + public ItemStack craft( @Nonnull CraftingContainer inv ) { ItemStack colourable = ItemStack.EMPTY; ColourTracker tracker = new ColourTracker(); - for( int i = 0; i < inv.size(); i++ ) + for( int i = 0; i < inv.getContainerSize(); i++ ) { - ItemStack stack = inv.getStack( i ); + ItemStack stack = inv.getItem( i ); if( stack.isEmpty() ) { @@ -93,7 +92,7 @@ public final class ColourableRecipe extends SpecialCraftingRecipe } @Override - public boolean fits( int x, int y ) + public boolean canCraftInDimensions( int x, int y ) { return x >= 2 && y >= 2; } diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index e3150f8e8..56a08e3a8 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -9,34 +9,33 @@ package dan200.computercraft.shared.common; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.network.container.HeldItemContainerData; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import net.minecraft.util.Hand; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +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.item.ItemStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ContainerHeldItem extends ScreenHandler +public class ContainerHeldItem extends AbstractContainerMenu { private final ItemStack stack; - private final Hand hand; + private final InteractionHand hand; - public ContainerHeldItem( ScreenHandlerType type, int id, PlayerEntity player, Hand hand ) + public ContainerHeldItem( MenuType type, int id, Player player, InteractionHand hand ) { super( type, id ); this.hand = hand; - stack = player.getStackInHand( hand ) + stack = player.getItemInHand( hand ) .copy(); } - public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) + public static ContainerHeldItem createPrintout( int id, Inventory inventory, HeldItemContainerData data ) { return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() ); } @@ -48,48 +47,48 @@ public class ContainerHeldItem extends ScreenHandler } @Override - public boolean canUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { if( !player.isAlive() ) { return false; } - ItemStack stack = player.getStackInHand( hand ); + ItemStack stack = player.getItemInHand( hand ); return stack == this.stack || !stack.isEmpty() && !this.stack.isEmpty() && stack.getItem() == this.stack.getItem(); } public static class Factory implements ExtendedScreenHandlerFactory { - private final ScreenHandlerType type; - private final Text name; - private final Hand hand; + private final MenuType type; + private final Component name; + private final InteractionHand hand; - public Factory( ScreenHandlerType type, ItemStack stack, Hand hand ) + public Factory( MenuType type, ItemStack stack, InteractionHand hand ) { this.type = type; - name = stack.getName(); + name = stack.getHoverName(); this.hand = hand; } @Nonnull @Override - public Text getDisplayName() + public Component getDisplayName() { return name; } @Nullable @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player ) { return new ContainerHeldItem( type, id, player, hand ); } @Override - public void writeScreenOpeningData( ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf ) + public void writeScreenOpeningData( ServerPlayer serverPlayerEntity, FriendlyByteBuf packetByteBuf ) { - packetByteBuf.writeEnumConstant( hand ); + packetByteBuf.writeEnum( hand ); } } } diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index b1642f413..97bfd646a 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -7,22 +7,21 @@ package dan200.computercraft.shared.common; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; -import net.minecraft.block.Block; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; public class DefaultBundledRedstoneProvider implements IBundledRedstoneProvider { @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getDefaultBundledRedstoneOutput( world, pos, side ); } - public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, Direction side ) + public static int getDefaultBundledRedstoneOutput( Level world, BlockPos pos, Direction side ) { Block block = world.getBlockState( pos ) .getBlock(); diff --git a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index 0be19a1ff..a1dca6e4f 100644 --- a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -6,13 +6,13 @@ package dan200.computercraft.shared.common; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; public interface IBundledRedstoneBlock { - boolean getBundledRedstoneConnectivity( World world, BlockPos pos, Direction side ); + boolean getBundledRedstoneConnectivity( Level world, BlockPos pos, Direction side ); - int getBundledRedstoneOutput( World world, BlockPos pos, Direction side ); + int getBundledRedstoneOutput( Level world, BlockPos pos, Direction side ); } diff --git a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java index d3e5041ec..50597e449 100644 --- a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.common; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; public interface IColouredItem { @@ -20,7 +20,7 @@ public interface IColouredItem static int getColourBasic( ItemStack stack ) { - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); return tag != null && tag.contains( NBT_COLOUR ) ? tag.getInt( NBT_COLOUR ) : -1; } @@ -35,7 +35,7 @@ public interface IColouredItem { if( colour == -1 ) { - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); if( tag != null ) { tag.remove( NBT_COLOUR ); @@ -43,7 +43,7 @@ public interface IColouredItem } else { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_COLOUR, colour ); } } diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 1adb7207e..87010f4a8 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -8,9 +8,8 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.network.client.TerminalState; -import net.minecraft.nbt.NbtCompound; - import java.util.concurrent.atomic.AtomicBoolean; +import net.minecraft.nbt.CompoundTag; public class ServerTerminal implements ITerminal { @@ -85,12 +84,12 @@ public class ServerTerminal implements ITerminal return new TerminalState( colour, terminal ); } - public void writeDescription( NbtCompound nbt ) + public void writeDescription( CompoundTag nbt ) { nbt.putBoolean( "colour", colour ); if( terminal != null ) { - NbtCompound terminal = new NbtCompound(); + CompoundTag terminal = new CompoundTag(); terminal.putInt( "term_width", this.terminal.getWidth() ); terminal.putInt( "term_height", this.terminal.getHeight() ); this.terminal.writeToNBT( terminal ); diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 787a18442..de99c3dbd 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -7,16 +7,15 @@ package dan200.computercraft.shared.common; import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; - +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import javax.annotation.Nonnull; public abstract class TileGeneric extends BlockEntity implements BlockEntityClientSerializable @@ -36,16 +35,16 @@ public abstract class TileGeneric extends BlockEntity implements BlockEntityClie public final void updateBlock() { - markDirty(); - BlockPos pos = getPos(); - BlockState state = getCachedState(); - getWorld().updateListeners( pos, state, state, 3 ); + setChanged(); + BlockPos pos = getBlockPos(); + BlockState state = getBlockState(); + getLevel().sendBlockUpdated( pos, state, state, 3 ); } @Nonnull - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - return ActionResult.PASS; + return InteractionResult.PASS; } public void onNeighbourChange( @Nonnull BlockPos neighbour ) @@ -60,9 +59,9 @@ public abstract class TileGeneric extends BlockEntity implements BlockEntityClie { } - public boolean isUsable( PlayerEntity player, boolean ignoreRange ) + public boolean isUsable( Player player, boolean ignoreRange ) { - if( player == null || !player.isAlive() || getWorld().getBlockEntity( getPos() ) != this ) + if( player == null || !player.isAlive() || getLevel().getBlockEntity( getBlockPos() ) != this ) { return false; } @@ -72,33 +71,33 @@ public abstract class TileGeneric extends BlockEntity implements BlockEntityClie } double range = getInteractRange( player ); - BlockPos pos = getPos(); - return player.getEntityWorld() == getWorld() && player.squaredDistanceTo( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range; + BlockPos pos = getBlockPos(); + return player.getCommandSenderWorld() == getLevel() && player.distanceToSqr( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range; } - protected double getInteractRange( PlayerEntity player ) + protected double getInteractRange( Player player ) { return 8.0; } @Override - public void fromClientTag( NbtCompound compoundTag ) + public void fromClientTag( CompoundTag compoundTag ) { readDescription( compoundTag ); } - protected void readDescription( @Nonnull NbtCompound nbt ) + protected void readDescription( @Nonnull CompoundTag nbt ) { } @Override - public NbtCompound toClientTag( NbtCompound compoundTag ) + public CompoundTag toClientTag( CompoundTag compoundTag ) { writeDescription( compoundTag ); return compoundTag; } - protected void writeDescription( @Nonnull NbtCompound nbt ) + protected void writeDescription( @Nonnull CompoundTag nbt ) { } } diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index a739044e2..b1dbe5778 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -13,18 +13,17 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.*; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.CommandManager; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.state.property.Property; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.World; - +import net.minecraft.world.level.Level; +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.minecraft.world.level.block.state.properties.Property; import java.util.*; /** @@ -66,19 +65,19 @@ public class CommandAPI implements ILuaAPI private Object[] doCommand( String command ) { - MinecraftServer server = computer.getWorld() + MinecraftServer server = computer.getLevel() .getServer(); - if( server == null || !server.areCommandBlocksEnabled() ) + if( server == null || !server.isCommandBlockEnabled() ) { return new Object[] { false, createOutput( "Command blocks disabled by server" ) }; } - CommandManager commandManager = server.getCommandManager(); + Commands commandManager = server.getCommands(); TileCommandComputer.CommandReceiver receiver = computer.getReceiver(); try { receiver.clearOutput(); - int result = commandManager.execute( computer.getSource(), command ); + int result = commandManager.performCommand( computer.getSource(), command ); return new Object[] { result > 0, receiver.copyOutput(), result }; } catch( Throwable t ) @@ -132,14 +131,14 @@ public class CommandAPI implements ILuaAPI @LuaFunction( mainThread = true ) public final List list( IArguments args ) throws LuaException { - MinecraftServer server = computer.getWorld() + MinecraftServer server = computer.getLevel() .getServer(); if( server == null ) { return Collections.emptyList(); } - CommandNode node = server.getCommandManager() + CommandNode node = server.getCommands() .getDispatcher() .getRoot(); for( int j = 0; j < args.count(); j++ ) @@ -176,7 +175,7 @@ public class CommandAPI implements ILuaAPI public final Object[] getBlockPosition() { // This is probably safe to do on the Lua thread. Probably. - BlockPos pos = computer.getPos(); + BlockPos pos = computer.getBlockPos(); return new Object[] { pos.getX(), pos.getY(), pos.getZ() }; } @@ -201,10 +200,10 @@ public class CommandAPI implements ILuaAPI public final List> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException { // Get the details of the block - World world = computer.getWorld(); + Level world = computer.getLevel(); BlockPos min = new BlockPos( Math.min( minX, maxX ), Math.min( minY, maxY ), Math.min( minZ, maxZ ) ); BlockPos max = new BlockPos( Math.max( minX, maxX ), Math.max( minY, maxY ), Math.max( minZ, maxZ ) ); - if( !world.isInBuildLimit( min ) || !world.isInBuildLimit( max ) ) + if( !world.isInWorldBounds( min ) || !world.isInWorldBounds( max ) ) { throw new LuaException( "Co-ordinates out of range" ); } @@ -231,18 +230,18 @@ public class CommandAPI implements ILuaAPI return results; } - private static Map getBlockInfo( World world, BlockPos pos ) + private static Map getBlockInfo( Level world, BlockPos pos ) { // Get the details of the block BlockState state = world.getBlockState( pos ); Block block = state.getBlock(); Map table = new HashMap<>(); - table.put( "name", Registry.BLOCK.getId( block ).toString() ); - table.put( "world", world.getRegistryKey() ); + table.put( "name", Registry.BLOCK.getKey( block ).toString() ); + table.put( "world", world.dimension() ); Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, Comparable> entry : state.getEntries().entrySet() ) + for( ImmutableMap.Entry, Comparable> entry : state.getValues().entrySet() ) { Property property = entry.getKey(); stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); @@ -252,7 +251,7 @@ public class CommandAPI implements ILuaAPI BlockEntity tile = world.getBlockEntity( pos ); if( tile != null ) { - table.put( "nbt", NBTUtil.toLua( tile.writeNbt( new NbtCompound() ) ) ); + table.put( "nbt", NBTUtil.toLua( tile.save( new CompoundTag() ) ) ); } return table; @@ -268,7 +267,7 @@ public class CommandAPI implements ILuaAPI { return value; } - return property.name( value ); + return property.getName( value ); } /** @@ -287,9 +286,9 @@ public class CommandAPI implements ILuaAPI public final Map getBlockInfo( int x, int y, int z ) throws LuaException { // Get the details of the block - World world = computer.getWorld(); + Level world = computer.getLevel(); BlockPos position = new BlockPos( x, y, z ); - if( world.isInBuildLimit( position ) ) + if( world.isInWorldBounds( position ) ) { return getBlockInfo( world, position ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 39b725791..35e249c34 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -10,45 +10,44 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.items.ComputerItemFactory; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.EnumProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +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.block.state.properties.EnumProperty; public class BlockComputer extends BlockComputerBase { - public static final EnumProperty STATE = EnumProperty.of( "state", ComputerState.class ); - public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class ); + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockComputer( Settings settings, ComputerFamily family, BlockEntityType type ) + public BlockComputer( Properties settings, ComputerFamily family, BlockEntityType type ) { super( settings, family, type ); - setDefaultState( getDefaultState().with( FACING, Direction.NORTH ) - .with( STATE, ComputerState.OFF ) ); + registerDefaultState( defaultBlockState().setValue( FACING, Direction.NORTH ) + .setValue( STATE, ComputerState.OFF ) ); } @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, - placement.getPlayerFacing() + return defaultBlockState().setValue( FACING, + placement.getHorizontalDirection() .getOpposite() ); } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( FACING, STATE ); } @@ -72,7 +71,7 @@ public class BlockComputer extends BlockComputerBase @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileComputer( getFamily(), getTypeByFamily( getFamily() ), pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 7a366c74a..f2cc48927 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -13,34 +13,33 @@ import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityTicker; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.loot.context.LootContext; -import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.stat.Stats; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.BlockView; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.stats.Stats; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.Vec3; public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock { - private static final Identifier DROP = new Identifier( ComputerCraft.MOD_ID, "computer" ); + private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); private final ComputerFamily family; - protected BlockComputerBase( Settings settings, ComputerFamily family, BlockEntityType type ) + protected BlockComputerBase( Properties settings, ComputerFamily family, BlockEntityType type ) { super( settings, type ); this.family = family; @@ -48,9 +47,9 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public void onBlockAdded( @Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving ) + public void onPlace( @Nonnull BlockState state, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving ) { - super.onBlockAdded( state, world, pos, oldState, isMoving ); + super.onPlace( state, world, pos, oldState, isMoving ); BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileComputerBase ) @@ -61,21 +60,21 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public boolean emitsRedstonePower( @Nonnull BlockState state ) + public boolean isSignalSource( @Nonnull BlockState state ) { return true; } @Override @Deprecated - public int getWeakRedstonePower( @Nonnull BlockState state, @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) + public int getSignal( @Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) { - return getStrongRedstonePower( state, world, pos, incomingSide ); + return getDirectSignal( state, world, pos, incomingSide ); } @Override @Deprecated - public int getStrongRedstonePower( @Nonnull BlockState state, BlockView world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) + public int getDirectSignal( @Nonnull BlockState state, BlockGetter world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) { BlockEntity entity = world.getBlockEntity( pos ); if( !(entity instanceof TileComputerBase) ) @@ -100,13 +99,13 @@ public abstract class BlockComputerBase extends Bloc } @Override - public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, Direction side ) + public boolean getBundledRedstoneConnectivity( Level world, BlockPos pos, Direction side ) { return true; } @Override - public int getBundledRedstoneOutput( World world, BlockPos pos, Direction side ) + public int getBundledRedstoneOutput( Level world, BlockPos pos, Direction side ) { BlockEntity entity = world.getBlockEntity( pos ); if( !(entity instanceof TileComputerBase) ) @@ -126,21 +125,21 @@ public abstract class BlockComputerBase extends Bloc } @Override - public void afterBreak( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile, + public void playerDestroy( @Nonnull Level world, Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile, @Nonnull ItemStack tool ) { // Don't drop blocks here - see onBlockHarvested. - player.incrementStat( Stats.MINED.getOrCreateStat( this ) ); - player.addExhaustion( 0.005F ); + player.awardStat( Stats.BLOCK_MINED.get( this ) ); + player.causeFoodExhaustion( 0.005F ); } @Override - public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) { - super.onPlaced( world, pos, state, placer, stack ); + super.setPlacedBy( world, pos, state, placer, stack ); BlockEntity tile = world.getBlockEntity( pos ); - if( !world.isClient && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem ) + if( !world.isClientSide && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem ) { IComputerTile computer = (IComputerTile) tile; IComputerItem item = (IComputerItem) stack.getItem(); @@ -161,7 +160,7 @@ public abstract class BlockComputerBase extends Bloc @Nonnull @Override - public ItemStack getPickStack( BlockView world, BlockPos pos, BlockState state ) + public ItemStack getCloneItemStack( BlockGetter world, BlockPos pos, BlockState state ) { BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileComputerBase ) @@ -173,23 +172,23 @@ public abstract class BlockComputerBase extends Bloc } } - return super.getPickStack( world, pos, state ); + return super.getCloneItemStack( world, pos, state ); } @Nonnull protected abstract ItemStack getItem( TileComputerBase tile ); @Override - public void onBreak( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player ) + public void playerWillDestroy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Player player ) { // Call super as it is what provides sound and block break particles. Does not do anything else. - super.onBreak( world, pos, state, player ); + super.playerWillDestroy( world, pos, state, player ); - if( !(world instanceof ServerWorld) ) + if( !(world instanceof ServerLevel) ) { return; } - ServerWorld serverWorld = (ServerWorld) world; + ServerLevel serverWorld = (ServerLevel) world; // We drop the item here instead of doing it in the harvest method, as we should // drop computers for creative players too. @@ -198,26 +197,26 @@ public abstract class BlockComputerBase extends Bloc if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - LootContext.Builder context = new LootContext.Builder( serverWorld ).random( world.random ) - .parameter( LootContextParameters.ORIGIN, Vec3d.ofCenter( pos ) ) - .parameter( LootContextParameters.TOOL, player.getMainHandStack() ) - .parameter( LootContextParameters.THIS_ENTITY, player ) - .parameter( LootContextParameters.BLOCK_ENTITY, tile ) - .putDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) ); - for( ItemStack item : state.getDroppedStacks( context ) ) + LootContext.Builder context = new LootContext.Builder( serverWorld ).withRandom( world.random ) + .withParameter( LootContextParams.ORIGIN, Vec3.atCenterOf( pos ) ) + .withParameter( LootContextParams.TOOL, player.getMainHandItem() ) + .withParameter( LootContextParams.THIS_ENTITY, player ) + .withParameter( LootContextParams.BLOCK_ENTITY, tile ) + .withDynamicDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) ); + for( ItemStack item : state.getDrops( context ) ) { - dropStack( world, pos, item ); + popResource( world, pos, item ); } - state.onStacksDropped( serverWorld, pos, player.getMainHandStack() ); + state.spawnAfterBreak( serverWorld, pos, player.getMainHandItem() ); } } @Nullable @Override - public BlockEntityTicker getTicker( World world, BlockState state, BlockEntityType type ) + public BlockEntityTicker getTicker( Level world, BlockState state, BlockEntityType type ) { - return world.isClient ? null : ( world1, pos, state1, tile ) -> { + return world.isClientSide ? null : ( world1, pos, state1, tile ) -> { if ( tile instanceof TileComputerBase computer ) { computer.serverTick(); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index c9cc998e1..55d69dc16 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -10,21 +10,20 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.commands.CommandSource; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.CommandOutput; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec2f; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.GameRules; - +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; @@ -45,7 +44,7 @@ public class TileCommandComputer extends TileComputer return receiver; } - public ServerCommandSource getSource() + public CommandSourceStack getSource() { ServerComputer computer = getServerComputer(); String name = "@"; @@ -58,14 +57,14 @@ public class TileCommandComputer extends TileComputer } } - return new ServerCommandSource( receiver, - new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), - Vec2f.ZERO, - (ServerWorld) getWorld(), + return new CommandSourceStack( receiver, + new Vec3( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ), + Vec2.ZERO, + (ServerLevel) getLevel(), 2, name, - new LiteralText( name ), - getWorld().getServer(), + new TextComponent( name ), + getLevel().getServer(), null ); } @@ -78,30 +77,30 @@ public class TileCommandComputer extends TileComputer } @Override - public boolean isUsable( PlayerEntity player, boolean ignoreRange ) + public boolean isUsable( Player player, boolean ignoreRange ) { return isUsable( player ) && super.isUsable( player, ignoreRange ); } - public static boolean isUsable( PlayerEntity player ) + public static boolean isUsable( Player player ) { MinecraftServer server = player.getServer(); - if( server == null || !server.areCommandBlocksEnabled() ) + if( server == null || !server.isCommandBlockEnabled() ) { - player.sendMessage( new TranslatableText( "advMode.notEnabled" ), true ); + player.displayClientMessage( new TranslatableComponent( "advMode.notEnabled" ), true ); return false; } - else if( ComputerCraft.commandRequireCreative ? !player.isCreativeLevelTwoOp() : !server.getPlayerManager() - .isOperator( player.getGameProfile() ) ) + else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList() + .isOp( player.getGameProfile() ) ) { - player.sendMessage( new TranslatableText( "advMode.notAllowed" ), true ); + player.displayClientMessage( new TranslatableComponent( "advMode.notAllowed" ), true ); return false; } return true; } - public class CommandReceiver implements CommandOutput + public class CommandReceiver implements CommandSource { private final Map output = new HashMap<>(); @@ -121,29 +120,29 @@ public class TileCommandComputer extends TileComputer } @Override - public void sendSystemMessage( @Nonnull Text textComponent, @Nonnull UUID id ) + public void sendMessage( @Nonnull Component textComponent, @Nonnull UUID id ) { output.put( output.size() + 1, textComponent.getString() ); } @Override - public boolean shouldReceiveFeedback() + public boolean acceptsSuccess() { - return getWorld().getGameRules() - .getBoolean( GameRules.SEND_COMMAND_FEEDBACK ); + return getLevel().getGameRules() + .getBoolean( GameRules.RULE_SENDCOMMANDFEEDBACK ); } @Override - public boolean shouldTrackOutput() + public boolean acceptsFailure() { return true; } @Override - public boolean shouldBroadcastConsoleToOps() + public boolean shouldInformAdmins() { - return getWorld().getGameRules() - .getBoolean( GameRules.COMMAND_BLOCK_OUTPUT ); + return getLevel().getGameRules() + .getBoolean( GameRules.RULE_COMMANDBLOCKOUTPUT ); } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 280f4c4d5..0af1ae53a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -13,16 +13,15 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; public class TileComputer extends TileComputerBase { @@ -33,7 +32,7 @@ public class TileComputer extends TileComputerBase super( type, family, pos, state ); } - public boolean isUsableByPlayer( PlayerEntity player ) + public boolean isUsableByPlayer( Player player ) { return isUsable( player, false ); } @@ -41,17 +40,17 @@ public class TileComputer extends TileComputerBase @Override protected void updateBlockState( ComputerState newState ) { - BlockState existing = getCachedState(); - if( existing.get( BlockComputer.STATE ) != newState ) + BlockState existing = getBlockState(); + if( existing.getValue( BlockComputer.STATE ) != newState ) { - getWorld().setBlockState( getPos(), existing.with( BlockComputer.STATE, newState ), 3 ); + getLevel().setBlock( getBlockPos(), existing.setValue( BlockComputer.STATE, newState ), 3 ); } } @Override public Direction getDirection() { - return getCachedState().get( BlockComputer.FACING ); + return getBlockState().getValue( BlockComputer.FACING ); } @Override @@ -74,13 +73,13 @@ public class TileComputer extends TileComputerBase protected ServerComputer createComputer( int instanceID, int id ) { ComputerFamily family = getFamily(); - ServerComputer computer = new ServerComputer( getWorld(), + ServerComputer computer = new ServerComputer( getLevel(), id, label, instanceID, family, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); - computer.setPosition( getPos() ); + computer.setPosition( getBlockPos() ); return computer; } @@ -103,7 +102,7 @@ public class TileComputer extends TileComputerBase @Nullable @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player ) { return new ComputerMenuWithoutInventory( ComputerCraftRegistry.ModContainers.COMPUTER, id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 0e6955f9c..47292b391 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -21,27 +21,26 @@ import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.RedstoneUtil; import joptsimple.internal.Strings; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.RedstoneWireBlock; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.Nameable; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.RedStoneWireBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -72,7 +71,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT unload(); for( Direction dir : DirectionUtil.FACINGS ) { - RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); + RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir ); } } @@ -86,7 +85,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { if( instanceID >= 0 ) { - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { ComputerCraft.serverComputerRegistry.remove( instanceID ); } @@ -96,42 +95,42 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - ItemStack currentItem = player.getStackInHand( hand ); - if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasCustomName() ) + ItemStack currentItem = player.getItemInHand( hand ); + if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasCustomHoverName() ) { // Label to rename computer - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - setLabel( currentItem.getName() + setLabel( currentItem.getHoverName() .getString() ); - currentItem.decrement( 1 ); + currentItem.shrink( 1 ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } - else if( !player.isInSneakingPose() ) + else if( !player.isCrouching() ) { // Regular right click to activate computer - if( !getWorld().isClient && isUsable( player, false ) ) + if( !getLevel().isClientSide && isUsable( player, false ) ) { createServerComputer().turnOn(); createServerComputer().sendTerminalState( player ); new ComputerContainerData( createServerComputer() ).open( player, this ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } - return ActionResult.PASS; + return InteractionResult.PASS; } - protected boolean canNameWithTag( PlayerEntity player ) + protected boolean canNameWithTag( Player player ) { return false; } public ServerComputer createServerComputer() { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return null; } @@ -159,14 +158,14 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT public ServerComputer getServerComputer() { - return getWorld().isClient ? null : ComputerCraft.serverComputerRegistry.get( instanceID ); + return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID ); } protected abstract ServerComputer createComputer( int instanceID, int id ); public void updateInput() { - if( getWorld() == null || getWorld().isClient ) + if( getLevel() == null || getLevel().isClientSide ) { return; } @@ -181,7 +180,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT BlockPos pos = computer.getPosition(); for( Direction dir : DirectionUtil.FACINGS ) { - updateSideInput( computer, dir, pos.offset( dir ) ); + updateSideInput( computer, dir, pos.relative( dir ) ); } } @@ -190,11 +189,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT Direction offsetSide = dir.getOpposite(); ComputerSide localDir = remapToLocalSide( dir ); - computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) ); - computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); + computer.setRedstoneInput( localDir, getRedstoneInput( level, offset, dir ) ); + computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), offset, offsetSide ) ); if( !isPeripheralBlockedOnSide( localDir ) ) { - IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide ); + IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), offset, offsetSide ); computer.setPeripheral( localDir, peripheral ); } } @@ -212,16 +211,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT * @param side The side we are reading from * @return The effective redstone power */ - protected static int getRedstoneInput( World world, BlockPos pos, Direction side ) + protected static int getRedstoneInput( Level world, BlockPos pos, Direction side ) { - int power = world.getEmittedRedstonePower( pos, side ); + int power = world.getSignal( pos, side ); if( power >= 15 ) { return power; } BlockState neighbour = world.getBlockState( pos ); - return neighbour.getBlock() == Blocks.REDSTONE_WIRE ? Math.max( power, neighbour.get( RedstoneWireBlock.POWER ) ) : power; + return neighbour.getBlock() == Blocks.REDSTONE_WIRE ? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) ) : power; } protected boolean isPeripheralBlockedOnSide( ComputerSide localSide ) @@ -249,7 +248,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - protected void readDescription( @Nonnull NbtCompound nbt ) + protected void readDescription( @Nonnull CompoundTag nbt ) { super.readDescription( nbt ); label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; @@ -257,7 +256,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - protected void writeDescription( @Nonnull NbtCompound nbt ) + protected void writeDescription( @Nonnull CompoundTag nbt ) { super.writeDescription( nbt ); if( label != null ) @@ -313,16 +312,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT updateBlock(); for( Direction dir : DirectionUtil.FACINGS ) { - RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); + RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir ); } } protected abstract void updateBlockState( ComputerState newState ); @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); // Load ID, label and power state computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; @@ -332,7 +331,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public NbtCompound writeNbt( @Nonnull NbtCompound nbt ) + public CompoundTag save( @Nonnull CompoundTag nbt ) { // Save ID, label and power state if( computerID >= 0 ) @@ -344,19 +343,19 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT nbt.putString( NBT_LABEL, label ); } nbt.putBoolean( NBT_ON, on ); - return super.writeNbt( nbt ); + return super.save( nbt ); } @Override - public void markRemoved() + public void setRemoved() { unload(); - super.markRemoved(); + super.setRemoved(); } private void updateInput( BlockPos neighbour ) { - if( getWorld() == null || this.world.isClient ) + if( getLevel() == null || this.level.isClientSide ) { return; } @@ -369,7 +368,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT for( Direction dir : DirectionUtil.FACINGS ) { - BlockPos offset = pos.offset( dir ); + BlockPos offset = worldPosition.relative( dir ); if( offset.equals( neighbour ) ) { updateSideInput( computer, dir, offset ); @@ -383,7 +382,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT private void updateInput( Direction dir ) { - if( getWorld() == null || this.world.isClient ) + if( getLevel() == null || this.level.isClientSide ) { return; } @@ -394,7 +393,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT return; } - updateSideInput( computer, dir, pos.offset( dir ) ); + updateSideInput( computer, dir, worldPosition.relative( dir ) ); } @Override @@ -406,7 +405,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final void setComputerID( int id ) { - if( this.world.isClient || computerID == id ) + if( this.level.isClientSide || computerID == id ) { return; } @@ -417,7 +416,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { computer.setID( computerID ); } - markDirty(); + setChanged(); } @Override @@ -431,7 +430,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final void setLabel( String label ) { - if( this.world.isClient || Objects.equals( this.label, label ) ) + if( this.level.isClientSide || Objects.equals( this.label, label ) ) { return; } @@ -442,7 +441,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { computer.setLabel( label ); } - markDirty(); + setChanged(); } @Override @@ -477,10 +476,10 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public Text getName() + public Component getName() { - return hasCustomName() ? new LiteralText( label ) : new TranslatableText( getCachedState().getBlock() - .getTranslationKey() ); + return hasCustomName() ? new TextComponent( label ) : new TranslatableComponent( getBlockState().getBlock() + .getDescriptionId() ); } @Override @@ -491,22 +490,22 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public Text getDisplayName() + public Component getDisplayName() { return Nameable.super.getDisplayName(); } @Nullable @Override - public Text getCustomName() + public Component getCustomName() { - return hasCustomName() ? new LiteralText( label ) : null; + return hasCustomName() ? new TextComponent( label ) : null; } @Override - public void writeScreenOpeningData( ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf ) + public void writeScreenOpeningData( ServerPlayer serverPlayerEntity, FriendlyByteBuf packetByteBuf ) { packetByteBuf.writeInt( getServerComputer().getInstanceID() ); - packetByteBuf.writeEnumConstant( getServerComputer().getFamily() ); + packetByteBuf.writeEnum( getServerComputer().getFamily() ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index 615b65eef..df0a18625 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared.computer.core; import dan200.computercraft.shared.common.ClientTerminal; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.*; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.CompoundTag; public class ClientComputer extends ClientTerminal implements IComputer { @@ -17,7 +17,7 @@ public class ClientComputer extends ClientTerminal implements IComputer private boolean on = false; private boolean blinking = false; - private NbtCompound userData = null; + private CompoundTag userData = null; public ClientComputer( int instanceID ) @@ -26,7 +26,7 @@ public class ClientComputer extends ClientTerminal implements IComputer this.instanceID = instanceID; } - public NbtCompound getUserData() + public CompoundTag getUserData() { return userData; } @@ -123,7 +123,7 @@ public class ClientComputer extends ClientTerminal implements IComputer NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); } - public void setState( ComputerState state, NbtCompound userData ) + public void setState( ComputerState state, CompoundTag userData ) { on = state != ComputerState.OFF; blinking = state == ComputerState.BLINKING; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java index 29e427049..c2a9873c1 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java @@ -6,11 +6,10 @@ package dan200.computercraft.shared.computer.core; -import net.minecraft.util.StringIdentifiable; - import javax.annotation.Nonnull; +import net.minecraft.util.StringRepresentable; -public enum ComputerState implements StringIdentifiable +public enum ComputerState implements StringRepresentable { OFF( "off", "" ), ON( "on", "_on" ), BLINKING( "blinking", "_blink" ); @@ -25,7 +24,7 @@ public enum ComputerState implements StringIdentifiable @Nonnull @Override - public String asString() + public String getSerializedName() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java index d3ff52edf..442fbd8d8 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java @@ -8,10 +8,9 @@ package dan200.computercraft.shared.computer.core; import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; -import net.minecraft.server.network.ServerPlayerEntity; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.server.level.ServerPlayer; import java.util.List; import java.util.UUID; @@ -61,7 +60,7 @@ public interface IContainerComputer * @param uploader The player uploading files. * @param uploadId The unique ID of this upload. */ - void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ); + void finishUpload( @Nonnull ServerPlayer uploader, @Nonnull UUID uploadId ); /** * Continue an upload. @@ -69,5 +68,5 @@ public interface IContainerComputer * @param uploader The player uploading files. * @param overwrite Whether the files should be overwritten or not. */ - void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ); + void confirmUpload( @Nonnull ServerPlayer uploader, boolean overwrite ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 8204424c9..11358dd53 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -24,13 +24,12 @@ import dan200.computercraft.shared.network.client.ComputerDataClientMessage; import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage; import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.screen.ScreenHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.InputStream; @@ -40,15 +39,15 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput private final int instanceID; private final ComputerFamily family; private final Computer computer; - private World world; + private Level world; private BlockPos position; - private NbtCompound userData; + private CompoundTag userData; private boolean changed; private boolean changedLastFrame; private int ticksSincePing; - public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) + public ServerComputer( Level world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) { super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight ); this.instanceID = instanceID; @@ -71,12 +70,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return family; } - public World getWorld() + public Level getWorld() { return world; } - public void setWorld( World world ) + public void setWorld( Level world ) { this.world = world; } @@ -128,11 +127,11 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput computer.unload(); } - public NbtCompound getUserData() + public CompoundTag getUserData() { if( userData == null ) { - userData = new NbtCompound(); + userData = new CompoundTag(); } return userData; } @@ -162,8 +161,8 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput // Send terminal state to clients who are currently interacting with the computer. NetworkMessage packet = null; - for( PlayerEntity player : server.getPlayerManager() - .getPlayerList() ) + for( Player player : server.getPlayerList() + .getPlayers() ) { if( isInteracting( player ) ) { @@ -188,7 +187,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return new ComputerDataClientMessage( this ); } - protected boolean isInteracting( PlayerEntity player ) + protected boolean isInteracting( Player player ) { return getContainer( player ) != null; } @@ -199,14 +198,14 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput } @Nullable - public IContainerComputer getContainer( PlayerEntity player ) + public IContainerComputer getContainer( Player player ) { if( player == null ) { return null; } - ScreenHandler container = player.currentScreenHandler; + AbstractContainerMenu container = player.containerMenu; if( !(container instanceof IContainerComputer) ) { return null; @@ -264,13 +263,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return computer.isOn() && computer.isBlinking(); } - public void sendComputerState( PlayerEntity player ) + public void sendComputerState( Player player ) { // Send state to client NetworkHandler.sendToPlayer( player, createComputerPacket() ); } - public void sendTerminalState( PlayerEntity player ) + public void sendTerminalState( Player player ) { // Send terminal state to client NetworkHandler.sendToPlayer( player, createTerminalPacket() ); @@ -352,13 +351,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public int getDay() { - return (int) ((world.getTimeOfDay() + 6000) / 24000) + 1; + return (int) ((world.getDayTime() + 6000) / 24000) + 1; } @Override public double getTimeOfDay() { - return (world.getTimeOfDay() + 6000) % 24000 / 1000.0; + return (world.getDayTime() + 6000) % 24000 / 1000.0; } @Override diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java index f3384de72..849f3e307 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java @@ -9,11 +9,10 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.InvisibleSlot; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.ScreenHandlerType; - import java.util.function.Predicate; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; /** * A computer menu which does not have any visible inventory. @@ -22,19 +21,19 @@ import java.util.function.Predicate; */ public class ComputerMenuWithoutInventory extends ContainerComputerBase { - public ComputerMenuWithoutInventory( ScreenHandlerType type, int id, PlayerInventory player, Predicate canUse, IComputer computer, ComputerFamily family ) + public ComputerMenuWithoutInventory( MenuType type, int id, Inventory player, Predicate canUse, IComputer computer, ComputerFamily family ) { super( type, id, canUse, computer, family ); addSlots( player ); } - public ComputerMenuWithoutInventory( ScreenHandlerType type, int id, PlayerInventory player, ComputerContainerData data ) + public ComputerMenuWithoutInventory( MenuType type, int id, Inventory player, ComputerContainerData data ) { super( type, id, player, data ); addSlots( player ); } - private void addSlots( PlayerInventory player ) + private void addSlots( Inventory player ) { for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index 8ea9bbc7e..e49be66a0 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -17,26 +17,25 @@ import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.UploadResultMessage; import dan200.computercraft.shared.network.container.ComputerContainerData; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.TranslatableText; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +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 java.io.IOException; import java.nio.channels.WritableByteChannel; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; -public abstract class ContainerComputerBase extends ScreenHandler implements IContainerComputer +public abstract class ContainerComputerBase extends AbstractContainerMenu implements IContainerComputer { private static final String LIST_PREFIX = "\n \u2022 "; - private final Predicate canUse; + private final Predicate canUse; private final IComputer computer; private final ComputerFamily family; private final InputState input = new InputState( this ); @@ -44,7 +43,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo private UUID toUploadId; private List toUpload; - public ContainerComputerBase( ScreenHandlerType type, int id, PlayerInventory player, ComputerContainerData data ) + public ContainerComputerBase( MenuType type, int id, Inventory player, ComputerContainerData data ) { this( type, id, @@ -53,7 +52,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo data.getFamily() ); } - public ContainerComputerBase( ScreenHandlerType type, int id, Predicate canUse, IComputer computer, + public ContainerComputerBase( MenuType type, int id, Predicate canUse, IComputer computer, ComputerFamily family ) { super( type, id ); @@ -62,10 +61,10 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo this.family = family; } - protected static IComputer getComputer( PlayerInventory player, ComputerContainerData data ) + protected static IComputer getComputer( Inventory player, ComputerContainerData data ) { int id = data.getInstanceId(); - if( !player.player.world.isClient ) + if( !player.player.level.isClientSide ) { return ComputerCraft.serverComputerRegistry.get( id ); } @@ -99,14 +98,14 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo } @Override - public void close( @Nonnull PlayerEntity player ) + public void removed( @Nonnull Player player ) { - super.close( player ); + super.removed( player ); input.close(); } @Override - public boolean canUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { return canUse.test( player ); } @@ -131,7 +130,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo } @Override - public void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ) + public void finishUpload( @Nonnull ServerPlayer uploader, @Nonnull UUID uploadId ) { if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) ) { @@ -144,7 +143,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo } @Override - public void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ) + public void confirmUpload( @Nonnull ServerPlayer uploader, boolean overwrite ) { if( toUploadId == null || toUpload == null || toUpload.isEmpty() ) { @@ -170,7 +169,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo if( !upload.checksumMatches() ) { ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() ); - return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) ); + return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.corrupted" ) ); } } @@ -186,7 +185,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo { return new UploadResultMessage( UploadResult.ERROR, - new TranslatableText( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) + new TranslatableComponent( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) ); } @@ -200,7 +199,7 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo toUpload = files; return new UploadResultMessage( UploadResult.CONFIRM_OVERWRITE, - new TranslatableText( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) + new TranslatableComponent( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) ); } @@ -219,13 +218,13 @@ public abstract class ContainerComputerBase extends ScreenHandler implements ICo } return new UploadResultMessage( - UploadResult.SUCCESS, new TranslatableText( "gui.computercraft.upload.success.msg", files.size() ) + UploadResult.SUCCESS, new TranslatableComponent( "gui.computercraft.upload.success.msg", files.size() ) ); } catch( FileSystemException | IOException e ) { ComputerCraft.log.error( "Error uploading files", e ); - return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); + return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 341908650..9f186b4cb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -12,30 +12,29 @@ import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.container.ViewComputerContainerData; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; - import javax.annotation.Nonnull; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; public class ContainerViewComputer extends ComputerMenuWithoutInventory { private final int width; private final int height; - public ContainerViewComputer( int id, PlayerInventory player, ServerComputer computer ) + public ContainerViewComputer( int id, Inventory player, ServerComputer computer ) { super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, p -> canInteractWith( computer, p ), computer, computer.getFamily() ); width = height = 0; } - public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data ) + public ContainerViewComputer( int id, Inventory player, ViewComputerContainerData data ) { super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, data ); width = data.getWidth(); height = data.getHeight(); } - private static boolean canInteractWith( @Nonnull ServerComputer computer, @Nonnull PlayerEntity player ) + private static boolean canInteractWith( @Nonnull ServerComputer computer, @Nonnull Player player ) { // If this computer no longer exists then discard it. if( ComputerCraft.serverComputerRegistry.get( computer.getInstanceID() ) != computer ) diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index b267240c5..0394db48b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -9,9 +9,8 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; public final class ComputerItemFactory { diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index e887dbb6b..aa26b0c68 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -7,10 +7,9 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; - import javax.annotation.Nonnull; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; public interface IComputerItem { @@ -18,13 +17,13 @@ public interface IComputerItem default int getComputerID( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } default String getLabel( @Nonnull ItemStack stack ) { - return stack.hasCustomName() ? stack.getName() + return stack.hasCustomHoverName() ? stack.getHoverName() .getString() : null; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index 3fc0370e8..ad0563612 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -8,14 +8,13 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; -import net.minecraft.text.LiteralText; - import javax.annotation.Nonnull; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.ItemStack; public class ItemComputer extends ItemComputerBase { - public ItemComputer( BlockComputer block, Settings settings ) + public ItemComputer( BlockComputer block, Properties settings ) { super( block, settings ); } @@ -25,12 +24,12 @@ public class ItemComputer extends ItemComputerBase ItemStack result = new ItemStack( this ); if( id >= 0 ) { - result.getOrCreateNbt() + result.getOrCreateTag() .putInt( NBT_ID, id ); } if( label != null ) { - result.setCustomName( new LiteralText( label ) ); + result.setHoverName( new TextComponent( label ) ); } return result; } @@ -39,9 +38,9 @@ public class ItemComputer extends ItemComputerBase public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family ) { ItemStack result = ComputerItemFactory.create( getComputerID( stack ), null, family ); - if( stack.hasCustomName() ) + if( stack.hasCustomHoverName() ) { - result.setCustomName( stack.getName() ); + result.setHoverName( stack.getHoverName() ); } return result; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 482e2916b..d02e7b7cf 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -12,38 +12,37 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.computer.blocks.BlockComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; import java.util.List; public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia { private final ComputerFamily family; - public ItemComputerBase( BlockComputerBase block, Settings settings ) + public ItemComputerBase( BlockComputerBase block, Properties settings ) { super( block, settings ); family = block.getFamily(); } @Override - public void appendTooltip( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull TooltipContext options ) + public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List list, @Nonnull TooltipFlag options ) { if( options.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) { - list.add( new TranslatableText( "gui.computercraft.tooltip.computer_id", id ).formatted( Formatting.GRAY ) ); + list.add( new TranslatableComponent( "gui.computercraft.tooltip.computer_id", id ).withStyle( ChatFormatting.GRAY ) ); } } } @@ -67,17 +66,17 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte { if( label != null ) { - stack.setCustomName( new LiteralText( label ) ); + stack.setHoverName( new TextComponent( label ) ); } else { - stack.removeCustomName(); + stack.resetHoverName(); } return true; } @Override - public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull Level world ) { ComputerFamily family = getFamily(); if( family != ComputerFamily.COMMAND ) diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index 8b4cfaa58..168b7e131 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -7,15 +7,14 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.ShapedRecipe; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.level.Level; /** * Represents a recipe which converts a computer from one form into another. @@ -24,7 +23,7 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe { private final String group; - public ComputerConvertRecipe( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result ) + public ComputerConvertRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result ) { super( identifier, group, width, height, ingredients, result ); this.group = group; @@ -38,16 +37,16 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe } @Override - public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { if( !super.matches( inventory, world ) ) { return false; } - for( int i = 0; i < inventory.size(); i++ ) + for( int i = 0; i < inventory.getContainerSize(); i++ ) { - if( inventory.getStack( i ) + if( inventory.getItem( i ) .getItem() instanceof IComputerItem ) { return true; @@ -59,12 +58,12 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { // Find our computer item and convert it. - for( int i = 0; i < inventory.size(); i++ ) + for( int i = 0; i < inventory.getContainerSize(); i++ ) { - ItemStack stack = inventory.getStack( i ); + ItemStack stack = inventory.getItem( i ); if( stack.getItem() instanceof IComputerItem ) { return convert( (IComputerItem) stack.getItem(), stack ); diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index d882505f9..a0c6df14c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -9,21 +9,20 @@ package dan200.computercraft.shared.computer.recipe; import com.google.gson.JsonObject; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.util.RecipeUtil; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.util.JsonHelper; -import net.minecraft.util.collection.DefaultedList; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe { private final ComputerFamily family; - public ComputerFamilyRecipe( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result, + public ComputerFamilyRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { super( identifier, group, width, height, ingredients, result ); @@ -39,51 +38,51 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe { @Nonnull @Override - public T read( @Nonnull Identifier identifier, @Nonnull JsonObject json ) + public T fromJson( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { - String group = JsonHelper.getString( json, "group", "" ); + String group = GsonHelper.getAsString( json, "group", "" ); ComputerFamily family = RecipeUtil.getFamily( json, "family" ); RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json ); - ItemStack result = outputFromJson( JsonHelper.getObject( json, "result" ) ); + ItemStack result = itemStackFromJson( GsonHelper.getAsJsonObject( json, "result" ) ); return create( identifier, group, template.width, template.height, template.ingredients, result, family ); } - protected abstract T create( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result, + protected abstract T create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ); @Nonnull @Override - public T read( @Nonnull Identifier identifier, @Nonnull PacketByteBuf buf ) + public T fromNetwork( @Nonnull ResourceLocation identifier, @Nonnull FriendlyByteBuf buf ) { int width = buf.readVarInt(); int height = buf.readVarInt(); - String group = buf.readString( Short.MAX_VALUE ); + String group = buf.readUtf( Short.MAX_VALUE ); - DefaultedList ingredients = DefaultedList.ofSize( width * height, Ingredient.EMPTY ); + NonNullList ingredients = NonNullList.withSize( width * height, Ingredient.EMPTY ); for( int i = 0; i < ingredients.size(); i++ ) { - ingredients.set( i, Ingredient.fromPacket( buf ) ); + ingredients.set( i, Ingredient.fromNetwork( buf ) ); } - ItemStack result = buf.readItemStack(); - ComputerFamily family = buf.readEnumConstant( ComputerFamily.class ); + ItemStack result = buf.readItem(); + ComputerFamily family = buf.readEnum( ComputerFamily.class ); return create( identifier, group, width, height, ingredients, result, family ); } @Override - public void write( @Nonnull PacketByteBuf buf, @Nonnull T recipe ) + public void write( @Nonnull FriendlyByteBuf buf, @Nonnull T recipe ) { buf.writeVarInt( recipe.getWidth() ); buf.writeVarInt( recipe.getHeight() ); - buf.writeString( recipe.getGroup() ); + buf.writeUtf( recipe.getGroup() ); for( Ingredient ingredient : recipe.getIngredients() ) { - ingredient.write( buf ); + ingredient.toNetwork( buf ); } - buf.writeItemStack( recipe.getOutput() ); - buf.writeEnumConstant( recipe.getFamily() ); + buf.writeItem( recipe.getResultItem() ); + buf.writeEnum( recipe.getFamily() ); } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java index b22c10b14..0a54e4f50 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -8,13 +8,12 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; public class ComputerUpgradeRecipe extends ComputerFamilyRecipe { @@ -22,14 +21,14 @@ public class ComputerUpgradeRecipe extends ComputerFamilyRecipe new ComputerFamilyRecipe.Serializer() { @Override - protected ComputerUpgradeRecipe create( Identifier identifier, String group, int width, int height, DefaultedList ingredients, + protected ComputerUpgradeRecipe create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { return new ComputerUpgradeRecipe( identifier, group, width, height, ingredients, result, family ); } }; - public ComputerUpgradeRecipe( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result, + public ComputerUpgradeRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { super( identifier, group, width, height, ingredients, result, family ); diff --git a/src/main/java/dan200/computercraft/shared/computer/upload/UploadResult.java b/src/main/java/dan200/computercraft/shared/computer/upload/UploadResult.java index 2c332c0ef..11398b04c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/upload/UploadResult.java +++ b/src/main/java/dan200/computercraft/shared/computer/upload/UploadResult.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.shared.computer.upload; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; public enum UploadResult { @@ -14,12 +14,12 @@ public enum UploadResult ERROR, CONFIRM_OVERWRITE; - public static final Text SUCCESS_TITLE = new TranslatableText( "gui.computercraft.upload.success" ); + public static final Component SUCCESS_TITLE = new TranslatableComponent( "gui.computercraft.upload.success" ); - public static final Text FAILED_TITLE = new TranslatableText( "gui.computercraft.upload.failed" ); - public static final Text COMPUTER_OFF_MSG = new TranslatableText( "gui.computercraft.upload.failed.computer_off" ); - public static final Text OUT_OF_SPACE_MSG = new TranslatableText( "gui.computercraft.upload.failed.out_of_space" ); - public static final Text TOO_MUCH_MSG = new TranslatableText( "gui.computercraft.upload.failed.too_much" ); + public static final Component FAILED_TITLE = new TranslatableComponent( "gui.computercraft.upload.failed" ); + public static final Component COMPUTER_OFF_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.computer_off" ); + public static final Component OUT_OF_SPACE_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.out_of_space" ); + public static final Component TOO_MUCH_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.too_much" ); - public static final Text UPLOAD_OVERWRITE = new TranslatableText( "gui.computercraft.upload.overwrite" ); + public static final Component UPLOAD_OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite" ); } diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index ee98295f1..f24697123 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -6,25 +6,24 @@ package dan200.computercraft.shared.data; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.loot.condition.LootCondition; -import net.minecraft.loot.condition.LootConditionType; -import net.minecraft.loot.context.LootContext; -import net.minecraft.loot.context.LootContextParameter; -import net.minecraft.loot.context.LootContextParameters; -import net.minecraft.util.Nameable; - import javax.annotation.Nonnull; +import net.minecraft.world.Nameable; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParam; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import java.util.Collections; import java.util.Set; /** * A loot condition which checks if the tile entity has a name. */ -public final class BlockNamedEntityLootCondition implements LootCondition +public final class BlockNamedEntityLootCondition implements LootItemCondition { public static final BlockNamedEntityLootCondition INSTANCE = new BlockNamedEntityLootCondition(); - public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final LootItemConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); public static final Builder BUILDER = () -> INSTANCE; private BlockNamedEntityLootCondition() @@ -34,20 +33,20 @@ public final class BlockNamedEntityLootCondition implements LootCondition @Override public boolean test( LootContext lootContext ) { - BlockEntity tile = lootContext.get( LootContextParameters.BLOCK_ENTITY ); + BlockEntity tile = lootContext.getParamOrNull( LootContextParams.BLOCK_ENTITY ); return tile instanceof Nameable && ((Nameable) tile).hasCustomName(); } @Nonnull @Override - public Set> getRequiredParameters() + public Set> getReferencedContextParams() { - return Collections.singleton( LootContextParameters.BLOCK_ENTITY ); + return Collections.singleton( LootContextParams.BLOCK_ENTITY ); } @Override @Nonnull - public LootConditionType getType() + public LootItemConditionType getType() { return TYPE; } diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index 8a45e575b..d26e63910 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -9,13 +9,12 @@ package dan200.computercraft.shared.data; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import net.minecraft.loot.condition.LootCondition; -import net.minecraft.loot.condition.LootConditionType; -import net.minecraft.util.JsonSerializer; - import javax.annotation.Nonnull; +import net.minecraft.world.level.storage.loot.Serializer; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; -public final class ConstantLootConditionSerializer implements JsonSerializer +public final class ConstantLootConditionSerializer implements Serializer { private final T instance; @@ -24,9 +23,9 @@ public final class ConstantLootConditionSerializer impl this.instance = instance; } - public static LootConditionType type( T condition ) + public static LootItemConditionType type( T condition ) { - return new LootConditionType( new ConstantLootConditionSerializer<>( condition ) ); + return new LootItemConditionType( new ConstantLootConditionSerializer<>( condition ) ); } @Override @@ -36,7 +35,7 @@ public final class ConstantLootConditionSerializer impl @Nonnull @Override - public T fromJson( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context ) + public T deserialize( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context ) { return instance; } diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java index 7b2717d29..6e7601a13 100644 --- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -7,24 +7,23 @@ package dan200.computercraft.shared.data; import dan200.computercraft.shared.computer.blocks.IComputerTile; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.loot.condition.LootCondition; -import net.minecraft.loot.condition.LootConditionType; -import net.minecraft.loot.context.LootContext; -import net.minecraft.loot.context.LootContextParameter; -import net.minecraft.loot.context.LootContextParameters; - import javax.annotation.Nonnull; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParam; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import java.util.Collections; import java.util.Set; /** * A loot condition which checks if the tile entity has has a non-0 ID. */ -public final class HasComputerIdLootCondition implements LootCondition +public final class HasComputerIdLootCondition implements LootItemCondition { public static final HasComputerIdLootCondition INSTANCE = new HasComputerIdLootCondition(); - public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final LootItemConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); public static final Builder BUILDER = () -> INSTANCE; private HasComputerIdLootCondition() @@ -34,20 +33,20 @@ public final class HasComputerIdLootCondition implements LootCondition @Override public boolean test( LootContext lootContext ) { - BlockEntity tile = lootContext.get( LootContextParameters.BLOCK_ENTITY ); + BlockEntity tile = lootContext.getParamOrNull( LootContextParams.BLOCK_ENTITY ); return tile instanceof IComputerTile && ((IComputerTile) tile).getComputerID() >= 0; } @Nonnull @Override - public Set> getRequiredParameters() + public Set> getReferencedContextParams() { - return Collections.singleton( LootContextParameters.BLOCK_ENTITY ); + return Collections.singleton( LootContextParams.BLOCK_ENTITY ); } @Override @Nonnull - public LootConditionType getType() + public LootItemConditionType getType() { return TYPE; } diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index debdffb46..fe48d81e5 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -6,25 +6,24 @@ package dan200.computercraft.shared.data; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.loot.condition.LootCondition; -import net.minecraft.loot.condition.LootConditionType; -import net.minecraft.loot.context.LootContext; -import net.minecraft.loot.context.LootContextParameter; -import net.minecraft.loot.context.LootContextParameters; - import javax.annotation.Nonnull; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParam; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import java.util.Collections; import java.util.Set; /** * A loot condition which checks if the entity is in creative mode. */ -public final class PlayerCreativeLootCondition implements LootCondition +public final class PlayerCreativeLootCondition implements LootItemCondition { public static final PlayerCreativeLootCondition INSTANCE = new PlayerCreativeLootCondition(); - public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final LootItemConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); public static final Builder BUILDER = () -> INSTANCE; private PlayerCreativeLootCondition() @@ -34,20 +33,20 @@ public final class PlayerCreativeLootCondition implements LootCondition @Override public boolean test( LootContext lootContext ) { - Entity entity = lootContext.get( LootContextParameters.THIS_ENTITY ); - return entity instanceof PlayerEntity && ((PlayerEntity) entity).getAbilities().creativeMode; + Entity entity = lootContext.getParamOrNull( LootContextParams.THIS_ENTITY ); + return entity instanceof Player && ((Player) entity).getAbilities().instabuild; } @Nonnull @Override - public Set> getRequiredParameters() + public Set> getReferencedContextParams() { - return Collections.singleton( LootContextParameters.THIS_ENTITY ); + return Collections.singleton( LootContextParams.THIS_ENTITY ); } @Override @Nonnull - public LootConditionType getType() + public LootItemConditionType getType() { return TYPE; } diff --git a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java index f973cf5a5..eaba346e6 100644 --- a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java @@ -15,8 +15,8 @@ import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; // A poor mod menu integration just for testing the monitor rendering changes we've been making :) @@ -28,7 +28,7 @@ public class ModMenuIntegration implements ModMenuApi { return parent -> { ConfigBuilder builder = ConfigBuilder.create().setParentScreen( parent ) - .setTitle( new LiteralText( "Computer Craft" ) ) + .setTitle( new TextComponent( "Computer Craft" ) ) .setSavingRunnable( () -> { Config.clientSpec.correct( Config.clientConfig ); Config.sync(); @@ -36,14 +36,14 @@ public class ModMenuIntegration implements ModMenuApi ComputerCraft.log.info( "Monitor renderer: {}", ComputerCraft.monitorRenderer ); } ); - ConfigCategory client = builder.getOrCreateCategory( new LiteralText( "Client" ) ); + ConfigCategory client = builder.getOrCreateCategory( new TextComponent( "Client" ) ); ConfigEntryBuilder entryBuilder = builder.entryBuilder(); - client.addEntry( entryBuilder.startEnumSelector( new LiteralText( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) + client.addEntry( entryBuilder.startEnumSelector( new TextComponent( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) .setDefaultValue( MonitorRenderer.BEST ) .setSaveConsumer( renderer -> { Config.clientConfig.set( "monitor_renderer", renderer ); } ) - .setTooltip( Text.of( Config.clientConfig.getComment( "monitor_renderer" ) ) ) + .setTooltip( Component.nullToEmpty( Config.clientConfig.getComment( "monitor_renderer" ) ) ) .build() ); return builder.build(); diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 3d656c87a..5e6b1e2d8 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -13,48 +13,47 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.util.Colour; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.ChatFormatting; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; import java.util.List; public class ItemDisk extends Item implements IMedia, IColouredItem { private static final String NBT_ID = "DiskId"; - public ItemDisk( Settings settings ) + public ItemDisk( Properties settings ) { super( settings ); } @Override - public void appendTooltip( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, TooltipContext options ) + public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List list, TooltipFlag options ) { if( options.isAdvanced() ) { int id = getDiskID( stack ); if( id >= 0 ) { - list.add( new TranslatableText( "gui.computercraft.tooltip.disk_id", id ).formatted( Formatting.GRAY ) ); + list.add( new TranslatableComponent( "gui.computercraft.tooltip.disk_id", id ).withStyle( ChatFormatting.GRAY ) ); } } } @Override - public void appendStacks( @Nonnull ItemGroup tabs, @Nonnull DefaultedList list ) + public void fillItemCategory( @Nonnull CreativeModeTab tabs, @Nonnull NonNullList list ) { - if( !isIn( tabs ) ) + if( !allowdedIn( tabs ) ) { return; } @@ -78,21 +77,21 @@ public class ItemDisk extends Item implements IMedia, IColouredItem { if( id >= 0 ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_ID, id ); } } public static int getDiskID( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } @Override public String getLabel( @Nonnull ItemStack stack ) { - return stack.hasCustomName() ? stack.getName() + return stack.hasCustomHoverName() ? stack.getHoverName() .getString() : null; } @@ -101,17 +100,17 @@ public class ItemDisk extends Item implements IMedia, IColouredItem { if( label != null ) { - stack.setCustomName( new LiteralText( label ) ); + stack.setHoverName( new TextComponent( label ) ); } else { - stack.removeCustomName(); + stack.resetHoverName(); } return true; } @Override - public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull Level world ) { int diskID = getDiskID( stack ); if( diskID < 0 ) diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 07ecffb99..1120116b5 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -9,19 +9,18 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.network.container.HeldItemContainerData; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.TypedActionResult; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; import java.util.List; public class ItemPrintout extends Item @@ -35,7 +34,7 @@ public class ItemPrintout extends Item private static final String NBT_LINE_COLOUR = "Color"; private final Type type; - public ItemPrintout( Settings settings, Type type ) + public ItemPrintout( Properties settings, Type type ) { super( settings ); this.type = type; @@ -55,12 +54,12 @@ public class ItemPrintout extends Item // Build NBT if( title != null ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putString( NBT_TITLE, title ); } if( text != null ) { - NbtCompound tag = stack.getOrCreateNbt(); + CompoundTag tag = stack.getOrCreateTag(); tag.putInt( NBT_PAGES, text.length / LINES_PER_PAGE ); for( int i = 0; i < text.length; i++ ) { @@ -72,7 +71,7 @@ public class ItemPrintout extends Item } if( colours != null ) { - NbtCompound tag = stack.getOrCreateNbt(); + CompoundTag tag = stack.getOrCreateTag(); for( int i = 0; i < colours.length; i++ ) { if( colours[i] != null ) @@ -105,7 +104,7 @@ public class ItemPrintout extends Item private static String[] getLines( @Nonnull ItemStack stack, String prefix ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); int numLines = getPageCount( stack ) * LINES_PER_PAGE; String[] lines = new String[numLines]; for( int i = 0; i < lines.length; i++ ) @@ -117,7 +116,7 @@ public class ItemPrintout extends Item public static int getPageCount( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_PAGES ) ? nbt.getInt( NBT_PAGES ) : 1; } @@ -128,31 +127,31 @@ public class ItemPrintout extends Item @Nonnull @Override - public TypedActionResult use( World world, @Nonnull PlayerEntity player, @Nonnull Hand hand ) + public InteractionResultHolder use( Level world, @Nonnull Player player, @Nonnull InteractionHand hand ) { - if( !world.isClient ) + if( !world.isClientSide ) { new HeldItemContainerData( hand ).open( player, new ContainerHeldItem.Factory( ComputerCraftRegistry.ModContainers.PRINTOUT, - player.getStackInHand( hand ), + player.getItemInHand( hand ), hand ) ); } - return new TypedActionResult<>( ActionResult.SUCCESS, player.getStackInHand( hand ) ); + return new InteractionResultHolder<>( InteractionResult.SUCCESS, player.getItemInHand( hand ) ); } @Override - public void appendTooltip( @Nonnull ItemStack stack, World world, @Nonnull List list, @Nonnull TooltipContext options ) + public void appendHoverText( @Nonnull ItemStack stack, Level world, @Nonnull List list, @Nonnull TooltipFlag options ) { String title = getTitle( stack ); if( title != null && !title.isEmpty() ) { - list.add( new LiteralText( title ) ); + list.add( new TextComponent( title ) ); } } public static String getTitle( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : null; } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index ae4e6e990..b00df1647 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -12,18 +12,17 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.filesystem.SubMount; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.Colour; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; import java.io.IOException; import java.util.List; @@ -33,7 +32,7 @@ public class ItemTreasureDisk extends Item implements IMedia private static final String NBT_COLOUR = "Colour"; private static final String NBT_SUB_PATH = "SubPath"; - public ItemTreasureDisk( Settings settings ) + public ItemTreasureDisk( Properties settings ) { super( settings ); } @@ -41,7 +40,7 @@ public class ItemTreasureDisk extends Item implements IMedia public static ItemStack create( String subPath, int colourIndex ) { ItemStack result = new ItemStack( ComputerCraftRegistry.ModItems.TREASURE_DISK ); - NbtCompound nbt = result.getOrCreateNbt(); + CompoundTag nbt = result.getOrCreateTag(); nbt.putString( NBT_SUB_PATH, subPath ); int slash = subPath.indexOf( '/' ); @@ -62,29 +61,29 @@ public class ItemTreasureDisk extends Item implements IMedia public static int getColour( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.BLUE.getHex(); } @Override - public void appendTooltip( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull TooltipContext tooltipOptions ) + public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List list, @Nonnull TooltipFlag tooltipOptions ) { String label = getTitle( stack ); if( !label.isEmpty() ) { - list.add( new LiteralText( label ) ); + list.add( new TextComponent( label ) ); } } @Override - public void appendStacks( @Nonnull ItemGroup group, @Nonnull DefaultedList stacks ) + public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList stacks ) { } @Nonnull private static String getTitle( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : "'alongtimeago' by dan200"; } @@ -95,7 +94,7 @@ public class ItemTreasureDisk extends Item implements IMedia } @Override - public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull Level world ) { IMount rootTreasure = getTreasureMount(); String subPath = getSubPath( stack ); @@ -128,7 +127,7 @@ public class ItemTreasureDisk extends Item implements IMedia @Nonnull private static String getSubPath( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_SUB_PATH ) ? nbt.getString( NBT_SUB_PATH ) : "dan200/alongtimeago"; } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 6a4a7f8d2..c090111dd 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -6,13 +6,12 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.api.media.IMedia; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.MusicDiscItem; -import net.minecraft.sound.SoundEvent; -import net.minecraft.text.TranslatableText; - import javax.annotation.Nonnull; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.RecordItem; /** * An implementation of IMedia for ItemRecords. @@ -35,22 +34,22 @@ public final class RecordMedia implements IMedia public String getAudioTitle( @Nonnull ItemStack stack ) { Item item = stack.getItem(); - if( !(item instanceof MusicDiscItem) ) + if( !(item instanceof RecordItem) ) { return null; } - return new TranslatableText( item.getTranslationKey() + ".desc" ).getString(); + return new TranslatableComponent( item.getDescriptionId() + ".desc" ).getString(); } @Override public SoundEvent getAudio( @Nonnull ItemStack stack ) { Item item = stack.getItem(); - if( !(item instanceof MusicDiscItem) ) + if( !(item instanceof RecordItem) ) { return null; } - return ((MusicDiscItem) item).getSound(); + return ((RecordItem) item).getSound(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index 748e61f91..61ac56ab1 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -10,40 +10,39 @@ import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.SpecialCraftingRecipe; -import net.minecraft.recipe.SpecialRecipeSerializer; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; -public class DiskRecipe extends SpecialCraftingRecipe +public class DiskRecipe extends CustomRecipe { - public static final RecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( DiskRecipe::new ); - private final Ingredient paper = Ingredient.ofItems( Items.PAPER ); + public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( DiskRecipe::new ); + private final Ingredient paper = Ingredient.of( Items.PAPER ); // TODO: Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE ); - private final Ingredient redstone = Ingredient.ofItems( Items.REDSTONE ); + private final Ingredient redstone = Ingredient.of( Items.REDSTONE ); - public DiskRecipe( Identifier id ) + public DiskRecipe( ResourceLocation id ) { super( id ); } @Override - public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inv, @Nonnull Level world ) { boolean paperFound = false; boolean redstoneFound = false; - for( int i = 0; i < inv.size(); i++ ) + for( int i = 0; i < inv.getContainerSize(); i++ ) { - ItemStack stack = inv.getStack( i ); + ItemStack stack = inv.getItem( i ); if( !stack.isEmpty() ) { @@ -75,13 +74,13 @@ public class DiskRecipe extends SpecialCraftingRecipe @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inv ) + public ItemStack craft( @Nonnull CraftingContainer inv ) { ColourTracker tracker = new ColourTracker(); - for( int i = 0; i < inv.size(); i++ ) + for( int i = 0; i < inv.getContainerSize(); i++ ) { - ItemStack stack = inv.getStack( i ); + ItemStack stack = inv.getItem( i ); if( stack.isEmpty() ) { @@ -99,7 +98,7 @@ public class DiskRecipe extends SpecialCraftingRecipe } @Override - public boolean fits( int x, int y ) + public boolean canCraftInDimensions( int x, int y ) { return x >= 2 && y >= 2; } @@ -113,7 +112,7 @@ public class DiskRecipe extends SpecialCraftingRecipe @Nonnull @Override - public ItemStack getOutput() + public ItemStack getResultItem() { return ItemDisk.createFromIDAndColour( -1, null, Colour.BLUE.getHex() ); } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index 421af7edf..2652c7018 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -7,46 +7,45 @@ package dan200.computercraft.shared.media.recipes; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.SpecialCraftingRecipe; -import net.minecraft.recipe.SpecialRecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; -public final class PrintoutRecipe extends SpecialCraftingRecipe +public final class PrintoutRecipe extends CustomRecipe { - public static final RecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( PrintoutRecipe::new ); - private final Ingredient paper = Ingredient.ofItems( Items.PAPER ); - private final Ingredient leather = Ingredient.ofItems( Items.LEATHER ); - private final Ingredient string = Ingredient.ofItems( Items.STRING ); + public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( PrintoutRecipe::new ); + private final Ingredient paper = Ingredient.of( Items.PAPER ); + private final Ingredient leather = Ingredient.of( Items.LEATHER ); + private final Ingredient string = Ingredient.of( Items.STRING ); - private PrintoutRecipe( Identifier id ) + private PrintoutRecipe( ResourceLocation id ) { super( id ); } @Nonnull @Override - public ItemStack getOutput() + public ItemStack getResultItem() { return ItemPrintout.createMultipleFromTitleAndText( null, null, null ); } @Override - public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { return !craft( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack craft( @Nonnull CraftingContainer inventory ) { // See if we match the recipe, and extract the input disk ID and dye colour int numPages = 0; @@ -59,7 +58,7 @@ public final class PrintoutRecipe extends SpecialCraftingRecipe { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack stack = inventory.getStack( x + y * inventory.getWidth() ); + ItemStack stack = inventory.getItem( x + y * inventory.getWidth() ); if( !stack.isEmpty() ) { if( stack.getItem() instanceof ItemPrintout && ((ItemPrintout) stack.getItem()).getType() != ItemPrintout.Type.BOOK ) @@ -153,7 +152,7 @@ public final class PrintoutRecipe extends SpecialCraftingRecipe } @Override - public boolean fits( int x, int y ) + public boolean canCraftInDimensions( int x, int y ) { return x >= 3 && y >= 3; } diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index e37f4411e..0d24ce401 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -21,28 +21,27 @@ import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.PacketContext; import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import net.minecraft.world.chunk.WorldChunk; - +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.Vec3; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; public final class NetworkHandler { - private static final Int2ObjectMap> packetReaders = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap> packetReaders = new Int2ObjectOpenHashMap<>(); private static final Object2IntMap> packetIds = new Object2IntOpenHashMap<>(); - private static final Identifier ID = new Identifier( ComputerCraft.MOD_ID, "main" ); + private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "main" ); private NetworkHandler() { @@ -79,7 +78,7 @@ public final class NetworkHandler registerMainThread( 19, UploadResultMessage.class, UploadResultMessage::new ); } - private static void receive( PacketContext context, PacketByteBuf buffer ) + private static void receive( PacketContext context, FriendlyByteBuf buffer ) { int type = buffer.readByte(); packetReaders.get( type ) @@ -94,7 +93,7 @@ public final class NetworkHandler * @param id The identifier for this packet type * @param decoder The factory for this type of packet. */ - private static void registerMainThread( int id, Class type, Function decoder ) + private static void registerMainThread( int id, Class type, Function decoder ) { packetIds.put( type, id ); packetReaders.put( id, ( context, buf ) -> { @@ -111,52 +110,52 @@ public final class NetworkHandler .getClass(); } - private static PacketByteBuf encode( NetworkMessage message ) + private static FriendlyByteBuf encode( NetworkMessage message ) { - PacketByteBuf buf = new PacketByteBuf( Unpooled.buffer() ); + FriendlyByteBuf buf = new FriendlyByteBuf( Unpooled.buffer() ); buf.writeByte( packetIds.getInt( message.getClass() ) ); message.toBytes( buf ); return buf; } - public static void sendToPlayer( PlayerEntity player, NetworkMessage packet ) + public static void sendToPlayer( Player player, NetworkMessage packet ) { - ((ServerPlayerEntity) player).networkHandler.sendPacket( new CustomPayloadS2CPacket( ID, encode( packet ) ) ); + ((ServerPlayer) player).connection.send( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } public static void sendToAllPlayers( NetworkMessage packet ) { MinecraftServer server = GameInstanceUtils.getServer(); - server.getPlayerManager() - .sendToAll( new CustomPayloadS2CPacket( ID, encode( packet ) ) ); + server.getPlayerList() + .broadcastAll( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } public static void sendToAllPlayers( MinecraftServer server, NetworkMessage packet ) { - server.getPlayerManager() - .sendToAll( new CustomPayloadS2CPacket( ID, encode( packet ) ) ); + server.getPlayerList() + .broadcastAll( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } @Environment( EnvType.CLIENT ) public static void sendToServer( NetworkMessage packet ) { - MinecraftClient.getInstance().player.networkHandler.sendPacket( new CustomPayloadC2SPacket( ID, encode( packet ) ) ); + Minecraft.getInstance().player.connection.send( new ServerboundCustomPayloadPacket( ID, encode( packet ) ) ); } - public static void sendToAllAround( NetworkMessage packet, World world, Vec3d pos, double range ) + public static void sendToAllAround( NetworkMessage packet, Level world, Vec3 pos, double range ) { world.getServer() - .getPlayerManager() - .sendToAround( null, pos.x, pos.y, pos.z, range, world.getRegistryKey(), new CustomPayloadS2CPacket( ID, encode( packet ) ) ); + .getPlayerList() + .broadcast( null, pos.x, pos.y, pos.z, range, world.dimension(), new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } - public static void sendToAllTracking( NetworkMessage packet, WorldChunk chunk ) + public static void sendToAllTracking( NetworkMessage packet, LevelChunk chunk ) { - for( PlayerEntity player : chunk.getWorld().getPlayers() ) + for( Player player : chunk.getLevel().players() ) { - if ( chunk.getWorld().getRegistryKey().getValue() == player.getEntityWorld().getRegistryKey().getValue() && player.getChunkPos().equals( chunk.getPos() ) ) + if ( chunk.getLevel().dimension().location() == player.getCommandSenderWorld().dimension().location() && player.chunkPosition().equals( chunk.getPos() ) ) { - ((ServerPlayerEntity) player).networkHandler.sendPacket( new CustomPayloadS2CPacket( ID, encode( packet ) ) ); + ((ServerPlayer) player).connection.send( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index b1ab12c69..1f4c387b4 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -7,8 +7,7 @@ package dan200.computercraft.shared.network; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; /** @@ -23,7 +22,7 @@ public interface NetworkMessage * * @param buf The buffer to write data to. */ - void toBytes( @Nonnull PacketByteBuf buf ); + void toBytes( @Nonnull FriendlyByteBuf buf ); /** * Handle this {@link NetworkMessage}. diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index c21f60edf..224e3c4fe 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -12,9 +12,8 @@ import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.text.Text; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import javax.annotation.Nonnull; public class ChatTableClientMessage implements NetworkMessage @@ -30,17 +29,17 @@ public class ChatTableClientMessage implements NetworkMessage this.table = table; } - public ChatTableClientMessage( @Nonnull PacketByteBuf buf ) + public ChatTableClientMessage( @Nonnull FriendlyByteBuf buf ) { int id = buf.readVarInt(); int columns = buf.readVarInt(); TableBuilder table; if( buf.readBoolean() ) { - Text[] headers = new Text[columns]; + Component[] headers = new Component[columns]; for( int i = 0; i < columns; i++ ) { - headers[i] = buf.readText(); + headers[i] = buf.readComponent(); } table = new TableBuilder( id, headers ); } @@ -52,10 +51,10 @@ public class ChatTableClientMessage implements NetworkMessage int rows = buf.readVarInt(); for( int i = 0; i < rows; i++ ) { - Text[] row = new Text[columns]; + Component[] row = new Component[columns]; for( int j = 0; j < columns; j++ ) { - row[j] = buf.readText(); + row[j] = buf.readComponent(); } table.row( row ); } @@ -65,26 +64,26 @@ public class ChatTableClientMessage implements NetworkMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeVarInt( table.getId() ); buf.writeVarInt( table.getColumns() ); buf.writeBoolean( table.getHeaders() != null ); if( table.getHeaders() != null ) { - for( Text header : table.getHeaders() ) + for( Component header : table.getHeaders() ) { - buf.writeText( header ); + buf.writeComponent( header ); } } buf.writeVarInt( table.getRows() .size() ); - for( Text[] row : table.getRows() ) + for( Component[] row : table.getRows() ) { - for( Text column : row ) + for( Component column : row ) { - buf.writeText( column ); + buf.writeComponent( column ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java index ad04ce2aa..a9611c524 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java @@ -9,9 +9,8 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.network.NetworkMessage; -import net.minecraft.network.PacketByteBuf; - import javax.annotation.Nonnull; +import net.minecraft.network.FriendlyByteBuf; /** * A packet, which performs an action on a {@link ClientComputer}. @@ -25,7 +24,7 @@ public abstract class ComputerClientMessage implements NetworkMessage this.instanceId = instanceId; } - public ComputerClientMessage( @Nonnull PacketByteBuf buf ) + public ComputerClientMessage( @Nonnull FriendlyByteBuf buf ) { instanceId = buf.readVarInt(); } @@ -36,7 +35,7 @@ public abstract class ComputerClientMessage implements NetworkMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeVarInt( instanceId ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index 405d7e29e..85f271ec4 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -9,9 +9,8 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; /** @@ -20,7 +19,7 @@ import javax.annotation.Nonnull; public class ComputerDataClientMessage extends ComputerClientMessage { private final ComputerState state; - private final NbtCompound userData; + private final CompoundTag userData; public ComputerDataClientMessage( ServerComputer computer ) { @@ -29,18 +28,18 @@ public class ComputerDataClientMessage extends ComputerClientMessage userData = computer.getUserData(); } - public ComputerDataClientMessage( @Nonnull PacketByteBuf buf ) + public ComputerDataClientMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); - state = buf.readEnumConstant( ComputerState.class ); + state = buf.readEnum( ComputerState.class ); userData = buf.readNbt(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); - buf.writeEnumConstant( state ); + buf.writeEnum( state ); buf.writeNbt( userData ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java index 7ae774055..322c11cc4 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.FriendlyByteBuf; public class ComputerDeletedClientMessage extends ComputerClientMessage { @@ -17,7 +17,7 @@ public class ComputerDeletedClientMessage extends ComputerClientMessage super( instanceId ); } - public ComputerDeletedClientMessage( PacketByteBuf buffer ) + public ComputerDeletedClientMessage( FriendlyByteBuf buffer ) { super( buffer ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index a6a7b745c..6e0b4cf1a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -7,8 +7,7 @@ package dan200.computercraft.shared.network.client; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; public class ComputerTerminalClientMessage extends ComputerClientMessage @@ -21,14 +20,14 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage this.state = state; } - public ComputerTerminalClientMessage( @Nonnull PacketByteBuf buf ) + public ComputerTerminalClientMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); state = new TerminalState( buf ); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); state.write( buf ); diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java index 740171dab..b003a6a88 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -8,12 +8,11 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.math.BlockPos; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nonnull; public class MonitorClientMessage implements NetworkMessage @@ -27,14 +26,14 @@ public class MonitorClientMessage implements NetworkMessage this.state = state; } - public MonitorClientMessage( @Nonnull PacketByteBuf buf ) + public MonitorClientMessage( @Nonnull FriendlyByteBuf buf ) { pos = buf.readBlockPos(); state = new TerminalState( buf ); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeBlockPos( pos ); state.write( buf ); @@ -43,13 +42,13 @@ public class MonitorClientMessage implements NetworkMessage @Override public void handle( PacketContext context ) { - ClientPlayerEntity player = MinecraftClient.getInstance().player; - if( player == null || player.world == null ) + LocalPlayer player = Minecraft.getInstance().player; + if( player == null || player.level == null ) { return; } - BlockEntity te = player.world.getBlockEntity( pos ); + BlockEntity te = player.level.getBlockEntity( pos ); if( !(te instanceof TileMonitor) ) { return; diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 35587fdcf..cc5c2a49a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -10,13 +10,12 @@ import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.sound.SoundEvent; -import net.minecraft.text.LiteralText; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; - +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.sounds.SoundEvent; import javax.annotation.Nonnull; /** @@ -46,13 +45,13 @@ public class PlayRecordClientMessage implements NetworkMessage soundEvent = null; } - public PlayRecordClientMessage( PacketByteBuf buf ) + public PlayRecordClientMessage( FriendlyByteBuf buf ) { pos = buf.readBlockPos(); if( buf.readBoolean() ) { - name = buf.readString( Short.MAX_VALUE ); - soundEvent = Registry.SOUND_EVENT.get( buf.readIdentifier() ); + name = buf.readUtf( Short.MAX_VALUE ); + soundEvent = Registry.SOUND_EVENT.get( buf.readResourceLocation() ); } else { @@ -62,7 +61,7 @@ public class PlayRecordClientMessage implements NetworkMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeBlockPos( pos ); if( soundEvent == null ) @@ -72,8 +71,8 @@ public class PlayRecordClientMessage implements NetworkMessage else { buf.writeBoolean( true ); - buf.writeString( name ); - buf.writeIdentifier( soundEvent.getId() ); + buf.writeUtf( name ); + buf.writeResourceLocation( soundEvent.getLocation() ); } } @@ -81,11 +80,11 @@ public class PlayRecordClientMessage implements NetworkMessage @Environment( EnvType.CLIENT ) public void handle( PacketContext context ) { - MinecraftClient mc = MinecraftClient.getInstance(); - mc.worldRenderer.playSong( soundEvent, pos ); + Minecraft mc = Minecraft.getInstance(); + mc.levelRenderer.playStreamingMusic( soundEvent, pos ); if( name != null ) { - mc.inGameHud.setRecordPlayingOverlay( new LiteralText( name ) ); + mc.gui.setNowPlaying( new TextComponent( name ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java index 9bfe74a03..a8e131ca2 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java @@ -10,9 +10,8 @@ import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.math.Vec3d; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.UUID; @@ -26,27 +25,27 @@ import java.util.UUID; public class SpeakerMoveClientMessage implements NetworkMessage { private final UUID source; - private final Vec3d pos; + private final Vec3 pos; - public SpeakerMoveClientMessage( UUID source, Vec3d pos ) + public SpeakerMoveClientMessage( UUID source, Vec3 pos ) { this.source = source; this.pos = pos; } - public SpeakerMoveClientMessage( PacketByteBuf buf ) + public SpeakerMoveClientMessage( FriendlyByteBuf buf ) { - source = buf.readUuid(); - pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() ); + source = buf.readUUID(); + pos = new Vec3( buf.readDouble(), buf.readDouble(), buf.readDouble() ); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { - buf.writeUuid( source ); - buf.writeDouble( pos.getX() ); - buf.writeDouble( pos.getY() ); - buf.writeDouble( pos.getZ() ); + buf.writeUUID( source ); + buf.writeDouble( pos.x() ); + buf.writeDouble( pos.y() ); + buf.writeDouble( pos.z() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java index a913d1ea9..9c93516f9 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java @@ -10,10 +10,9 @@ import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Vec3d; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.UUID; @@ -27,12 +26,12 @@ import java.util.UUID; public class SpeakerPlayClientMessage implements NetworkMessage { private final UUID source; - private final Vec3d pos; - private final Identifier sound; + private final Vec3 pos; + private final ResourceLocation sound; private final float volume; private final float pitch; - public SpeakerPlayClientMessage( UUID source, Vec3d pos, Identifier event, float volume, float pitch ) + public SpeakerPlayClientMessage( UUID source, Vec3 pos, ResourceLocation event, float volume, float pitch ) { this.source = source; this.pos = pos; @@ -41,23 +40,23 @@ public class SpeakerPlayClientMessage implements NetworkMessage this.pitch = pitch; } - public SpeakerPlayClientMessage( PacketByteBuf buf ) + public SpeakerPlayClientMessage( FriendlyByteBuf buf ) { - source = buf.readUuid(); - pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() ); - sound = buf.readIdentifier(); + source = buf.readUUID(); + pos = new Vec3( buf.readDouble(), buf.readDouble(), buf.readDouble() ); + sound = buf.readResourceLocation(); volume = buf.readFloat(); pitch = buf.readFloat(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { - buf.writeUuid( source ); - buf.writeDouble( pos.getX() ); - buf.writeDouble( pos.getY() ); - buf.writeDouble( pos.getZ() ); - buf.writeIdentifier( sound ); + buf.writeUUID( source ); + buf.writeDouble( pos.x() ); + buf.writeDouble( pos.y() ); + buf.writeDouble( pos.z() ); + buf.writeResourceLocation( sound ); buf.writeFloat( volume ); buf.writeFloat( pitch ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java index bdc630244..5a14a23a6 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java @@ -10,8 +10,7 @@ import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; import java.util.UUID; @@ -31,15 +30,15 @@ public class SpeakerStopClientMessage implements NetworkMessage this.source = source; } - public SpeakerStopClientMessage( PacketByteBuf buf ) + public SpeakerStopClientMessage( FriendlyByteBuf buf ) { - source = buf.readUuid(); + source = buf.readUUID(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { - buf.writeUuid( source ); + buf.writeUUID( source ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java index 0ecfe413c..49d704f8b 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java +++ b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java @@ -11,9 +11,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; -import net.minecraft.network.PacketByteBuf; - import javax.annotation.Nullable; +import net.minecraft.network.FriendlyByteBuf; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -62,11 +61,11 @@ public class TerminalState height = terminal.getHeight(); ByteBuf buf = buffer = Unpooled.buffer(); - terminal.write( new PacketByteBuf( buf ) ); + terminal.write( new FriendlyByteBuf( buf ) ); } } - public TerminalState( PacketByteBuf buf ) + public TerminalState( FriendlyByteBuf buf ) { colour = buf.readBoolean(); compress = buf.readBoolean(); @@ -124,7 +123,7 @@ public class TerminalState } } - public void write( PacketByteBuf buf ) + public void write( FriendlyByteBuf buf ) { buf.writeBoolean( colour ); buf.writeBoolean( compress ); @@ -191,6 +190,6 @@ public class TerminalState { throw new NullPointerException( "buffer" ); } - terminal.read( new PacketByteBuf( buffer ) ); + terminal.read( new FriendlyByteBuf( buffer ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java b/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java index 012908bd4..3dbaa8406 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java @@ -10,11 +10,10 @@ import dan200.computercraft.client.gui.OptionScreen; import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.text.Text; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import javax.annotation.Nonnull; public class UploadResultMessage implements NetworkMessage @@ -23,33 +22,33 @@ public class UploadResultMessage implements NetworkMessage public static final UploadResultMessage OUT_OF_SPACE = new UploadResultMessage( UploadResult.ERROR, UploadResult.OUT_OF_SPACE_MSG ); private final UploadResult result; - private final Text message; + private final Component message; - public UploadResultMessage( UploadResult result, Text message ) + public UploadResultMessage( UploadResult result, Component message ) { this.result = result; this.message = message; } - public UploadResultMessage( @Nonnull PacketByteBuf buf ) + public UploadResultMessage( @Nonnull FriendlyByteBuf buf ) { - result = buf.readEnumConstant( UploadResult.class ); - message = buf.readText(); + result = buf.readEnum( UploadResult.class ); + message = buf.readComponent(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { - buf.writeEnumConstant( result ); - buf.writeText( message ); + buf.writeEnum( result ); + buf.writeComponent( message ); } @Override public void handle( PacketContext context ) { - MinecraftClient minecraft = MinecraftClient.getInstance(); + Minecraft minecraft = Minecraft.getInstance(); - Screen screen = OptionScreen.unwrap( minecraft.currentScreen ); + Screen screen = OptionScreen.unwrap( minecraft.screen ); if( screen instanceof ComputerScreenBase ) { ((ComputerScreenBase) screen).uploadResult( result, message ); diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java index 7edd25185..f39a12acf 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.FriendlyByteBuf; public class ComputerContainerData implements ContainerData { @@ -21,17 +21,17 @@ public class ComputerContainerData implements ContainerData family = computer.getFamily(); } - public ComputerContainerData( PacketByteBuf byteBuf ) + public ComputerContainerData( FriendlyByteBuf byteBuf ) { id = byteBuf.readInt(); - family = byteBuf.readEnumConstant( ComputerFamily.class ); + family = byteBuf.readEnum( ComputerFamily.class ); } @Override - public void toBytes( PacketByteBuf buf ) + public void toBytes( FriendlyByteBuf buf ) { buf.writeInt( id ); - buf.writeEnumConstant( family ); + buf.writeEnum( family ); } public int getInstanceId() diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index c29d774b8..9f04a309a 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -7,14 +7,13 @@ package dan200.computercraft.shared.network.container; import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.util.Identifier; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +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.inventory.MenuType; import javax.annotation.Nonnull; import java.util.function.Function; @@ -23,7 +22,7 @@ import java.util.function.Function; */ public interface ContainerData { - static ScreenHandlerType toType( Identifier identifier, Function reader, + static MenuType toType( ResourceLocation identifier, Function reader, Factory factory ) { return ScreenHandlerRegistry.registerExtended( identifier, @@ -31,7 +30,7 @@ public interface ContainerData playerInventory, reader.apply( packetByteBuf ) ) ); } - static ScreenHandlerType toType( Identifier identifier, ScreenHandlerType type, Function reader, + static MenuType toType( ResourceLocation identifier, MenuType type, Function reader, FixedFactory factory ) { return ScreenHandlerRegistry.registerExtended( identifier, @@ -40,21 +39,21 @@ public interface ContainerData reader.apply( packetByteBuf ) ) ); } - void toBytes( PacketByteBuf buf ); + void toBytes( FriendlyByteBuf buf ); - default void open( PlayerEntity player, NamedScreenHandlerFactory owner ) + default void open( Player player, MenuProvider owner ) { - if ( player.world.isClient ) return; - player.openHandledScreen( owner ); + if ( player.level.isClientSide ) return; + player.openMenu( owner ); } - interface Factory + interface Factory { - C create( int id, @Nonnull PlayerInventory inventory, T data ); + C create( int id, @Nonnull Inventory inventory, T data ); } - interface FixedFactory + interface FixedFactory { - C create( ScreenHandlerType type, int id, @Nonnull PlayerInventory inventory, T data ); + C create( MenuType type, int id, @Nonnull Inventory inventory, T data ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index a32e35af0..a63f6da75 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -7,10 +7,9 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.common.ContainerHeldItem; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Hand; - import javax.annotation.Nonnull; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.InteractionHand; /** * Opens a printout GUI based on the currently held item. @@ -20,26 +19,26 @@ import javax.annotation.Nonnull; */ public class HeldItemContainerData implements ContainerData { - private final Hand hand; + private final InteractionHand hand; - public HeldItemContainerData( Hand hand ) + public HeldItemContainerData( InteractionHand hand ) { this.hand = hand; } - public HeldItemContainerData( PacketByteBuf buffer ) + public HeldItemContainerData( FriendlyByteBuf buffer ) { - hand = buffer.readEnumConstant( Hand.class ); + hand = buffer.readEnum( InteractionHand.class ); } @Override - public void toBytes( PacketByteBuf buf ) + public void toBytes( FriendlyByteBuf buf ) { - buf.writeEnumConstant( hand ); + buf.writeEnum( hand ); } @Nonnull - public Hand getHand() + public InteractionHand getHand() { return hand; } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index 7999ca681..dc4cf0850 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -8,9 +8,8 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.network.PacketByteBuf; - import javax.annotation.Nonnull; +import net.minecraft.network.FriendlyByteBuf; /** * View an arbitrary computer on the client. @@ -37,7 +36,7 @@ public class ViewComputerContainerData extends ComputerContainerData } } - public ViewComputerContainerData( PacketByteBuf buffer ) + public ViewComputerContainerData( FriendlyByteBuf buffer ) { super( buffer ); width = buffer.readVarInt(); @@ -45,7 +44,7 @@ public class ViewComputerContainerData extends ComputerContainerData } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); buf.writeVarInt( width ); diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index 00395bbca..d9bf0e045 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -9,8 +9,7 @@ package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; public class ComputerActionServerMessage extends ComputerServerMessage @@ -23,17 +22,17 @@ public class ComputerActionServerMessage extends ComputerServerMessage this.action = action; } - public ComputerActionServerMessage( @Nonnull PacketByteBuf buf ) + public ComputerActionServerMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); - action = buf.readEnumConstant( Action.class ); + action = buf.readEnum( Action.class ); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); - buf.writeEnumConstant( action ); + buf.writeEnum( action ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index 3acf35e38..a4444ca44 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -11,8 +11,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; /** @@ -29,13 +28,13 @@ public abstract class ComputerServerMessage implements NetworkMessage this.instanceId = instanceId; } - public ComputerServerMessage( @Nonnull PacketByteBuf buf ) + public ComputerServerMessage( @Nonnull FriendlyByteBuf buf ) { instanceId = buf.readVarInt(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeVarInt( instanceId ); } diff --git a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java index 557433f63..038bb9278 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java @@ -8,9 +8,8 @@ package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; import javax.annotation.Nonnull; public class ContinueUploadMessage extends ComputerServerMessage @@ -23,14 +22,14 @@ public class ContinueUploadMessage extends ComputerServerMessage this.overwrite = overwrite; } - public ContinueUploadMessage( @Nonnull PacketByteBuf buf ) + public ContinueUploadMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); overwrite = buf.readBoolean(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); buf.writeBoolean( overwrite ); @@ -39,7 +38,7 @@ public class ContinueUploadMessage extends ComputerServerMessage @Override protected void handle( PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) { - ServerPlayerEntity player = (ServerPlayerEntity) context.getPlayer(); + ServerPlayer player = (ServerPlayer) context.getPlayer(); if( player != null ) container.confirmUpload( player, overwrite ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index cf00e23f0..b2408449b 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -10,8 +10,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; public class KeyEventServerMessage extends ComputerServerMessage @@ -30,7 +29,7 @@ public class KeyEventServerMessage extends ComputerServerMessage this.key = key; } - public KeyEventServerMessage( @Nonnull PacketByteBuf buf ) + public KeyEventServerMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); type = buf.readByte(); @@ -38,7 +37,7 @@ public class KeyEventServerMessage extends ComputerServerMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); buf.writeByte( type ); diff --git a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index 872f168ed..5959fca6b 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -10,8 +10,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; public class MouseEventServerMessage extends ComputerServerMessage @@ -35,7 +34,7 @@ public class MouseEventServerMessage extends ComputerServerMessage this.y = y; } - public MouseEventServerMessage( @Nonnull PacketByteBuf buf ) + public MouseEventServerMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); type = buf.readByte(); @@ -45,7 +44,7 @@ public class MouseEventServerMessage extends ComputerServerMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); buf.writeByte( type ); diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index 730d7b6f9..991ee5a27 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -10,9 +10,8 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.util.NBTUtil; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -34,20 +33,20 @@ public class QueueEventServerMessage extends ComputerServerMessage this.args = args; } - public QueueEventServerMessage( @Nonnull PacketByteBuf buf ) + public QueueEventServerMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); - event = buf.readString( Short.MAX_VALUE ); + event = buf.readUtf( Short.MAX_VALUE ); - NbtCompound args = buf.readNbt(); + CompoundTag args = buf.readNbt(); this.args = args == null ? null : NBTUtil.decodeObjects( args ); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); - buf.writeString( event ); + buf.writeUtf( event ); buf.writeNbt( args == null ? null : NBTUtil.encodeObjects( args ) ); } diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java index af7f8b29d..f7da4af24 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java @@ -10,8 +10,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; - +import net.minecraft.network.FriendlyByteBuf; import javax.annotation.Nonnull; public class RequestComputerMessage implements NetworkMessage @@ -23,13 +22,13 @@ public class RequestComputerMessage implements NetworkMessage this.instance = instance; } - public RequestComputerMessage( @Nonnull PacketByteBuf buf ) + public RequestComputerMessage( @Nonnull FriendlyByteBuf buf ) { instance = buf.readVarInt(); } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { buf.writeVarInt( instance ); } diff --git a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java index 136ce08bb..8a1bd4f66 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java @@ -13,9 +13,8 @@ import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.network.NetworkHandler; import io.netty.handler.codec.DecoderException; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; import javax.annotation.Nonnull; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -47,10 +46,10 @@ public class UploadFileMessage extends ComputerServerMessage this.slices = slices; } - public UploadFileMessage( @Nonnull PacketByteBuf buf ) + public UploadFileMessage( @Nonnull FriendlyByteBuf buf ) { super( buf ); - uuid = buf.readUuid(); + uuid = buf.readUUID(); int flag = this.flag = buf.readByte(); int totalSize = 0; @@ -62,7 +61,7 @@ public class UploadFileMessage extends ComputerServerMessage List files = this.files = new ArrayList<>( nFiles ); for( int i = 0; i < nFiles; i++ ) { - String name = buf.readString( MAX_FILE_NAME ); + String name = buf.readUtf( MAX_FILE_NAME ); int size = buf.readVarInt(); if( size > MAX_SIZE || (totalSize += size) >= MAX_SIZE ) { @@ -99,10 +98,10 @@ public class UploadFileMessage extends ComputerServerMessage } @Override - public void toBytes( @Nonnull PacketByteBuf buf ) + public void toBytes( @Nonnull FriendlyByteBuf buf ) { super.toBytes( buf ); - buf.writeUuid( uuid ); + buf.writeUUID( uuid ); buf.writeByte( flag ); if( (flag & FLAG_FIRST) != 0 ) @@ -110,7 +109,7 @@ public class UploadFileMessage extends ComputerServerMessage buf.writeVarInt( files.size() ); for( FileUpload file : files ) { - buf.writeString( file.getName(), MAX_FILE_NAME ); + buf.writeUtf( file.getName(), MAX_FILE_NAME ); buf.writeVarInt( file.getLength() ); buf.writeBytes( file.getChecksum() ); } @@ -175,7 +174,7 @@ public class UploadFileMessage extends ComputerServerMessage @Override protected void handle( PacketContext context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) { - ServerPlayerEntity player = (ServerPlayerEntity) context.getPlayer(); + ServerPlayer player = (ServerPlayer) context.getPlayer(); if( player != null ) { if( (flag & FLAG_FIRST) != 0 ) container.startUpload( uuid, files ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index c812dd91b..b6ada9750 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -10,10 +10,9 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.computer.apis.CommandAPI; -import net.minecraft.block.entity.CommandBlockBlockEntity; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.CommandBlockEntity; /** * This peripheral allows you to interact with command blocks. @@ -26,11 +25,11 @@ import javax.annotation.Nonnull; */ public class CommandBlockPeripheral implements IPeripheral { - private static final Identifier CAP_ID = new Identifier( ComputerCraft.MOD_ID, "command_block" ); + private static final ResourceLocation CAP_ID = new ResourceLocation( ComputerCraft.MOD_ID, "command_block" ); - private final CommandBlockBlockEntity commandBlock; + private final CommandBlockEntity commandBlock; - public CommandBlockPeripheral( CommandBlockBlockEntity commandBlock ) + public CommandBlockPeripheral( CommandBlockEntity commandBlock ) { this.commandBlock = commandBlock; } @@ -63,7 +62,7 @@ public class CommandBlockPeripheral implements IPeripheral @LuaFunction( mainThread = true ) public final String getCommand() { - return commandBlock.getCommandExecutor() + return commandBlock.getCommandBlock() .getCommand(); } @@ -75,10 +74,10 @@ public class CommandBlockPeripheral implements IPeripheral @LuaFunction( mainThread = true ) public final void setCommand( String command ) { - commandBlock.getCommandExecutor() + commandBlock.getCommandBlock() .setCommand( command ); - commandBlock.getCommandExecutor() - .markDirty(); + commandBlock.getCommandBlock() + .onUpdated(); } /** @@ -91,9 +90,9 @@ public class CommandBlockPeripheral implements IPeripheral @LuaFunction( mainThread = true ) public final Object[] runCommand() { - commandBlock.getCommandExecutor() - .execute( commandBlock.getWorld() ); - int result = commandBlock.getCommandExecutor() + commandBlock.getCommandBlock() + .performCommand( commandBlock.getLevel() ); + int result = commandBlock.getCommandBlock() .getSuccessCount(); return result > 0 ? new Object[] { true } : new Object[] { false, "Command failed" }; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java index 295054c01..37e05fbc6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -8,99 +8,98 @@ package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityTicker; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.stat.Stats; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.EnumProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.Nameable; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.stats.Stats; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +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.block.state.properties.EnumProperty; public class BlockDiskDrive extends BlockGeneric { - static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; - static final EnumProperty STATE = EnumProperty.of( "state", DiskDriveState.class ); + static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + static final EnumProperty STATE = EnumProperty.create( "state", DiskDriveState.class ); - public BlockDiskDrive( Settings settings ) + public BlockDiskDrive( Properties settings ) { super( settings, ComputerCraftRegistry.ModTiles.DISK_DRIVE ); - setDefaultState( getStateManager().getDefaultState() - .with( FACING, Direction.NORTH ) - .with( STATE, DiskDriveState.EMPTY ) ); + registerDefaultState( getStateDefinition().any() + .setValue( FACING, Direction.NORTH ) + .setValue( STATE, DiskDriveState.EMPTY ) ); } @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, - placement.getPlayerFacing() + return defaultBlockState().setValue( FACING, + placement.getHorizontalDirection() .getOpposite() ); } @Nullable @Override - public BlockEntityTicker getTicker( World world, BlockState state, BlockEntityType type ) + public BlockEntityTicker getTicker( Level world, BlockState state, BlockEntityType type ) { - return world.isClient ? null : BlockDiskDrive.checkType( type, ComputerCraftRegistry.ModTiles.DISK_DRIVE, TileDiskDrive::tick ); + return world.isClientSide ? null : BlockDiskDrive.createTickerHelper( type, ComputerCraftRegistry.ModTiles.DISK_DRIVE, TileDiskDrive::tick ); } @Override - public void afterBreak( - @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity te, @Nonnull ItemStack stack + public void playerDestroy( + @Nonnull Level world, @Nonnull Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity te, @Nonnull ItemStack stack ) { if( te instanceof Nameable && ((Nameable) te).hasCustomName() ) { - player.incrementStat( Stats.MINED.getOrCreateStat( this ) ); - player.addExhaustion( 0.005F ); + player.awardStat( Stats.BLOCK_MINED.get( this ) ); + player.causeFoodExhaustion( 0.005F ); ItemStack result = new ItemStack( this ); - result.setCustomName( ((Nameable) te).getCustomName() ); - dropStack( world, pos, result ); + result.setHoverName( ((Nameable) te).getCustomName() ); + popResource( world, pos, result ); } else { - super.afterBreak( world, player, pos, state, te, stack ); + super.playerDestroy( world, player, pos, state, te, stack ); } } @Override - public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) { - if( stack.hasCustomName() ) + if( stack.hasCustomHoverName() ) { BlockEntity tileentity = world.getBlockEntity( pos ); if( tileentity instanceof TileDiskDrive ) { - ((TileDiskDrive) tileentity).customName = stack.getName(); + ((TileDiskDrive) tileentity).customName = stack.getHoverName(); } } } @Override - protected void appendProperties( StateManager.Builder properties ) + protected void createBlockStateDefinition( StateDefinition.Builder properties ) { properties.add( FACING, STATE ); } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileDiskDrive( ComputerCraftRegistry.ModTiles.DISK_DRIVE, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index 385fe16b1..a5d2245d7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -7,26 +7,25 @@ package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.shared.ComputerCraftRegistry; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.SimpleInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.slot.Slot; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.SimpleContainer; +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.Slot; +import net.minecraft.world.item.ItemStack; -public class ContainerDiskDrive extends ScreenHandler +public class ContainerDiskDrive extends AbstractContainerMenu { - private final Inventory inventory; + private final Container inventory; - public ContainerDiskDrive( int id, PlayerInventory player ) + public ContainerDiskDrive( int id, Inventory player ) { - this( id, player, new SimpleInventory( 1 ) ); + this( id, player, new SimpleContainer( 1 ) ); } - public ContainerDiskDrive( int id, PlayerInventory player, Inventory inventory ) + public ContainerDiskDrive( int id, Inventory player, Container inventory ) { super( ComputerCraftRegistry.ModContainers.DISK_DRIVE, id ); @@ -50,21 +49,21 @@ public class ContainerDiskDrive extends ScreenHandler @Nonnull @Override - public ItemStack transferSlot( @Nonnull PlayerEntity player, int slotIndex ) + public ItemStack quickMoveStack( @Nonnull Player player, int slotIndex ) { Slot slot = slots.get( slotIndex ); - if( slot == null || !slot.hasStack() ) + if( slot == null || !slot.hasItem() ) { return ItemStack.EMPTY; } - ItemStack existing = slot.getStack() + ItemStack existing = slot.getItem() .copy(); ItemStack result = existing.copy(); if( slotIndex == 0 ) { // Insert into player inventory - if( !insertItem( existing, 1, 37, true ) ) + if( !moveItemStackTo( existing, 1, 37, true ) ) { return ItemStack.EMPTY; } @@ -72,7 +71,7 @@ public class ContainerDiskDrive extends ScreenHandler else { // Insert into drive inventory - if( !insertItem( existing, 0, 1, false ) ) + if( !moveItemStackTo( existing, 0, 1, false ) ) { return ItemStack.EMPTY; } @@ -80,11 +79,11 @@ public class ContainerDiskDrive extends ScreenHandler if( existing.isEmpty() ) { - slot.setStack( ItemStack.EMPTY ); + slot.set( ItemStack.EMPTY ); } else { - slot.markDirty(); + slot.setChanged(); } if( existing.getCount() == result.getCount() ) @@ -92,13 +91,13 @@ public class ContainerDiskDrive extends ScreenHandler return ItemStack.EMPTY; } - slot.onTakeItem( player, existing ); + slot.onTake( player, existing ); return result; } @Override - public boolean canUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { - return inventory.canPlayerUse( player ); + return inventory.stillValid( player ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 91ee5bc82..fe074ca4c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -14,10 +14,9 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.util.StringUtil; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.item.ItemStack; import java.util.Optional; /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java index 1e146c3c7..1891bf501 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -6,11 +6,10 @@ package dan200.computercraft.shared.peripheral.diskdrive; -import net.minecraft.util.StringIdentifiable; - import javax.annotation.Nonnull; +import net.minecraft.util.StringRepresentable; -public enum DiskDriveState implements StringIdentifiable +public enum DiskDriveState implements StringRepresentable { EMPTY( "empty" ), FULL( "full" ), INVALID( "invalid" ); @@ -23,7 +22,7 @@ public enum DiskDriveState implements StringIdentifiable @Override @Nonnull - public String asString() + public String getSerializedName() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 957f209b3..529aadab2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -17,38 +17,37 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.util.DefaultInventory; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.RecordUtil; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.ItemEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.sound.SoundEvent; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.Nameable; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +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.chat.TranslatableComponent; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.item.ItemEntity; +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.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import java.util.HashMap; import java.util.Map; import java.util.Set; -public final class TileDiskDrive extends TileGeneric implements DefaultInventory, IPeripheralTile, Nameable, NamedScreenHandlerFactory +public final class TileDiskDrive extends TileGeneric implements DefaultInventory, IPeripheralTile, Nameable, MenuProvider { private static final String NBT_NAME = "CustomName"; private static final String NBT_ITEM = "Item"; private final Map computers = new HashMap<>(); - Text customName; + Component customName; @Nonnull private ItemStack diskStack = ItemStack.EMPTY; private IMount diskMount = null; @@ -74,81 +73,81 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - if( player.isInSneakingPose() ) + if( player.isCrouching() ) { // Try to put a disk into the drive - ItemStack disk = player.getStackInHand( hand ); + ItemStack disk = player.getItemInHand( hand ); if( disk.isEmpty() ) { - return ActionResult.PASS; + return InteractionResult.PASS; } - if( !getWorld().isClient && getStack( 0 ).isEmpty() && MediaProviders.get( disk ) != null ) + if( !getLevel().isClientSide && getItem( 0 ).isEmpty() && MediaProviders.get( disk ) != null ) { setDiskStack( disk ); - player.setStackInHand( hand, ItemStack.EMPTY ); + player.setItemInHand( hand, ItemStack.EMPTY ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } else { // Open the GUI - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - player.openHandledScreen( this ); + player.openMenu( this ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } } public Direction getDirection() { - return getCachedState().get( BlockDiskDrive.FACING ); + return getBlockState().getValue( BlockDiskDrive.FACING ); } @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); - customName = nbt.contains( NBT_NAME ) ? Text.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + super.load( nbt ); + customName = nbt.contains( NBT_NAME ) ? Component.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; if( nbt.contains( NBT_ITEM ) ) { - NbtCompound item = nbt.getCompound( NBT_ITEM ); - diskStack = ItemStack.fromNbt( item ); + CompoundTag item = nbt.getCompound( NBT_ITEM ); + diskStack = ItemStack.of( item ); diskMount = null; } } @Nonnull @Override - public NbtCompound writeNbt( @Nonnull NbtCompound nbt ) + public CompoundTag save( @Nonnull CompoundTag nbt ) { if( customName != null ) { - nbt.putString( NBT_NAME, Text.Serializer.toJson( customName ) ); + nbt.putString( NBT_NAME, Component.Serializer.toJson( customName ) ); } if( !diskStack.isEmpty() ) { - NbtCompound item = new NbtCompound(); - diskStack.writeNbt( item ); + CompoundTag item = new CompoundTag(); + diskStack.save( item ); nbt.put( NBT_ITEM, item ); } - return super.writeNbt( nbt ); + return super.save( nbt ); } @Override - public void markDirty() + public void setChanged() { - if( !world.isClient ) + if( !level.isClientSide ) { updateBlockState(); } - super.markDirty(); + super.setChanged(); } - public static void tick( World world, BlockPos pos, BlockState state, TileDiskDrive tileDiskDrive ) + public static void tick( Level world, BlockPos pos, BlockState state, TileDiskDrive tileDiskDrive ) { // Ejection if( tileDiskDrive.ejectQueued ) @@ -160,7 +159,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory // Music synchronized( tileDiskDrive ) { - if( !world.isClient && tileDiskDrive.recordPlaying != tileDiskDrive.recordQueued || tileDiskDrive.restartRecord ) + if( !world.isClientSide && tileDiskDrive.recordPlaying != tileDiskDrive.recordQueued || tileDiskDrive.restartRecord ) { tileDiskDrive.restartRecord = false; if( tileDiskDrive.recordQueued ) @@ -189,7 +188,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory // IInventory implementation @Override - public int size() + public int getContainerSize() { return 1; } @@ -202,14 +201,14 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public ItemStack getStack( int slot ) + public ItemStack getItem( int slot ) { return diskStack; } @Nonnull @Override - public ItemStack removeStack( int slot, int count ) + public ItemStack removeItem( int slot, int count ) { if( diskStack.isEmpty() ) { @@ -219,18 +218,18 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory if( diskStack.getCount() <= count ) { ItemStack disk = diskStack; - setStack( slot, ItemStack.EMPTY ); + setItem( slot, ItemStack.EMPTY ); return disk; } ItemStack part = diskStack.split( count ); - setStack( slot, diskStack.isEmpty() ? ItemStack.EMPTY : diskStack ); + setItem( slot, diskStack.isEmpty() ? ItemStack.EMPTY : diskStack ); return part; } @Nonnull @Override - public ItemStack removeStack( int slot ) + public ItemStack removeItemNoUpdate( int slot ) { ItemStack result = diskStack; diskStack = ItemStack.EMPTY; @@ -240,13 +239,13 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public void setStack( int slot, @Nonnull ItemStack stack ) + public void setItem( int slot, @Nonnull ItemStack stack ) { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { diskStack = stack; diskMount = null; - markDirty(); + setChanged(); return; } @@ -280,7 +279,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory // Swap disk over diskStack = stack; diskMount = null; - markDirty(); + setChanged(); // Mount new disk if( !diskStack.isEmpty() ) @@ -295,15 +294,15 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public boolean canPlayerUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { return isUsable( player, false ); } @Override - public void clear() + public void clearContent() { - setStack( 0, ItemStack.EMPTY ); + setItem( 0, ItemStack.EMPTY ); } @Nonnull @@ -341,7 +340,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { if( diskMount == null ) { - diskMount = contents.createDataMount( diskStack, getWorld() ); + diskMount = contents.createDataMount( diskStack, getLevel() ); } if( diskMount != null ) { @@ -383,12 +382,12 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull ItemStack getDiskStack() { - return getStack( 0 ); + return getItem( 0 ); } void setDiskStack( @Nonnull ItemStack stack ) { - setStack( 0, stack ); + setItem( 0, stack ); } void unmount( IComputerAccess computer ) @@ -449,7 +448,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private void updateBlockState() { - if( removed ) + if( remove ) { return; } @@ -467,18 +466,18 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private void updateBlockState( DiskDriveState state ) { - BlockState blockState = getCachedState(); - if( blockState.get( BlockDiskDrive.STATE ) == state ) + BlockState blockState = getBlockState(); + if( blockState.getValue( BlockDiskDrive.STATE ) == state ) { return; } - getWorld().setBlockState( getPos(), blockState.with( BlockDiskDrive.STATE, state ) ); + getLevel().setBlockAndUpdate( getBlockPos(), blockState.setValue( BlockDiskDrive.STATE, state ) ); } private synchronized void ejectContents( boolean destroyed ) { - if( this.world.isClient || diskStack.isEmpty() ) + if( this.level.isClientSide || diskStack.isEmpty() ) { return; } @@ -493,21 +492,21 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory if( !destroyed ) { Direction dir = getDirection(); - xOff = dir.getOffsetX(); - zOff = dir.getOffsetZ(); + xOff = dir.getStepX(); + zOff = dir.getStepZ(); } - BlockPos pos = getPos(); + BlockPos pos = getBlockPos(); double x = pos.getX() + 0.5 + xOff * 0.5; double y = pos.getY() + 0.75; double z = pos.getZ() + 0.5 + zOff * 0.5; - ItemEntity entityitem = new ItemEntity( getWorld(), x, y, z, disks ); - entityitem.setVelocity( xOff * 0.15, 0, zOff * 0.15 ); + ItemEntity entityitem = new ItemEntity( getLevel(), x, y, z, disks ); + entityitem.setDeltaMovement( xOff * 0.15, 0, zOff * 0.15 ); - getWorld().spawnEntity( entityitem ); + getLevel().addFreshEntity( entityitem ); if( !destroyed ) { - getWorld().syncGlobalEvent( 1000, getPos(), 0 ); + getLevel().globalLevelEvent( 1000, getBlockPos(), 0 ); } } @@ -517,11 +516,11 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory SoundEvent record = contents != null ? contents.getAudio( diskStack ) : null; if( record != null ) { - RecordUtil.playRecord( record, contents.getAudioTitle( diskStack ), getWorld(), getPos() ); + RecordUtil.playRecord( record, contents.getAudioTitle( diskStack ), getLevel(), getBlockPos() ); } else { - RecordUtil.playRecord( null, null, getWorld(), getPos() ); + RecordUtil.playRecord( null, null, getLevel(), getBlockPos() ); } } @@ -529,15 +528,15 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private void stopRecord() { - RecordUtil.playRecord( null, null, getWorld(), getPos() ); + RecordUtil.playRecord( null, null, getLevel(), getBlockPos() ); } @Nonnull @Override - public Text getName() + public Component getName() { - return customName != null ? customName : new TranslatableText( getCachedState().getBlock() - .getTranslationKey() ); + return customName != null ? customName : new TranslatableComponent( getBlockState().getBlock() + .getDescriptionId() ); } @Override @@ -548,21 +547,21 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public Text getDisplayName() + public Component getDisplayName() { return Nameable.super.getDisplayName(); } @Nullable @Override - public Text getCustomName() + public Component getCustomName() { return customName; } @Nonnull @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player ) { return new ContainerDiskDrive( id, inventory, this ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java index c4c59ee4a..48bcf77c5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -12,12 +12,11 @@ import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import java.util.List; class GenericPeripheral implements IDynamicPeripheral @@ -28,7 +27,7 @@ class GenericPeripheral implements IDynamicPeripheral GenericPeripheral( BlockEntity tile, List methods ) { - Identifier type = BlockEntityType.getId( tile.getType() ); + ResourceLocation type = BlockEntityType.getKey( tile.getType() ); this.tile = tile; this.type = type == null ? "unknown" : type.toString(); this.methods = methods; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index d4b3e0b16..a6dfbe1a2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -8,20 +8,19 @@ package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.asm.NamedMethod; import dan200.computercraft.core.asm.PeripheralMethod; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.ArrayList; import java.util.List; public class GenericPeripheralProvider { @Nullable - public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + public static IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) { BlockEntity tile = world.getBlockEntity( pos ); if( tile == null ) return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index 4b9a9e0ed..ad965520c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -6,10 +6,9 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.common.collect.ImmutableMap; -import net.minecraft.block.BlockState; -import net.minecraft.state.property.Property; - import javax.annotation.Nonnull; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import java.util.HashMap; import java.util.Map; @@ -21,7 +20,7 @@ public class BlockData data.put( "name", DataHelpers.getId( state.getBlock() ) ); Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, ? extends Comparable> entry : state.getEntries().entrySet() ) + for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) { Property property = entry.getKey(); stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); @@ -35,6 +34,6 @@ public class BlockData private static Object getPropertyValue( Property property, Comparable value ) { if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value; - return property.name( value ); + return property.getName( value ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java index 210aa5b5a..fd771675b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -5,14 +5,13 @@ */ package dan200.computercraft.shared.peripheral.generic.data; -import net.minecraft.block.Block; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.item.Item; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.block.Block; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -23,31 +22,31 @@ public final class DataHelpers { } @Nonnull - public static Map getTags( @Nonnull Collection tags ) + public static Map getTags( @Nonnull Collection tags ) { Map result = new HashMap<>( tags.size() ); - for( Identifier location : tags ) result.put( location.toString(), true ); + for( ResourceLocation location : tags ) result.put( location.toString(), true ); return result; } @Nullable public static String getId( @Nonnull Block block ) { - Identifier id = Registry.BLOCK.getId( block ); + ResourceLocation id = Registry.BLOCK.getKey( block ); return id == null ? null : id.toString(); } @Nullable public static String getId( @Nonnull Item item ) { - Identifier id = Registry.ITEM.getId( item ); + ResourceLocation id = Registry.ITEM.getKey( item ); return id == null ? null : id.toString(); } @Nullable public static String getId( @Nonnull Enchantment enchantment ) { - Identifier id = Registry.ENCHANTMENT.getId( enchantment ); + ResourceLocation id = Registry.ENCHANTMENT.getKey( enchantment ); return id == null ? null : id.toString(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index a5781483a..61cb8e68a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,21 +7,20 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.item.EnchantedBookItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtElement; -import net.minecraft.tag.ServerTagManagerHolder; -import net.minecraft.tag.TagGroup; -import net.minecraft.text.Text; -import net.minecraft.util.registry.Registry; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.tags.SerializationTags; +import net.minecraft.tags.TagCollection; +import net.minecraft.world.item.EnchantedBookItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import java.util.*; import java.util.stream.Collectors; @@ -43,7 +42,7 @@ public class ItemData public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) { fillBasicSafe( data, stack ); - String hash = NBTUtil.getNBTHash( stack.getNbt() ); + String hash = NBTUtil.getNBTHash( stack.getTag() ); if( hash != null ) data.put( "nbt", hash ); return data; @@ -56,39 +55,39 @@ public class ItemData fillBasic( data, stack ); - data.put( "displayName", stack.getName().getString() ); - data.put( "maxCount", stack.getMaxCount() ); + data.put( "displayName", stack.getHoverName().getString() ); + data.put( "maxCount", stack.getMaxStackSize() ); - if( stack.isDamageable() ) + if( stack.isDamageableItem() ) { - data.put( "damage", stack.getDamage() ); + data.put( "damage", stack.getDamageValue() ); data.put( "maxDamage", stack.getMaxDamage() ); } if( stack.isDamaged() ) { - data.put( "durability", (double) stack.getDamage() / stack.getMaxDamage() ); + data.put( "durability", (double) stack.getDamageValue() / stack.getMaxDamage() ); } // requireNonNull is safe because we got the Identifiers out of the TagGroup to start with. Would be nicer // to stream the tags directly but TagGroup isn't a collection :( - TagGroup itemTags = ServerTagManagerHolder.getTagManager().getOrCreateTagGroup( Registry.ITEM_KEY ); - data.put( "tags", DataHelpers.getTags( itemTags.getTagIds().stream() + TagCollection itemTags = SerializationTags.getInstance().getOrEmpty( Registry.ITEM_REGISTRY ); + data.put( "tags", DataHelpers.getTags( itemTags.getAvailableTags().stream() .filter( id -> Objects.requireNonNull( itemTags.getTag( id ) ).contains( stack.getItem() ) ) .collect( Collectors.toList() ) ) ); // chaos x2 - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); if( tag != null && tag.contains( "display", NBTUtil.TAG_COMPOUND ) ) { - NbtCompound displayTag = tag.getCompound( "display" ); + CompoundTag displayTag = tag.getCompound( "display" ); if( displayTag.contains( "Lore", NBTUtil.TAG_LIST ) ) { - NbtList loreTag = displayTag.getList( "Lore", NBTUtil.TAG_STRING ); + ListTag loreTag = displayTag.getList( "Lore", NBTUtil.TAG_STRING ); data.put( "lore", loreTag.stream() .map( ItemData::parseTextComponent ) .filter( Objects::nonNull ) - .map( Text::getString ) + .map( Component::getString ) .collect( Collectors.toList() ) ); } } @@ -113,11 +112,11 @@ public class ItemData @Nullable - private static Text parseTextComponent( @Nonnull NbtElement x ) + private static Component parseTextComponent( @Nonnull Tag x ) { try { - return Text.Serializer.fromJson( x.toString() ); + return Component.Serializer.fromJson( x.toString() ); } catch( JsonParseException e ) { @@ -139,17 +138,17 @@ public class ItemData if( stack.getItem() instanceof EnchantedBookItem && (hideFlags & 32) == 0 ) { - addEnchantments( EnchantedBookItem.getEnchantmentNbt( stack ), enchants ); + addEnchantments( EnchantedBookItem.getEnchantments( stack ), enchants ); } - if( stack.hasEnchantments() && (hideFlags & 1) == 0 ) + if( stack.isEnchanted() && (hideFlags & 1) == 0 ) { /* * Mimic the EnchantmentHelper.getEnchantments(ItemStack stack) behavior without special case for Enchanted book. * I'll do that to have the same data than ones displayed in tooltip. * @see EnchantmentHelper.getEnchantments(ItemStack stack) */ - addEnchantments( stack.getEnchantments(), enchants ); + addEnchantments( stack.getEnchantmentTags(), enchants ); } return enchants; @@ -162,21 +161,21 @@ public class ItemData * @param enchants The enchantment map to add it to. * @see EnchantmentHelper */ - private static void addEnchantments( @Nonnull NbtList rawEnchants, @Nonnull ArrayList> enchants ) + private static void addEnchantments( @Nonnull ListTag rawEnchants, @Nonnull ArrayList> enchants ) { if( rawEnchants.isEmpty() ) return; enchants.ensureCapacity( enchants.size() + rawEnchants.size() ); - for( Map.Entry entry : EnchantmentHelper.fromNbt( rawEnchants ).entrySet() ) + for( Map.Entry entry : EnchantmentHelper.deserializeEnchantments( rawEnchants ).entrySet() ) { Enchantment enchantment = entry.getKey(); Integer level = entry.getValue(); HashMap enchant = new HashMap<>( 3 ); enchant.put( "name", DataHelpers.getId( enchantment ) ); enchant.put( "level", level ); - enchant.put( "displayName", enchantment.getName( level ).getString() ); + enchant.put( "displayName", enchantment.getFullname( level ).getString() ); enchants.add( enchant ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 4b5d76be1..30e1ef920 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -14,14 +14,13 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.Nameable; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; +import net.minecraft.world.Nameable; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -37,9 +36,9 @@ public class InventoryMethods implements GenericSource { @Nonnull @Override - public Identifier id() + public ResourceLocation id() { - return new Identifier( ComputerCraft.MOD_ID, "inventory" ); + return new ResourceLocation( ComputerCraft.MOD_ID, "inventory" ); } /** @@ -49,7 +48,7 @@ public class InventoryMethods implements GenericSource * @return The number of slots in this inventory. */ @LuaFunction( mainThread = true ) - public static int size( Inventory inventory ) + public static int size( Container inventory ) { return extractHandler( inventory ).size(); } @@ -61,12 +60,12 @@ public class InventoryMethods implements GenericSource * @return The name of this inventory, or {@code nil} if not present. */ @LuaFunction( mainThread = true ) - public static String name( Inventory inventory ) + public static String name( Container inventory ) { if( inventory instanceof Nameable ) { Nameable i = (Nameable) inventory; - return i.hasCustomName() ? i.getName().asString() : null; + return i.hasCustomName() ? i.getName().getContents() : null; } return null; } @@ -95,7 +94,7 @@ public class InventoryMethods implements GenericSource * } */ @LuaFunction( mainThread = true ) - public static Map> list( Inventory inventory ) + public static Map> list( Container inventory ) { ItemStorage itemStorage = extractHandler( inventory ); @@ -142,7 +141,7 @@ public class InventoryMethods implements GenericSource */ @Nullable @LuaFunction( mainThread = true ) - public static Map getItemDetail( Inventory inventory, int slot ) throws LuaException + public static Map getItemDetail( Container inventory, int slot ) throws LuaException { ItemStorage itemStorage = extractHandler( inventory ); @@ -173,10 +172,10 @@ public class InventoryMethods implements GenericSource * } */ @LuaFunction( mainThread = true ) - public static int getItemLimit( Inventory inventory, int slot ) throws LuaException + public static int getItemLimit( Container inventory, int slot ) throws LuaException { - assertBetween( slot, 1, inventory.size(), "Slot out of range (%s)" ); - return inventory.getMaxCountPerStack(); + assertBetween( slot, 1, inventory.getContainerSize(), "Slot out of range (%s)" ); + return inventory.getMaxStackSize(); } /** @@ -206,7 +205,7 @@ public class InventoryMethods implements GenericSource */ @LuaFunction( mainThread = true ) public static int pushItems( - Inventory from, IComputerAccess computer, + Container from, IComputerAccess computer, String toName, int fromSlot, Optional limit, Optional toSlot ) throws LuaException { @@ -255,7 +254,7 @@ public class InventoryMethods implements GenericSource */ @LuaFunction( mainThread = true ) public static int pullItems( - Inventory to, IComputerAccess computer, + Container to, IComputerAccess computer, String fromName, int fromSlot, Optional limit, Optional toSlot ) throws LuaException { @@ -284,15 +283,15 @@ public class InventoryMethods implements GenericSource { if( object instanceof BlockEntity ) { - Inventory inventory = InventoryUtil.getInventory( (BlockEntity) object ); + Container inventory = InventoryUtil.getInventory( (BlockEntity) object ); if( inventory != null ) { return ItemStorage.wrap( inventory ); } } - else if ( object instanceof Inventory ) + else if ( object instanceof Container ) { - return ItemStorage.wrap( (Inventory) object ); + return ItemStorage.wrap( (Container) object ); } return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 27e02f18f..3367fe068 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -14,10 +14,9 @@ import dan200.computercraft.api.network.IPacketSender; import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import java.util.HashSet; import java.util.Set; @@ -217,8 +216,8 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa parseChannel( channel ); parseChannel( replyChannel ); - World world = getWorld(); - Vec3d position = getPosition(); + Level world = getWorld(); + Vec3 position = getPosition(); IPacketNetwork network = this.network; if( world == null || position == null || network == null ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java index 1cf37fe63..ffec375cd 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -6,26 +6,25 @@ package dan200.computercraft.shared.peripheral.modem; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; - import javax.annotation.Nonnull; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; public final class ModemShapes { private static final VoxelShape[] BOXES = new VoxelShape[] { - VoxelShapes.cuboid( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), + Shapes.box( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), // Down - VoxelShapes.cuboid( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), + Shapes.box( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), // Up - VoxelShapes.cuboid( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), + Shapes.box( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), // North - VoxelShapes.cuboid( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), + Shapes.box( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), // South - VoxelShapes.cuboid( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), + Shapes.box( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), // West - VoxelShapes.cuboid( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), + Shapes.box( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), // East }; @@ -33,6 +32,6 @@ public final class ModemShapes public static VoxelShape getBounds( Direction facing ) { int direction = facing.ordinal(); - return direction < BOXES.length ? BOXES[direction] : VoxelShapes.fullCube(); + return direction < BOXES.length ? BOXES[direction] : Shapes.block(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 7b90d4ffd..8c78bc226 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -12,43 +12,47 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.util.WorldUtil; import net.fabricmc.fabric.api.block.BlockPickInteractionAware; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ShapeContext; -import net.minecraft.block.Waterloggable; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.FluidState; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.BooleanProperty; -import net.minecraft.state.property.EnumProperty; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.world.*; - +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +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.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.EnumMap; import static dan200.computercraft.shared.util.WaterloggableHelpers.*; -public class BlockCable extends BlockGeneric implements Waterloggable, BlockPickInteractionAware +public class BlockCable extends BlockGeneric implements SimpleWaterloggedBlock, BlockPickInteractionAware { - public static final EnumProperty MODEM = EnumProperty.of( "modem", CableModemVariant.class ); - public static final BooleanProperty CABLE = BooleanProperty.of( "cable" ); + public static final EnumProperty MODEM = EnumProperty.create( "modem", CableModemVariant.class ); + public static final BooleanProperty CABLE = BooleanProperty.create( "cable" ); - private static final BooleanProperty NORTH = BooleanProperty.of( "north" ); - private static final BooleanProperty SOUTH = BooleanProperty.of( "south" ); - private static final BooleanProperty EAST = BooleanProperty.of( "east" ); - private static final BooleanProperty WEST = BooleanProperty.of( "west" ); - private static final BooleanProperty UP = BooleanProperty.of( "up" ); - private static final BooleanProperty DOWN = BooleanProperty.of( "down" ); + private static final BooleanProperty NORTH = BooleanProperty.create( "north" ); + private static final BooleanProperty SOUTH = BooleanProperty.create( "south" ); + private static final BooleanProperty EAST = BooleanProperty.create( "east" ); + private static final BooleanProperty WEST = BooleanProperty.create( "west" ); + private static final BooleanProperty UP = BooleanProperty.create( "up" ); + private static final BooleanProperty DOWN = BooleanProperty.create( "down" ); static final EnumMap CONNECTIONS = new EnumMap<>( new ImmutableMap.Builder().put( Direction.DOWN, DOWN ) @@ -64,56 +68,56 @@ public class BlockCable extends BlockGeneric implements Waterloggable, BlockPick EAST ) .build() ); - public BlockCable( Settings settings ) + public BlockCable( Properties settings ) { super( settings, ComputerCraftRegistry.ModTiles.CABLE ); - setDefaultState( getStateManager().getDefaultState() - .with( MODEM, CableModemVariant.None ) - .with( CABLE, false ) - .with( NORTH, false ) - .with( SOUTH, false ) - .with( EAST, false ) - .with( WEST, false ) - .with( UP, false ) - .with( DOWN, false ) - .with( WATERLOGGED, false ) ); + registerDefaultState( getStateDefinition().any() + .setValue( MODEM, CableModemVariant.None ) + .setValue( CABLE, false ) + .setValue( NORTH, false ) + .setValue( SOUTH, false ) + .setValue( EAST, false ) + .setValue( WEST, false ) + .setValue( UP, false ) + .setValue( DOWN, false ) + .setValue( WATERLOGGED, false ) ); } public static boolean canConnectIn( BlockState state, Direction direction ) { - return state.get( BlockCable.CABLE ) && state.get( BlockCable.MODEM ) + return state.getValue( BlockCable.CABLE ) && state.getValue( BlockCable.MODEM ) .getFacing() != direction; } @Nonnull @Override @Deprecated - public BlockState getStateForNeighborUpdate( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull WorldAccess world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); // Should never happen, but handle the case where we've no modem or cable. - if( !state.get( CABLE ) && state.get( MODEM ) == CableModemVariant.None ) + if( !state.getValue( CABLE ) && state.getValue( MODEM ) == CableModemVariant.None ) { - return getFluidState( state ).getBlockState(); + return getFluidState( state ).createLegacyBlock(); } - return state.with( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) ); + return state.setValue( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) ); } - public static boolean doesConnectVisually( BlockState state, BlockView world, BlockPos pos, Direction direction ) + public static boolean doesConnectVisually( BlockState state, BlockGetter world, BlockPos pos, Direction direction ) { - if( !state.get( CABLE ) ) + if( !state.getValue( CABLE ) ) { return false; } - if( state.get( MODEM ) + if( state.getValue( MODEM ) .getFacing() == direction ) { return true; } - return ComputerCraftAPI.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ) != null; + return ComputerCraftAPI.getWiredElementAt( world, pos.relative( direction ), direction.getOpposite() ) != null; } @Nonnull @@ -124,41 +128,41 @@ public class BlockCable extends BlockGeneric implements Waterloggable, BlockPick return getWaterloggedFluidState( state ); } - public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, FluidState fluid ) + public boolean removedByPlayer( BlockState state, Level world, BlockPos pos, Player player, boolean willHarvest, FluidState fluid ) { - if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null ) + if( state.getValue( CABLE ) && state.getValue( MODEM ).getFacing() != null ) { - BlockHitResult hit = world.raycast( new RaycastContext( + BlockHitResult hit = world.clip( new ClipContext( WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ), - RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, player + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player ) ); if( hit.getType() == HitResult.Type.BLOCK ) { BlockEntity tile = world.getBlockEntity( pos ); - if( tile instanceof TileCable cable && tile.hasWorld() ) + if( tile instanceof TileCable cable && tile.hasLevel() ) { ItemStack item; BlockState newState; - if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) + if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) { - newState = state.with( MODEM, CableModemVariant.None ); + newState = state.setValue( MODEM, CableModemVariant.None ); item = new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ); } else { - newState = state.with( CABLE, false ); + newState = state.setValue( CABLE, false ); item = new ItemStack( ComputerCraftRegistry.ModItems.CABLE ); } - world.setBlockState( pos, correctConnections( world, pos, newState ), 3 ); + world.setBlock( pos, correctConnections( world, pos, newState ), 3 ); cable.modemChanged(); cable.connectionsChanged(); - if( !world.isClient && !player.getAbilities().creativeMode ) + if( !world.isClientSide && !player.getAbilities().instabuild ) { - Block.dropStack( world, pos, item ); + Block.popResource( world, pos, item ); } return false; @@ -170,66 +174,66 @@ public class BlockCable extends BlockGeneric implements Waterloggable, BlockPick } @Override - public ItemStack getPickedStack( BlockState state, BlockView world, BlockPos pos, @Nullable PlayerEntity player, HitResult hit ) + public ItemStack getPickedStack( BlockState state, BlockGetter world, BlockPos pos, @Nullable Player player, HitResult hit ) { - Direction modem = state.get( MODEM ).getFacing(); - boolean cable = state.get( CABLE ); + Direction modem = state.getValue( MODEM ).getFacing(); + boolean cable = state.getValue( CABLE ); // If we've only got one, just use that. if( !cable ) return new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ); if( modem == null ) return new ItemStack( ComputerCraftRegistry.ModItems.CABLE ); // We've a modem and cable, so try to work out which one we're interacting with - return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getPos().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ) : new ItemStack( ComputerCraftRegistry.ModItems.CABLE ); } @Override @Deprecated - public boolean canPlaceAt( BlockState state, @Nonnull WorldView world, @Nonnull BlockPos pos ) + public boolean canSurvive( BlockState state, @Nonnull LevelReader world, @Nonnull BlockPos pos ) { - Direction facing = state.get( MODEM ) + Direction facing = state.getValue( MODEM ) .getFacing(); if( facing == null ) { return true; } - return sideCoversSmallSquare( world, pos.offset( facing ), facing.getOpposite() ); + return canSupportCenter( world, pos.relative( facing ), facing.getOpposite() ); } @Nonnull @Override @Deprecated - public VoxelShape getOutlineShape( @Nonnull BlockState state, @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull ShapeContext context ) + public VoxelShape getShape( @Nonnull BlockState state, @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull CollisionContext context ) { return CableShapes.getShape( state ); } @Nullable @Override - public BlockState getPlacementState( @Nonnull ItemPlacementContext context ) + public BlockState getStateForPlacement( @Nonnull BlockPlaceContext context ) { - BlockState state = getDefaultState().with( WATERLOGGED, getWaterloggedStateForPlacement( context ) ); + BlockState state = defaultBlockState().setValue( WATERLOGGED, getWaterloggedStateForPlacement( context ) ); - if( context.getStack() + if( context.getItemInHand() .getItem() instanceof ItemBlockCable.Cable ) { - World world = context.getWorld(); - BlockPos pos = context.getBlockPos(); - return correctConnections( world, pos, state.with( CABLE, true ) ); + Level world = context.getLevel(); + BlockPos pos = context.getClickedPos(); + return correctConnections( world, pos, state.setValue( CABLE, true ) ); } else { - return state.with( MODEM, - CableModemVariant.from( context.getSide() + return state.setValue( MODEM, + CableModemVariant.from( context.getClickedFace() .getOpposite() ) ); } } @Override - public void onPlaced( World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) + public void setPlacedBy( Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) { BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileCable cable ) @@ -240,40 +244,40 @@ public class BlockCable extends BlockGeneric implements Waterloggable, BlockPick } } - super.onPlaced( world, pos, state, placer, stack ); + super.setPlacedBy( world, pos, state, placer, stack ); } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( MODEM, CABLE, NORTH, SOUTH, EAST, WEST, UP, DOWN, WATERLOGGED ); } - public static BlockState correctConnections( World world, BlockPos pos, BlockState state ) + public static BlockState correctConnections( Level world, BlockPos pos, BlockState state ) { - if( state.get( CABLE ) ) + if( state.getValue( CABLE ) ) { - return state.with( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) ) - .with( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) ) - .with( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) ) - .with( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) ) - .with( UP, doesConnectVisually( state, world, pos, Direction.UP ) ) - .with( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) ); + return state.setValue( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) ) + .setValue( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) ) + .setValue( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) ) + .setValue( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) ) + .setValue( UP, doesConnectVisually( state, world, pos, Direction.UP ) ) + .setValue( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) ); } else { - return state.with( NORTH, false ) - .with( SOUTH, false ) - .with( EAST, false ) - .with( WEST, false ) - .with( UP, false ) - .with( DOWN, false ); + return state.setValue( NORTH, false ) + .setValue( SOUTH, false ) + .setValue( EAST, false ) + .setValue( WEST, false ) + .setValue( UP, false ) + .setValue( DOWN, false ); } } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileCable( ComputerCraftRegistry.ModTiles.CABLE, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index a14875443..4b9d98423 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -8,38 +8,37 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.BooleanProperty; -import net.minecraft.util.math.BlockPos; - import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BooleanProperty; public class BlockWiredModemFull extends BlockGeneric { - public static final BooleanProperty MODEM_ON = BooleanProperty.of( "modem" ); - public static final BooleanProperty PERIPHERAL_ON = BooleanProperty.of( "peripheral" ); + public static final BooleanProperty MODEM_ON = BooleanProperty.create( "modem" ); + public static final BooleanProperty PERIPHERAL_ON = BooleanProperty.create( "peripheral" ); - public BlockWiredModemFull( Settings settings, BlockEntityType type ) + public BlockWiredModemFull( Properties settings, BlockEntityType type ) { super( settings, type ); - setDefaultState( getStateManager().getDefaultState() - .with( MODEM_ON, false ) - .with( PERIPHERAL_ON, false ) ); + registerDefaultState( getStateDefinition().any() + .setValue( MODEM_ON, false ) + .setValue( PERIPHERAL_ON, false ) ); } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( MODEM_ON, PERIPHERAL_ON ); } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileWiredModemFull( ComputerCraftRegistry.ModTiles.WIRED_MODEM_FULL, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index a45f27db7..be6b6e1f3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -6,13 +6,12 @@ package dan200.computercraft.shared.peripheral.modem.wired; -import net.minecraft.util.StringIdentifiable; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.Direction; +import net.minecraft.util.StringRepresentable; -public enum CableModemVariant implements StringIdentifiable +public enum CableModemVariant implements StringRepresentable { None( "none", null ), DownOff( "down_off", Direction.DOWN ), @@ -54,19 +53,19 @@ public enum CableModemVariant implements StringIdentifiable @Nonnull public static CableModemVariant from( Direction facing ) { - return facing == null ? None : VALUES[1 + facing.getId()]; + return facing == null ? None : VALUES[1 + facing.get3DDataValue()]; } @Nonnull public static CableModemVariant from( Direction facing, boolean modem, boolean peripheral ) { int state = (modem ? 2 : 0) + (peripheral ? 1 : 0); - return facing == null ? None : VALUES[1 + 6 * state + facing.getId()]; + return facing == null ? None : VALUES[1 + 6 * state + facing.get3DDataValue()]; } @Nonnull @Override - public String asString() + public String getSerializedName() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java index 12bd696cb..dbb270816 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -9,12 +9,11 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; import dan200.computercraft.shared.peripheral.modem.ModemShapes; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; - import java.util.EnumMap; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; @@ -23,10 +22,10 @@ public final class CableShapes private static final double MIN = 0.375; private static final double MAX = 1 - MIN; - private static final VoxelShape SHAPE_CABLE_CORE = VoxelShapes.cuboid( MIN, MIN, MIN, MAX, MAX, MAX ); + private static final VoxelShape SHAPE_CABLE_CORE = Shapes.box( MIN, MIN, MIN, MAX, MAX, MAX ); private static final EnumMap SHAPE_CABLE_ARM = new EnumMap<>( new ImmutableMap.Builder().put( Direction.DOWN, - VoxelShapes.cuboid( + Shapes.box( MIN, 0, MIN, @@ -34,7 +33,7 @@ public final class CableShapes MIN, MAX ) ) .put( Direction.UP, - VoxelShapes.cuboid( + Shapes.box( MIN, MAX, MIN, @@ -42,7 +41,7 @@ public final class CableShapes 1, MAX ) ) .put( Direction.NORTH, - VoxelShapes.cuboid( + Shapes.box( MIN, MIN, 0, @@ -50,7 +49,7 @@ public final class CableShapes MAX, MIN ) ) .put( Direction.SOUTH, - VoxelShapes.cuboid( + Shapes.box( MIN, MIN, MAX, @@ -58,7 +57,7 @@ public final class CableShapes MAX, 1 ) ) .put( Direction.WEST, - VoxelShapes.cuboid( + Shapes.box( 0, MIN, MIN, @@ -66,7 +65,7 @@ public final class CableShapes MAX, MAX ) ) .put( Direction.EAST, - VoxelShapes.cuboid( + Shapes.box( MAX, MIN, MIN, @@ -84,9 +83,9 @@ public final class CableShapes public static VoxelShape getCableShape( BlockState state ) { - if( !state.get( CABLE ) ) + if( !state.getValue( CABLE ) ) { - return VoxelShapes.empty(); + return Shapes.empty(); } return getCableShape( getCableIndex( state ) ); } @@ -104,7 +103,7 @@ public final class CableShapes { if( (index & (1 << facing.ordinal())) != 0 ) { - shape = VoxelShapes.union( shape, SHAPE_CABLE_ARM.get( facing ) ); + shape = Shapes.or( shape, SHAPE_CABLE_ARM.get( facing ) ); } } @@ -116,7 +115,7 @@ public final class CableShapes int index = 0; for( Direction facing : DirectionUtil.FACINGS ) { - if( state.get( CONNECTIONS.get( facing ) ) ) + if( state.getValue( CONNECTIONS.get( facing ) ) ) { index |= 1 << facing.ordinal(); } @@ -127,9 +126,9 @@ public final class CableShapes public static VoxelShape getShape( BlockState state ) { - Direction facing = state.get( MODEM ) + Direction facing = state.getValue( MODEM ) .getFacing(); - if( !state.get( CABLE ) ) + if( !state.getValue( CABLE ) ) { return getModemShape( state ); } @@ -146,15 +145,15 @@ public final class CableShapes shape = getCableShape( cableIndex ); if( facing != null ) { - shape = VoxelShapes.union( shape, ModemShapes.getBounds( facing ) ); + shape = Shapes.or( shape, ModemShapes.getBounds( facing ) ); } return SHAPES[index] = shape; } public static VoxelShape getModemShape( BlockState state ) { - Direction facing = state.get( MODEM ) + Direction facing = state.getValue( MODEM ) .getFacing(); - return facing == null ? VoxelShapes.empty() : ModemShapes.getBounds( facing ); + return facing == null ? Shapes.empty() : ModemShapes.getBounds( facing ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index eb86b95f5..ec5e4872c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -7,24 +7,23 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.ComputerCraftRegistry; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.sound.BlockSoundGroup; -import net.minecraft.sound.SoundCategory; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Util; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.core.Registry; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; @@ -32,28 +31,28 @@ public abstract class ItemBlockCable extends BlockItem { private String translationKey; - public ItemBlockCable( BlockCable block, Settings settings ) + public ItemBlockCable( BlockCable block, Properties settings ) { super( block, settings ); } - boolean placeAtCorrected( World world, BlockPos pos, BlockState state ) + boolean placeAtCorrected( Level world, BlockPos pos, BlockState state ) { return placeAt( world, pos, correctConnections( world, pos, state ), null ); } - boolean placeAt( World world, BlockPos pos, BlockState state, PlayerEntity player ) + boolean placeAt( Level world, BlockPos pos, BlockState state, Player player ) { // TODO: Check entity collision. - if( !state.canPlaceAt( world, pos ) ) + if( !state.canSurvive( world, pos ) ) { return false; } - world.setBlockState( pos, state, 3 ); - BlockSoundGroup soundType = state.getBlock() - .getSoundGroup( state ); - world.playSound( null, pos, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); + world.setBlock( pos, state, 3 ); + SoundType soundType = state.getBlock() + .getSoundType( state ); + world.playSound( null, pos, soundType.getPlaceSound(), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileCable cable ) @@ -67,19 +66,19 @@ public abstract class ItemBlockCable extends BlockItem @Nonnull @Override - public String getTranslationKey() + public String getDescriptionId() { if( translationKey == null ) { - translationKey = Util.createTranslationKey( "block", Registry.ITEM.getId( this ) ); + translationKey = Util.makeDescriptionId( "block", Registry.ITEM.getKey( this ) ); } return translationKey; } @Override - public void appendStacks( @Nonnull ItemGroup group, @Nonnull DefaultedList list ) + public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList list ) { - if( isIn( group ) ) + if( allowdedIn( group ) ) { list.add( new ItemStack( this ) ); } @@ -87,36 +86,36 @@ public abstract class ItemBlockCable extends BlockItem public static class WiredModem extends ItemBlockCable { - public WiredModem( BlockCable block, Settings settings ) + public WiredModem( BlockCable block, Properties settings ) { super( block, settings ); } @Nonnull @Override - public ActionResult place( ItemPlacementContext context ) + public InteractionResult place( BlockPlaceContext context ) { - ItemStack stack = context.getStack(); + ItemStack stack = context.getItemInHand(); if( stack.isEmpty() ) { - return ActionResult.FAIL; + return InteractionResult.FAIL; } - World world = context.getWorld(); - BlockPos pos = context.getBlockPos(); + Level world = context.getLevel(); + BlockPos pos = context.getClickedPos(); BlockState existingState = world.getBlockState( pos ); // Try to add a modem to a cable - if( existingState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && existingState.get( MODEM ) == CableModemVariant.None ) + if( existingState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && existingState.getValue( MODEM ) == CableModemVariant.None ) { - Direction side = context.getSide() + Direction side = context.getClickedFace() .getOpposite(); - BlockState newState = existingState.with( MODEM, CableModemVariant.from( side ) ) - .with( CONNECTIONS.get( side ), existingState.get( CABLE ) ); + BlockState newState = existingState.setValue( MODEM, CableModemVariant.from( side ) ) + .setValue( CONNECTIONS.get( side ), existingState.getValue( CABLE ) ); if( placeAt( world, pos, newState, context.getPlayer() ) ) { - stack.decrement( 1 ); - return ActionResult.SUCCESS; + stack.shrink( 1 ); + return InteractionResult.SUCCESS; } } @@ -126,48 +125,48 @@ public abstract class ItemBlockCable extends BlockItem public static class Cable extends ItemBlockCable { - public Cable( BlockCable block, Settings settings ) + public Cable( BlockCable block, Properties settings ) { super( block, settings ); } @Nonnull @Override - public ActionResult place( ItemPlacementContext context ) + public InteractionResult place( BlockPlaceContext context ) { - ItemStack stack = context.getStack(); + ItemStack stack = context.getItemInHand(); if( stack.isEmpty() ) { - return ActionResult.FAIL; + return InteractionResult.FAIL; } - World world = context.getWorld(); - BlockPos pos = context.getBlockPos(); + Level world = context.getLevel(); + BlockPos pos = context.getClickedPos(); // Try to add a cable to a modem inside the block we're clicking on. - BlockPos insidePos = pos.offset( context.getSide() + BlockPos insidePos = pos.relative( context.getClickedFace() .getOpposite() ); BlockState insideState = world.getBlockState( insidePos ); - if( insideState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && !insideState.get( BlockCable.CABLE ) && placeAtCorrected( world, + if( insideState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && !insideState.getValue( BlockCable.CABLE ) && placeAtCorrected( world, insidePos, - insideState.with( + insideState.setValue( BlockCable.CABLE, true ) ) ) { - stack.decrement( 1 ); - return ActionResult.SUCCESS; + stack.shrink( 1 ); + return InteractionResult.SUCCESS; } // Try to add a cable to a modem adjacent to this block BlockState existingState = world.getBlockState( pos ); - if( existingState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && !existingState.get( BlockCable.CABLE ) && placeAtCorrected( world, + if( existingState.getBlock() == ComputerCraftRegistry.ModBlocks.CABLE && !existingState.getValue( BlockCable.CABLE ) && placeAtCorrected( world, pos, - existingState.with( + existingState.setValue( BlockCable.CABLE, true ) ) ) { - stack.decrement( 1 ); - return ActionResult.SUCCESS; + stack.shrink( 1 ); + return InteractionResult.SUCCESS; } return super.place( context ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 077486c8e..75d14193f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -18,23 +18,22 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import java.util.Collections; import java.util.Map; @@ -57,10 +56,10 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = getPos().offset( getDirection() ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + BlockPos pos = getBlockPos().relative( getDirection() ); + return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Nonnull @@ -97,7 +96,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile private void onRemove() { - if( world == null || !world.isClient ) + if( level == null || !level.isClientSide ) { node.remove(); connectionsFormed = false; @@ -106,20 +105,20 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - if( player.isInSneakingPose() ) + if( player.isCrouching() ) { - return ActionResult.PASS; + return InteractionResult.PASS; } if( !canAttachPeripheral() ) { - return ActionResult.FAIL; + return InteractionResult.FAIL; } - if( this.world.isClient ) + if( this.level.isClientSide ) { - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } String oldName = peripheral.getConnectedName(); @@ -129,39 +128,39 @@ public class TileCable extends TileGeneric implements IPeripheralTile { if( oldName != null ) { - player.sendMessage( new TranslatableText( "chat.computercraft.wired_modem.peripheral_disconnected", + player.displayClientMessage( new TranslatableComponent( "chat.computercraft.wired_modem.peripheral_disconnected", ChatHelpers.copy( oldName ) ), false ); } if( newName != null ) { - player.sendMessage( new TranslatableText( "chat.computercraft.wired_modem.peripheral_connected", + player.displayClientMessage( new TranslatableComponent( "chat.computercraft.wired_modem.peripheral_connected", ChatHelpers.copy( newName ) ), false ); } } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } @Override public void onNeighbourChange( @Nonnull BlockPos neighbour ) { Direction dir = getDirection(); - if( neighbour.equals( getPos().offset( dir ) ) && hasModem() && !getCachedState().canPlaceAt( getWorld(), getPos() ) ) + if( neighbour.equals( getBlockPos().relative( dir ) ) && hasModem() && !getBlockState().canSurvive( getLevel(), getBlockPos() ) ) { if( hasCable() ) { // Drop the modem and convert to cable - Block.dropStack( getWorld(), getPos(), new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ) ); - getWorld().setBlockState( getPos(), - getCachedState().with( BlockCable.MODEM, CableModemVariant.None ) ); + Block.popResource( getLevel(), getBlockPos(), new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ) ); + getLevel().setBlockAndUpdate( getBlockPos(), + getBlockState().setValue( BlockCable.MODEM, CableModemVariant.None ) ); modemChanged(); connectionsChanged(); } else { // Drop everything and remove block - Block.dropStack( getWorld(), getPos(), new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ) ); - getWorld().removeBlock( getPos(), false ); + Block.popResource( getLevel(), getBlockPos(), new ItemStack( ComputerCraftRegistry.ModItems.WIRED_MODEM ) ); + getLevel().removeBlock( getBlockPos(), false ); // This'll call #destroy(), so we don't need to reset the network here. } @@ -180,18 +179,18 @@ public class TileCable extends TileGeneric implements IPeripheralTile public boolean hasModem() { - return getCachedState().get( BlockCable.MODEM ) != CableModemVariant.None; + return getBlockState().getValue( BlockCable.MODEM ) != CableModemVariant.None; } boolean hasCable() { - return getCachedState().get( BlockCable.CABLE ); + return getBlockState().getValue( BlockCable.CABLE ); } void modemChanged() { // Tell anyone who cares that the connection state has changed - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return; } @@ -203,25 +202,25 @@ public class TileCable extends TileGeneric implements IPeripheralTile peripheralAccessAllowed = false; peripheral.detach(); node.updatePeripherals( Collections.emptyMap() ); - markDirty(); + setChanged(); updateBlockState(); } } void connectionsChanged() { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return; } - BlockState state = getCachedState(); - World world = getWorld(); - BlockPos current = getPos(); + BlockState state = getBlockState(); + Level world = getLevel(); + BlockPos current = getBlockPos(); for( Direction facing : DirectionUtil.FACINGS ) { - BlockPos offset = current.offset( facing ); - if( !world.isChunkLoaded( offset ) ) + BlockPos offset = current.relative( facing ); + if( !world.hasChunkAt( offset ) ) { continue; } @@ -255,20 +254,20 @@ public class TileCable extends TileGeneric implements IPeripheralTile private void updateBlockState() { - BlockState state = getCachedState(); - CableModemVariant oldVariant = state.get( BlockCable.MODEM ); + BlockState state = getBlockState(); + CableModemVariant oldVariant = state.getValue( BlockCable.MODEM ); CableModemVariant newVariant = CableModemVariant.from( oldVariant.getFacing(), modem.getModemState() .isOpen(), peripheralAccessAllowed ); if( oldVariant != newVariant ) { - world.setBlockState( getPos(), state.with( BlockCable.MODEM, newVariant ) ); + level.setBlockAndUpdate( getBlockPos(), state.setValue( BlockCable.MODEM, newVariant ) ); } } private void refreshPeripheral() { - if( world != null && !isRemoved() && peripheral.attach( world, getPos(), getDirection() ) ) + if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), getDirection() ) ) { updateConnectedPeripherals(); } @@ -291,10 +290,10 @@ public class TileCable extends TileGeneric implements IPeripheralTile public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { super.onNeighbourTileEntityChange( neighbour ); - if( !world.isClient && peripheralAccessAllowed ) + if( !level.isClientSide && peripheralAccessAllowed ) { Direction facing = getDirection(); - if( getPos().offset( facing ) + if( getBlockPos().relative( facing ) .equals( neighbour ) ) { refreshPeripheral(); @@ -305,7 +304,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Override public void blockTick() { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return; } @@ -323,7 +322,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile connectionsChanged(); if( peripheralAccessAllowed ) { - peripheral.attach( world, pos, getDirection() ); + peripheral.attach( level, worldPosition, getDirection() ); updateConnectedPeripherals(); } } @@ -333,7 +332,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile { if( !peripheralAccessAllowed ) { - peripheral.attach( world, getPos(), getDirection() ); + peripheral.attach( level, getBlockPos(), getDirection() ); if( !peripheral.hasPeripheral() ) { return; @@ -356,56 +355,56 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nullable private Direction getMaybeDirection() { - return getCachedState().get( BlockCable.MODEM ).getFacing(); + return getBlockState().getValue( BlockCable.MODEM ).getFacing(); } @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); peripheral.read( nbt, "" ); } @Nonnull @Override - public NbtCompound writeNbt( NbtCompound nbt ) + public CompoundTag save( CompoundTag nbt ) { nbt.putBoolean( NBT_PERIPHERAL_ENABLED, peripheralAccessAllowed ); peripheral.write( nbt, "" ); - return super.writeNbt( nbt ); + return super.save( nbt ); } @Override - public void markRemoved() + public void setRemoved() { - super.markRemoved(); + super.setRemoved(); onRemove(); } @Override - public void cancelRemoval() + public void clearRemoved() { - super.cancelRemoval(); + super.clearRemoved(); TickScheduler.schedule( this ); } @Override - public void setCachedState( BlockState state ) + public void setBlockState( BlockState state ) { - super.setCachedState( state ); + super.setBlockState( state ); if( state != null ) return; - if( !world.isClient ) + if( !level.isClientSide ) { - world.getBlockTickScheduler() - .schedule( pos, - getCachedState().getBlock(), 0 ); + level.getBlockTicks() + .scheduleTick( worldPosition, + getBlockState().getBlock(), 0 ); } } public IWiredElement getElement( Direction facing ) { - return BlockCable.canConnectIn( getCachedState(), facing ) ? cable : null; + return BlockCable.canConnectIn( getBlockState(), facing ) ? cable : null; } @Nonnull @@ -419,17 +418,17 @@ public class TileCable extends TileGeneric implements IPeripheralTile { @Nonnull @Override - public World getWorld() + public Level getWorld() { - return TileCable.this.getWorld(); + return TileCable.this.getLevel(); } @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = getPos(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + BlockPos pos = getBlockPos(); + return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index abeebbe38..62073dbff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -17,21 +17,20 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import java.util.*; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON; @@ -54,7 +53,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile super( type, pos, state ); for( int i = 0; i < peripherals.length; i++ ) { - Direction facing = Direction.byId( i ); + Direction facing = Direction.from3DDataValue( i ); peripherals[i] = new WiredModemLocalPeripheral(); } } @@ -79,7 +78,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile private void doRemove() { - if( world == null || !world.isClient ) + if( level == null || !level.isClientSide ) { node.remove(); connectionsFormed = false; @@ -88,11 +87,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } // On server, we interacted if a peripheral was found @@ -106,7 +105,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } @Override @@ -118,11 +117,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Override public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { - if( !world.isClient && peripheralAccessAllowed ) + if( !level.isClientSide && peripheralAccessAllowed ) { for( Direction facing : DirectionUtil.FACINGS ) { - if( getPos().offset( facing ) + if( getBlockPos().relative( facing ) .equals( neighbour ) ) { refreshPeripheral( facing ); @@ -134,7 +133,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Override public void blockTick() { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return; } @@ -153,7 +152,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { for( Direction facing : DirectionUtil.FACINGS ) { - peripherals[facing.ordinal()].attach( world, getPos(), facing ); + peripherals[facing.ordinal()].attach( level, getBlockPos(), facing ); } updateConnectedPeripherals(); } @@ -162,17 +161,17 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile private void connectionsChanged() { - if( getWorld().isClient ) + if( getLevel().isClientSide ) { return; } - World world = getWorld(); - BlockPos current = getPos(); + Level world = getLevel(); + BlockPos current = getBlockPos(); for( Direction facing : DirectionUtil.FACINGS ) { - BlockPos offset = current.offset( facing ); - if( !world.isChunkLoaded( offset ) ) + BlockPos offset = current.relative( facing ); + if( !world.hasChunkAt( offset ) ) { continue; } @@ -190,7 +189,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile private void refreshPeripheral( @Nonnull Direction facing ) { WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()]; - if( world != null && !isRemoved() && peripheral.attach( world, getPos(), facing ) ) + if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) ) { updateConnectedPeripherals(); } @@ -226,16 +225,16 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile private void updateBlockState() { - BlockState state = getCachedState(); + BlockState state = getBlockState(); boolean modemOn = modemState.isOpen(), peripheralOn = peripheralAccessAllowed; - if( state.get( MODEM_ON ) == modemOn && state.get( PERIPHERAL_ON ) == peripheralOn ) + if( state.getValue( MODEM_ON ) == modemOn && state.getValue( PERIPHERAL_ON ) == peripheralOn ) { return; } - getWorld().setBlockState( getPos(), - state.with( MODEM_ON, modemOn ) - .with( PERIPHERAL_ON, peripheralOn ) ); + getLevel().setBlockAndUpdate( getBlockPos(), + state.setValue( MODEM_ON, modemOn ) + .setValue( PERIPHERAL_ON, peripheralOn ) ); } private Set getConnectedPeripheralNames() @@ -265,7 +264,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile for( Direction facing : DirectionUtil.FACINGS ) { WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()]; - peripheral.attach( world, getPos(), facing ); + peripheral.attach( level, getBlockPos(), facing ); hasAny |= peripheral.hasPeripheral(); } @@ -291,7 +290,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile updateBlockState(); } - private static void sendPeripheralChanges( PlayerEntity player, String kind, Collection peripherals ) + private static void sendPeripheralChanges( Player player, String kind, Collection peripherals ) { if( peripherals.isEmpty() ) { @@ -301,7 +300,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile List names = new ArrayList<>( peripherals ); names.sort( Comparator.naturalOrder() ); - LiteralText base = new LiteralText( "" ); + TextComponent base = new TextComponent( "" ); for( int i = 0; i < names.size(); i++ ) { if( i > 0 ) @@ -311,13 +310,13 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile base.append( ChatHelpers.copy( names.get( i ) ) ); } - player.sendMessage( new TranslatableText( kind, base ), false ); + player.displayClientMessage( new TranslatableComponent( kind, base ), false ); } @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); for( int i = 0; i < peripherals.length; i++ ) { @@ -327,27 +326,27 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public NbtCompound writeNbt( NbtCompound nbt ) + public CompoundTag save( CompoundTag nbt ) { nbt.putBoolean( NBT_PERIPHERAL_ENABLED, peripheralAccessAllowed ); for( int i = 0; i < peripherals.length; i++ ) { peripherals[i].write( nbt, Integer.toString( i ) ); } - return super.writeNbt( nbt ); + return super.save( nbt ); } @Override - public void markRemoved() + public void setRemoved() { - super.markRemoved(); + super.setRemoved(); doRemove(); } @Override - public void cancelRemoval() + public void clearRemoved() { - super.cancelRemoval(); + super.clearRemoved(); TickScheduler.schedule( this ); } @@ -378,10 +377,10 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = getPos().offset( side ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + BlockPos pos = getBlockPos().relative( side ); + return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Nonnull @@ -430,17 +429,17 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public World getWorld() + public Level getWorld() { - return entity.getWorld(); + return entity.getLevel(); } @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = entity.getPos(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + BlockPos pos = entity.getBlockPos(); + return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index de10208a1..d670aa68b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -11,14 +11,13 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Peripherals; import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.block.Block; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import java.util.Collections; import java.util.Map; @@ -45,7 +44,7 @@ public final class WiredModemLocalPeripheral * @param direction The direction so search in * @return Whether the peripheral changed. */ - public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull Direction direction ) + public boolean attach( @Nonnull Level world, @Nonnull BlockPos origin, @Nonnull Direction direction ) { IPeripheral oldPeripheral = peripheral; IPeripheral peripheral = this.peripheral = getPeripheralFrom( world, origin, direction ); @@ -75,9 +74,9 @@ public final class WiredModemLocalPeripheral } @Nullable - private IPeripheral getPeripheralFrom( World world, BlockPos pos, Direction direction ) + private IPeripheral getPeripheralFrom( Level world, BlockPos pos, Direction direction ) { - BlockPos offset = pos.offset( direction ); + BlockPos offset = pos.relative( direction ); Block block = world.getBlockState( offset ) .getBlock(); @@ -135,7 +134,7 @@ public final class WiredModemLocalPeripheral return peripheral == null ? Collections.emptyMap() : Collections.singletonMap( type + "_" + id, peripheral ); } - public void write( @Nonnull NbtCompound tag, @Nonnull String suffix ) + public void write( @Nonnull CompoundTag tag, @Nonnull String suffix ) { if( id >= 0 ) { @@ -147,7 +146,7 @@ public final class WiredModemLocalPeripheral } } - public void read( @Nonnull NbtCompound tag, @Nonnull String suffix ) + public void read( @Nonnull CompoundTag tag, @Nonnull String suffix ) { id = tag.contains( NBT_PERIPHERAL_ID + suffix, NBTUtil.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_PERIPHERAL_ID + suffix ) : -1; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 242354538..7574018cf 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -22,10 +22,9 @@ import dan200.computercraft.core.apis.PeripheralAPI; import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.world.level.Level; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -122,7 +121,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW @Nonnull @Override - public World getWorld() + public Level getWorld() { return modem.getWorld(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index c6ebe3809..979212717 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -10,56 +10,55 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.peripheral.modem.ModemShapes; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ShapeContext; -import net.minecraft.block.Waterloggable; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.fluid.FluidState; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.BooleanProperty; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.world.BlockView; -import net.minecraft.world.WorldAccess; -import net.minecraft.world.WorldView; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +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.BooleanProperty; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; import static dan200.computercraft.shared.util.WaterloggableHelpers.*; -public class BlockWirelessModem extends BlockGeneric implements Waterloggable +public class BlockWirelessModem extends BlockGeneric implements SimpleWaterloggedBlock { - public static final DirectionProperty FACING = Properties.FACING; - public static final BooleanProperty ON = BooleanProperty.of( "on" ); + public static final DirectionProperty FACING = BlockStateProperties.FACING; + public static final BooleanProperty ON = BooleanProperty.create( "on" ); private final ComputerFamily family; - public BlockWirelessModem( Settings settings, BlockEntityType type, ComputerFamily family ) + public BlockWirelessModem( Properties settings, BlockEntityType type, ComputerFamily family ) { super( settings, type ); this.family = family; - setDefaultState( getStateManager().getDefaultState() - .with( FACING, Direction.NORTH ) - .with( ON, false ) - .with( WATERLOGGED, false ) ); + registerDefaultState( getStateDefinition().any() + .setValue( FACING, Direction.NORTH ) + .setValue( ON, false ) + .setValue( WATERLOGGED, false ) ); } @Nonnull @Override @Deprecated - public BlockState getStateForNeighborUpdate( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull WorldAccess world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); - return side == state.get( FACING ) && !state.canPlaceAt( world, pos ) ? state.getFluidState() - .getBlockState() : state; + return side == state.getValue( FACING ) && !state.canSurvive( world, pos ) ? state.getFluidState() + .createLegacyBlock() : state; } @Nonnull @@ -72,32 +71,32 @@ public class BlockWirelessModem extends BlockGeneric implements Waterloggable @Override @Deprecated - public boolean canPlaceAt( BlockState state, @Nonnull WorldView world, BlockPos pos ) + public boolean canSurvive( BlockState state, @Nonnull LevelReader world, BlockPos pos ) { - Direction facing = state.get( FACING ); - return sideCoversSmallSquare( world, pos.offset( facing ), facing.getOpposite() ); + Direction facing = state.getValue( FACING ); + return canSupportCenter( world, pos.relative( facing ), facing.getOpposite() ); } @Nonnull @Override @Deprecated - public VoxelShape getOutlineShape( BlockState blockState, @Nonnull BlockView blockView, @Nonnull BlockPos blockPos, @Nonnull ShapeContext context ) + public VoxelShape getShape( BlockState blockState, @Nonnull BlockGetter blockView, @Nonnull BlockPos blockPos, @Nonnull CollisionContext context ) { - return ModemShapes.getBounds( blockState.get( FACING ) ); + return ModemShapes.getBounds( blockState.getValue( FACING ) ); } @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, - placement.getSide() + return defaultBlockState().setValue( FACING, + placement.getClickedFace() .getOpposite() ) - .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); + .setValue( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( FACING, ON, WATERLOGGED ); } @@ -113,7 +112,7 @@ public class BlockWirelessModem extends BlockGeneric implements Waterloggable @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileWirelessModem( getTypeByFamily( family ), family == ComputerFamily.ADVANCED, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 82d584a5b..0f44deaf5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -12,14 +12,13 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; public class TileWirelessModem extends TileGeneric implements IPeripheralTile { @@ -37,21 +36,21 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile } @Override - public void cancelRemoval() + public void clearRemoved() { - super.cancelRemoval(); + super.clearRemoved(); TickScheduler.schedule( this ); } @Override - public void setCachedState( BlockState state ) + public void setBlockState( BlockState state ) { - super.setCachedState( state ); + super.setBlockState( state ); if( state != null ) return; hasModemDirection = false; - world.getBlockTickScheduler() - .schedule( getPos(), - getCachedState().getBlock(), 0 ); + level.getBlockTicks() + .scheduleTick( getBlockPos(), + getBlockState().getBlock(), 0 ); } @Override @@ -87,17 +86,17 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile } hasModemDirection = true; - modemDirection = getCachedState().get( BlockWirelessModem.FACING ); + modemDirection = getBlockState().getValue( BlockWirelessModem.FACING ); } private void updateBlockState() { boolean on = modem.getModemState() .isOpen(); - BlockState state = getCachedState(); - if( state.get( BlockWirelessModem.ON ) != on ) + BlockState state = getBlockState(); + if( state.getValue( BlockWirelessModem.ON ) != on ) { - getWorld().setBlockState( getPos(), state.with( BlockWirelessModem.ON, on ) ); + getLevel().setBlockAndUpdate( getBlockPos(), state.setValue( BlockWirelessModem.ON, on ) ); } } @@ -121,18 +120,18 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile @Nonnull @Override - public World getWorld() + public Level getWorld() { - return entity.getWorld(); + return entity.getLevel(); } @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = entity.getPos() - .offset( entity.modemDirection ); - return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); + BlockPos pos = entity.getBlockPos() + .relative( entity.modemDirection ); + return new Vec3( pos.getX(), pos.getY(), pos.getZ() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index a628cadf0..3f0ca47aa 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -10,8 +10,8 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; public abstract class WirelessModemPeripheral extends ModemPeripheral { @@ -32,10 +32,10 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } else { - World world = getWorld(); + Level world = getWorld(); if( world != null ) { - Vec3d position = getPosition(); + Vec3 position = getPosition(); double minRange = ComputerCraft.modemRange; double maxRange = ComputerCraft.modemHighAltitudeRange; if( world.isRaining() && world.isThundering() ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java index 14f809156..7f3dcb35f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java @@ -83,7 +83,7 @@ public class WirelessNetwork implements IPacketNetwork { double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical double distanceSq = receiver.getPosition() - .squaredDistanceTo( sender.getPosition() ); + .distanceToSqr( sender.getPosition() ); if( interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange ) { receiver.receiveSameDimension( packet, Math.sqrt( distanceSq ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 22b3175e1..82e9b776d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -9,50 +9,49 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.EnumProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +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.block.state.properties.EnumProperty; public class BlockMonitor extends BlockGeneric { - public static final DirectionProperty ORIENTATION = DirectionProperty.of( "orientation", Direction.UP, Direction.DOWN, Direction.NORTH ); + public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation", Direction.UP, Direction.DOWN, Direction.NORTH ); - public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - static final EnumProperty STATE = EnumProperty.of( "state", MonitorEdgeState.class ); + static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class ); public boolean advanced; - public BlockMonitor( Settings settings, BlockEntityType type, boolean advanced ) + public BlockMonitor( Properties settings, BlockEntityType type, boolean advanced ) { super( settings, type ); this.advanced = advanced; // TODO: Test underwater - do we need isSolid at all? - setDefaultState( getStateManager().getDefaultState() - .with( ORIENTATION, Direction.NORTH ) - .with( FACING, Direction.NORTH ) - .with( STATE, MonitorEdgeState.NONE ) ); + registerDefaultState( getStateDefinition().any() + .setValue( ORIENTATION, Direction.NORTH ) + .setValue( FACING, Direction.NORTH ) + .setValue( STATE, MonitorEdgeState.NONE ) ); } @Override @Nullable - public BlockState getPlacementState( ItemPlacementContext context ) + public BlockState getStateForPlacement( BlockPlaceContext context ) { - float pitch = context.getPlayer() == null ? 0 : context.getPlayer().getPitch(); + float pitch = context.getPlayer() == null ? 0 : context.getPlayer().getXRot(); Direction orientation; if( pitch > 66.5f ) { @@ -69,20 +68,20 @@ public class BlockMonitor extends BlockGeneric orientation = Direction.NORTH; } - return getDefaultState().with( FACING, - context.getPlayerFacing() + return defaultBlockState().setValue( FACING, + context.getHorizontalDirection() .getOpposite() ) - .with( ORIENTATION, orientation ); + .setValue( ORIENTATION, orientation ); } @Override - public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, @Nonnull ItemStack itemStack ) { - super.onPlaced( world, pos, blockState, livingEntity, itemStack ); + super.setPlacedBy( world, pos, blockState, livingEntity, itemStack ); BlockEntity entity = world.getBlockEntity( pos ); - if( entity instanceof TileMonitor monitor && !world.isClient ) + if( entity instanceof TileMonitor monitor && !world.isClientSide ) { // Defer the block update if we're being placed by another TE. See #691 if( livingEntity == null || livingEntity instanceof FakePlayer ) @@ -96,14 +95,14 @@ public class BlockMonitor extends BlockGeneric } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( ORIENTATION, FACING, STATE ); } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileMonitor( advanced ? ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED : ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, advanced, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index db226210e..12eef839f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -8,11 +8,11 @@ package dan200.computercraft.shared.peripheral.monitor; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexBuffer; import dan200.computercraft.shared.common.ClientTerminal; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.gl.VertexBuffer; -import net.minecraft.util.math.BlockPos; +import net.minecraft.core.BlockPos; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL30; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index 1c4a0a87e..9568cf1f3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -6,13 +6,12 @@ package dan200.computercraft.shared.peripheral.monitor; -import net.minecraft.util.StringIdentifiable; - import javax.annotation.Nonnull; +import net.minecraft.util.StringRepresentable; import static dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState.Flags.*; -public enum MonitorEdgeState implements StringIdentifiable +public enum MonitorEdgeState implements StringRepresentable { NONE( "none", 0 ), @@ -60,7 +59,7 @@ public enum MonitorEdgeState implements StringIdentifiable @Nonnull @Override - public String asString() + public String getSerializedName() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 38fd20cfa..c6299cab3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -15,19 +15,18 @@ import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import java.util.HashSet; import java.util.Set; @@ -74,16 +73,16 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile return; } destroyed = true; - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { contractNeighbours(); } } @Override - public void markRemoved() + public void setRemoved() { - super.markRemoved(); + super.setRemoved(); if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) { clientMonitor.destroy(); @@ -103,23 +102,23 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - if( !player.isInSneakingPose() && getFront() == hit.getSide() ) + if( !player.isCrouching() && getFront() == hit.getDirection() ) { - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - monitorTouched( (float) (hit.getPos().x - hit.getBlockPos() + monitorTouched( (float) (hit.getLocation().x - hit.getBlockPos() .getX()), - (float) (hit.getPos().y - hit.getBlockPos() + (float) (hit.getLocation().y - hit.getBlockPos() .getY()), - (float) (hit.getPos().z - hit.getBlockPos() + (float) (hit.getLocation().z - hit.getBlockPos() .getZ()) ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } - return ActionResult.PASS; + return InteractionResult.PASS; } @Override @@ -172,7 +171,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } @Override - protected final void readDescription( @Nonnull NbtCompound nbt ) + protected final void readDescription( @Nonnull CompoundTag nbt ) { super.readDescription( nbt ); @@ -215,7 +214,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } @Override - protected void writeDescription( @Nonnull NbtCompound nbt ) + protected void writeDescription( @Nonnull CompoundTag nbt ) { super.writeDescription( nbt ); nbt.putInt( NBT_X, xIndex ); @@ -231,18 +230,18 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private MonitorState getNeighbour( int x, int y ) { - BlockPos pos = getPos(); + BlockPos pos = getBlockPos(); Direction right = getRight(); Direction down = getDown(); int xOffset = -xIndex + x; int yOffset = -yIndex + y; - return getSimilarMonitorAt( pos.offset( right, xOffset ) - .offset( down, yOffset ) ); + return getSimilarMonitorAt( pos.relative( right, xOffset ) + .relative( down, yOffset ) ); } public Direction getRight() { - return getDirection().rotateYCounterclockwise(); + return getDirection().getCounterClockWise(); } public Direction getDown() @@ -257,13 +256,13 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private MonitorState getSimilarMonitorAt( BlockPos pos ) { - if( pos.equals( getPos() ) ) + if( pos.equals( getBlockPos() ) ) { return MonitorState.present( this ); } - World world = getWorld(); - if( world == null || !world.isChunkLoaded( pos ) ) + Level world = getLevel(); + if( world == null || !world.hasChunkAt( pos ) ) { return MonitorState.UNLOADED; } @@ -283,19 +282,19 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile { // Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's // fun problems with the block being missing on the client. - BlockState state = getCachedState(); - return state.contains( BlockMonitor.FACING ) ? state.get( BlockMonitor.FACING ) : Direction.NORTH; + BlockState state = getBlockState(); + return state.hasProperty( BlockMonitor.FACING ) ? state.getValue( BlockMonitor.FACING ) : Direction.NORTH; } public Direction getOrientation() { - return getCachedState().get( BlockMonitor.ORIENTATION ); + return getBlockState().getValue( BlockMonitor.ORIENTATION ); } @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); xIndex = nbt.getInt( NBT_X ); yIndex = nbt.getInt( NBT_Y ); @@ -307,13 +306,13 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile @Nonnull @Override - public NbtCompound writeNbt( NbtCompound nbt ) + public CompoundTag save( CompoundTag nbt ) { nbt.putInt( NBT_X, xIndex ); nbt.putInt( NBT_Y, yIndex ); nbt.putInt( NBT_WIDTH, width ); nbt.putInt( NBT_HEIGHT, height ); - return super.writeNbt( nbt ); + return super.save( nbt ); } // @Override //TODO: make BlockEntityRenderer work with this, i guess. @@ -325,9 +324,9 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile // Sizing and placement stuff @Override - public void cancelRemoval() + public void clearRemoved() { - super.cancelRemoval(); + super.clearRemoved(); needsValidating = true; TickScheduler.schedule( this ); } @@ -397,9 +396,9 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile { // Otherwise fetch the origin and attempt to get its monitor // Note this may load chunks, but we don't really have a choice here. - BlockPos pos = getPos(); - BlockEntity te = world.getBlockEntity( pos.offset( getRight(), -xIndex ) - .offset( getDown(), -yIndex ) ); + BlockPos pos = getBlockPos(); + BlockEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ) + .relative( getDown(), -yIndex ) ); if( !(te instanceof TileMonitor) ) { return null; @@ -416,9 +415,9 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile return clientMonitor; } - BlockPos pos = getPos(); - BlockEntity te = world.getBlockEntity( pos.offset( getRight(), -xIndex ) - .offset( getDown(), -yIndex ) ); + BlockPos pos = getBlockPos(); + BlockEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ) + .relative( getDown(), -yIndex ) ); if( !(te instanceof TileMonitor) ) { return null; @@ -431,7 +430,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile { if( xIndex != 0 || yIndex != 0 ) { - ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getPos() ); + ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getBlockPos() ); return; } @@ -444,8 +443,8 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private void updateBlockState() { - getWorld().setBlockState( getPos(), - getCachedState().with( BlockMonitor.STATE, + getLevel().setBlock( getBlockPos(), + getBlockState().setValue( BlockMonitor.STATE, MonitorEdgeState.fromConnections( yIndex < height - 1, yIndex > 0, xIndex > 0, xIndex < width - 1 ) ), 2 ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java index 8aa24a4b3..ec660394e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.peripheral.monitor; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public class XYPair { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index d906fb391..ce267cc12 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -8,90 +8,89 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.stat.Stats; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.BooleanProperty; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.Nameable; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.stats.Stats; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +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.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.DirectionProperty; public class BlockPrinter extends BlockGeneric { - static final BooleanProperty TOP = BooleanProperty.of( "top" ); - static final BooleanProperty BOTTOM = BooleanProperty.of( "bottom" ); - private static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + static final BooleanProperty TOP = BooleanProperty.create( "top" ); + static final BooleanProperty BOTTOM = BooleanProperty.create( "bottom" ); + private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockPrinter( Settings settings ) + public BlockPrinter( Properties settings ) { super( settings, ComputerCraftRegistry.ModTiles.PRINTER ); - setDefaultState( getStateManager().getDefaultState() - .with( FACING, Direction.NORTH ) - .with( TOP, false ) - .with( BOTTOM, false ) ); + registerDefaultState( getStateDefinition().any() + .setValue( FACING, Direction.NORTH ) + .setValue( TOP, false ) + .setValue( BOTTOM, false ) ); } @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, - placement.getPlayerFacing() + return defaultBlockState().setValue( FACING, + placement.getHorizontalDirection() .getOpposite() ); } @Override - public void afterBreak( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity te, @Nonnull ItemStack stack ) + public void playerDestroy( @Nonnull Level world, @Nonnull Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity te, @Nonnull ItemStack stack ) { if( te instanceof Nameable && ((Nameable) te).hasCustomName() ) { - player.incrementStat( Stats.MINED.getOrCreateStat( this ) ); - player.addExhaustion( 0.005F ); + player.awardStat( Stats.BLOCK_MINED.get( this ) ); + player.causeFoodExhaustion( 0.005F ); ItemStack result = new ItemStack( this ); - result.setCustomName( ((Nameable) te).getCustomName() ); - dropStack( world, pos, result ); + result.setHoverName( ((Nameable) te).getCustomName() ); + popResource( world, pos, result ); } else { - super.afterBreak( world, player, pos, state, te, stack ); + super.playerDestroy( world, player, pos, state, te, stack ); } } @Override - public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) { - if( stack.hasCustomName() ) + if( stack.hasCustomHoverName() ) { BlockEntity tileentity = world.getBlockEntity( pos ); if( tileentity instanceof TilePrinter ) { - ((TilePrinter) tileentity).customName = stack.getName(); + ((TilePrinter) tileentity).customName = stack.getHoverName(); } } } @Override - protected void appendProperties( StateManager.Builder properties ) + protected void createBlockStateDefinition( StateDefinition.Builder properties ) { properties.add( FACING, TOP, BOTTOM ); } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TilePrinter( ComputerCraftRegistry.ModTiles.PRINTER, pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 4b94cb54d..f32db943a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -8,35 +8,34 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.SingleIntArray; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.SimpleInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.ArrayPropertyDelegate; -import net.minecraft.screen.PropertyDelegate; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.slot.Slot; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.SimpleContainer; +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.ContainerData; +import net.minecraft.world.inventory.SimpleContainerData; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; -public class ContainerPrinter extends ScreenHandler +public class ContainerPrinter extends AbstractContainerMenu { - private final Inventory inventory; - private final PropertyDelegate properties; + private final Container inventory; + private final ContainerData properties; - public ContainerPrinter( int id, PlayerInventory player ) + public ContainerPrinter( int id, Inventory player ) { - this( id, player, new SimpleInventory( TilePrinter.SLOTS ), new ArrayPropertyDelegate( 1 ) ); + this( id, player, new SimpleContainer( TilePrinter.SLOTS ), new SimpleContainerData( 1 ) ); } - private ContainerPrinter( int id, PlayerInventory player, Inventory inventory, PropertyDelegate properties ) + private ContainerPrinter( int id, Inventory player, Container inventory, ContainerData properties ) { super( ComputerCraftRegistry.ModContainers.PRINTER, id ); this.properties = properties; this.inventory = inventory; - addProperties( properties ); + addDataSlots( properties ); // Ink slot addSlot( new Slot( inventory, 0, 13, 35 ) ); @@ -69,7 +68,7 @@ public class ContainerPrinter extends ScreenHandler } } - public ContainerPrinter( int id, PlayerInventory player, TilePrinter printer ) + public ContainerPrinter( int id, Inventory player, TilePrinter printer ) { this( id, player, printer, (SingleIntArray) () -> printer.isPrinting() ? 1 : 0 ); } @@ -81,19 +80,19 @@ public class ContainerPrinter extends ScreenHandler @Nonnull @Override - public ItemStack transferSlot( @Nonnull PlayerEntity player, int index ) + public ItemStack quickMoveStack( @Nonnull Player player, int index ) { Slot slot = slots.get( index ); - if( slot == null || !slot.hasStack() ) + if( slot == null || !slot.hasItem() ) { return ItemStack.EMPTY; } - ItemStack stack = slot.getStack(); + ItemStack stack = slot.getItem(); ItemStack result = stack.copy(); if( index < 13 ) { // Transfer from printer to inventory - if( !insertItem( stack, 13, 49, true ) ) + if( !moveItemStackTo( stack, 13, 49, true ) ) { return ItemStack.EMPTY; } @@ -103,14 +102,14 @@ public class ContainerPrinter extends ScreenHandler // Transfer from inventory to printer if( TilePrinter.isInk( stack ) ) { - if( !insertItem( stack, 0, 1, false ) ) + if( !moveItemStackTo( stack, 0, 1, false ) ) { return ItemStack.EMPTY; } } else //if is paper { - if( !insertItem( stack, 1, 13, false ) ) + if( !moveItemStackTo( stack, 1, 13, false ) ) { return ItemStack.EMPTY; } @@ -119,11 +118,11 @@ public class ContainerPrinter extends ScreenHandler if( stack.isEmpty() ) { - slot.setStack( ItemStack.EMPTY ); + slot.set( ItemStack.EMPTY ); } else { - slot.markDirty(); + slot.setChanged(); } if( stack.getCount() == result.getCount() ) @@ -131,13 +130,13 @@ public class ContainerPrinter extends ScreenHandler return ItemStack.EMPTY; } - slot.onTakeItem( player, stack ); + slot.onTake( player, stack ); return result; } @Override - public boolean canUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { - return inventory.canPlayerUse( player ); + return inventory.stillValid( player ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index d38eb04e1..505a86f7d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -15,33 +15,32 @@ import dan200.computercraft.shared.util.ColourUtils; import dan200.computercraft.shared.util.DefaultSidedInventory; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.Inventories; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Hand; -import net.minecraft.util.Nameable; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.Nameable; +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.DyeColor; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; -public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, Nameable, NamedScreenHandlerFactory +public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, Nameable, MenuProvider { static final int SLOTS = 13; private static final String NBT_NAME = "CustomName"; @@ -64,10 +63,10 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent 6, }; private static final int[] SIDE_SLOTS = new int[] { 0 }; - private final DefaultedList inventory = DefaultedList.ofSize( SLOTS, ItemStack.EMPTY ); + private final NonNullList inventory = NonNullList.withSize( SLOTS, ItemStack.EMPTY ); private final ItemStorage itemHandlerAll = ItemStorage.wrap( this ); private final Terminal page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); - Text customName; + Component customName; private String pageTitle = ""; private boolean printing = false; @@ -84,18 +83,18 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { - if( player.isInSneakingPose() ) + if( player.isCrouching() ) { - return ActionResult.PASS; + return InteractionResult.PASS; } - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - player.openHandledScreen( this ); + player.openMenu( this ); } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } private void ejectContents() @@ -106,11 +105,11 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( !stack.isEmpty() ) { // Remove the stack from the inventory - setStack( i, ItemStack.EMPTY ); + setItem( i, ItemStack.EMPTY ); // Spawn the item in the world - WorldUtil.dropItemStack( stack, getWorld(), - Vec3d.of( getPos() ) + WorldUtil.dropItemStack( stack, getLevel(), + Vec3.atLowerCornerOf( getBlockPos() ) .add( 0.5, 0.75, 0.5 ) ); } } @@ -149,28 +148,28 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private void updateBlockState( boolean top, boolean bottom ) { - if( removed ) + if( remove ) { return; } - BlockState state = getCachedState(); - if( state.get( BlockPrinter.TOP ) == top & state.get( BlockPrinter.BOTTOM ) == bottom ) + BlockState state = getBlockState(); + if( state.getValue( BlockPrinter.TOP ) == top & state.getValue( BlockPrinter.BOTTOM ) == bottom ) { return; } - getWorld().setBlockState( getPos(), - state.with( BlockPrinter.TOP, top ) - .with( BlockPrinter.BOTTOM, bottom ) ); + getLevel().setBlockAndUpdate( getBlockPos(), + state.setValue( BlockPrinter.TOP, top ) + .setValue( BlockPrinter.BOTTOM, bottom ) ); } @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); - customName = nbt.contains( NBT_NAME ) ? Text.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + customName = nbt.contains( NBT_NAME ) ? Component.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; // Read page synchronized( page ) @@ -181,16 +180,16 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } // Read inventory - Inventories.readNbt( nbt, inventory ); + ContainerHelper.loadAllItems( nbt, inventory ); } @Nonnull @Override - public NbtCompound writeNbt( @Nonnull NbtCompound nbt ) + public CompoundTag save( @Nonnull CompoundTag nbt ) { if( customName != null ) { - nbt.putString( NBT_NAME, Text.Serializer.toJson( customName ) ); + nbt.putString( NBT_NAME, Component.Serializer.toJson( customName ) ); } // Write page @@ -202,9 +201,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } // Write inventory - Inventories.writeNbt( nbt, inventory ); + ContainerHelper.saveAllItems( nbt, inventory ); - return super.writeNbt( nbt ); + return super.save( nbt ); } boolean isPrinting() @@ -214,7 +213,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent // IInventory implementation @Override - public int size() + public int getContainerSize() { return inventory.size(); } @@ -234,14 +233,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public ItemStack getStack( int slot ) + public ItemStack getItem( int slot ) { return inventory.get( slot ); } @Nonnull @Override - public ItemStack removeStack( int slot, int count ) + public ItemStack removeItem( int slot, int count ) { ItemStack stack = inventory.get( slot ); if( stack.isEmpty() ) @@ -251,7 +250,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( stack.getCount() <= count ) { - setStack( slot, ItemStack.EMPTY ); + setItem( slot, ItemStack.EMPTY ); return stack; } @@ -262,17 +261,17 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent inventory.set( slot, ItemStack.EMPTY ); updateBlockState(); } - markDirty(); + setChanged(); return part; } @Nonnull @Override - public ItemStack removeStack( int slot ) + public ItemStack removeItemNoUpdate( int slot ) { ItemStack result = inventory.get( slot ); inventory.set( slot, ItemStack.EMPTY ); - markDirty(); + setChanged(); updateBlockState(); return result; } @@ -280,32 +279,32 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent // ISidedInventory implementation @Override - public void setStack( int slot, @Nonnull ItemStack stack ) + public void setItem( int slot, @Nonnull ItemStack stack ) { inventory.set( slot, stack ); - markDirty(); + setChanged(); updateBlockState(); } @Override - public boolean canPlayerUse( @Nonnull PlayerEntity playerEntity ) + public boolean stillValid( @Nonnull Player playerEntity ) { return isUsable( playerEntity, false ); } @Override - public void clear() + public void clearContent() { for( int i = 0; i < inventory.size(); i++ ) { inventory.set( i, ItemStack.EMPTY ); } - markDirty(); + setChanged(); updateBlockState(); } @Override - public boolean isValid( int slot, @Nonnull ItemStack stack ) + public boolean canPlaceItem( int slot, @Nonnull ItemStack stack ) { if( slot == 0 ) { @@ -328,7 +327,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public int[] getAvailableSlots( @Nonnull Direction side ) + public int[] getSlotsForFace( @Nonnull Direction side ) { switch( side ) { @@ -400,7 +399,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( inventory.get( slot ) .isEmpty() ) { - setStack( slot, stack ); + setItem( slot, stack ); printing = false; return true; } @@ -480,21 +479,21 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent page.setCursorPos( 0, 0 ); // Decrement ink - inkStack.decrement( 1 ); + inkStack.shrink( 1 ); if( inkStack.isEmpty() ) { inventory.set( 0, ItemStack.EMPTY ); } // Decrement paper - paperStack.decrement( 1 ); + paperStack.shrink( 1 ); if( paperStack.isEmpty() ) { inventory.set( i, ItemStack.EMPTY ); updateBlockState(); } - markDirty(); + setChanged(); printing = true; return true; } @@ -503,10 +502,10 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public Text getName() + public Component getName() { - return customName != null ? customName : new TranslatableText( getCachedState().getBlock() - .getTranslationKey() ); + return customName != null ? customName : new TranslatableComponent( getBlockState().getBlock() + .getDescriptionId() ); } @Override @@ -516,21 +515,21 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - public Text getDisplayName() + public Component getDisplayName() { return Nameable.super.getDisplayName(); } @Nullable @Override - public Text getCustomName() + public Component getCustomName() { return customName; } @Nonnull @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player ) { return new ContainerPrinter( id, inventory, this ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index 34405b92b..6af719802 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -8,59 +8,58 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityTicker; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +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; public class BlockSpeaker extends BlockGeneric { - private static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockSpeaker( Settings settings ) + public BlockSpeaker( Properties settings ) { super( settings, ComputerCraftRegistry.ModTiles.SPEAKER ); - setDefaultState( getStateManager().getDefaultState() - .with( FACING, Direction.NORTH ) ); + registerDefaultState( getStateDefinition().any() + .setValue( FACING, Direction.NORTH ) ); } @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, - placement.getPlayerFacing() + return defaultBlockState().setValue( FACING, + placement.getHorizontalDirection() .getOpposite() ); } @Override - protected void appendProperties( StateManager.Builder properties ) + protected void createBlockStateDefinition( StateDefinition.Builder properties ) { properties.add( FACING ); } @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileSpeaker( ComputerCraftRegistry.ModTiles.SPEAKER, pos, state ); } @Nullable @Override - public BlockEntityTicker getTicker( World world, BlockState state, BlockEntityType type ) + public BlockEntityTicker getTicker( Level world, BlockState state, BlockEntityType type ) { - return world.isClient ? null : BlockSpeaker.checkType( type, ComputerCraftRegistry.ModTiles.SPEAKER, TileSpeaker::tick ); + return world.isClientSide ? null : BlockSpeaker.createTickerHelper( type, ComputerCraftRegistry.ModTiles.SPEAKER, TileSpeaker::tick ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index a74ea4849..1c990c874 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -14,17 +14,16 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage; import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage; -import net.minecraft.block.enums.Instrument; -import net.minecraft.network.packet.s2c.play.PlaySoundIdS2CPacket; +import net.minecraft.ResourceLocationException; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundCustomSoundPacket; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.sound.SoundCategory; -import net.minecraft.util.Identifier; -import net.minecraft.util.InvalidIdentifierException; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; import java.util.Optional; import java.util.UUID; @@ -46,7 +45,7 @@ public abstract class SpeakerPeripheral implements IPeripheral private long lastPlayTime = 0; private long lastPositionTime; - private Vec3d lastPosition; + private Vec3 lastPosition; public void update() { @@ -58,14 +57,14 @@ public abstract class SpeakerPeripheral implements IPeripheral // in the last second. if( lastPlayTime > 0 && (clock - lastPositionTime) >= 20 ) { - Vec3d position = getPosition(); + Vec3 position = getPosition(); if( lastPosition == null || lastPosition.distanceTo( position ) >= 0.1 ) { lastPosition = position; lastPositionTime = clock; NetworkHandler.sendToAllTracking( new SpeakerMoveClientMessage( getSource(), position ), - getWorld().getWorldChunk( new BlockPos( position ) ) + getWorld().getChunkAt( new BlockPos( position ) ) ); } } @@ -104,12 +103,12 @@ public abstract class SpeakerPeripheral implements IPeripheral float volume = (float) checkFinite( 1, volumeA.orElse( 1.0 ) ); float pitch = (float) checkFinite( 2, pitchA.orElse( 1.0 ) ); - Identifier identifier; + ResourceLocation identifier; try { - identifier = new Identifier( name ); + identifier = new ResourceLocation( name ); } - catch( InvalidIdentifierException e ) + catch( ResourceLocationException e ) { throw new LuaException( "Malformed sound name '" + name + "' " ); } @@ -117,7 +116,7 @@ public abstract class SpeakerPeripheral implements IPeripheral return playSound( context, identifier, volume, pitch, false ); } - private synchronized boolean playSound( ILuaContext context, Identifier name, float volume, float pitch, boolean isNote ) throws LuaException + private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException { if( clock - lastPlayTime < MIN_TICKS_BETWEEN_SOUNDS ) { @@ -127,10 +126,10 @@ public abstract class SpeakerPeripheral implements IPeripheral if( clock - lastPlayTime != 0 || notesThisTick.get() >= ComputerCraft.maxNotesPerTick ) return false; } - World world = getWorld(); - Vec3d pos = getPosition(); + Level world = getWorld(); + Vec3 pos = getPosition(); - float actualVolume = MathHelper.clamp( volume, 0.0f, 3.0f ); + float actualVolume = Mth.clamp( volume, 0.0f, 3.0f ); float range = actualVolume * 16; context.issueMainThreadTask( () -> { @@ -142,9 +141,9 @@ public abstract class SpeakerPeripheral implements IPeripheral if( isNote ) { - server.getPlayerManager().sendToAround( - null, pos.x, pos.y, pos.z, range, world.getRegistryKey(), - new PlaySoundIdS2CPacket( name, SoundCategory.RECORDS, pos, actualVolume, pitch ) + server.getPlayerList().broadcast( + null, pos.x, pos.y, pos.z, range, world.dimension(), + new ClientboundCustomSoundPacket( name, SoundSource.RECORDS, pos, actualVolume, pitch ) ); } else @@ -161,9 +160,9 @@ public abstract class SpeakerPeripheral implements IPeripheral return true; } - public abstract World getWorld(); + public abstract Level getWorld(); - public abstract Vec3d getPosition(); + public abstract Vec3 getPosition(); /** * Plays a note block note through the speaker. @@ -186,10 +185,10 @@ public abstract class SpeakerPeripheral implements IPeripheral float volume = (float) checkFinite( 1, volumeA.orElse( 1.0 ) ); float pitch = (float) checkFinite( 2, pitchA.orElse( 1.0 ) ); - Instrument instrument = null; - for( Instrument testInstrument : Instrument.values() ) + NoteBlockInstrument instrument = null; + for( NoteBlockInstrument testInstrument : NoteBlockInstrument.values() ) { - if( testInstrument.asString() + if( testInstrument.getSerializedName() .equalsIgnoreCase( name ) ) { instrument = testInstrument; @@ -205,7 +204,7 @@ public abstract class SpeakerPeripheral implements IPeripheral // If the resource location for note block notes changes, this method call will need to be updated boolean success = playSound( context, - instrument.getSound().getId(), + instrument.getSoundEvent().getLocation(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 2a0de631e..e062a3e65 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -9,15 +9,14 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; import java.util.UUID; public class TileSpeaker extends TileGeneric implements IPeripheralTile @@ -33,7 +32,7 @@ public class TileSpeaker extends TileGeneric implements IPeripheralTile peripheral = new Peripheral( this ); } - public static void tick( World world, BlockPos pos, BlockState state, TileSpeaker tileSpeaker ) + public static void tick( Level world, BlockPos pos, BlockState state, TileSpeaker tileSpeaker ) { tileSpeaker.peripheral.update(); } @@ -55,16 +54,16 @@ public class TileSpeaker extends TileGeneric implements IPeripheralTile } @Override - public World getWorld() + public Level getWorld() { - return speaker.getWorld(); + return speaker.getLevel(); } @Override - public Vec3d getPosition() + public Vec3 getPosition() { - BlockPos pos = speaker.getPos(); - return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); + BlockPos pos = speaker.getBlockPos(); + return new Vec3( pos.getX(), pos.getY(), pos.getZ() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index fec1ce9ef..847b37d19 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -14,11 +14,11 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.collection.DefaultedList; +import net.minecraft.core.NonNullList; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; /** * Control the current pocket computer, adding or removing upgrades. @@ -63,20 +63,20 @@ public class PocketAPI implements ILuaAPI public final Object[] equipBack() { Entity entity = computer.getEntity(); - if( !(entity instanceof PlayerEntity) ) + if( !(entity instanceof Player) ) { return new Object[] { false, "Cannot find player" }; } - PlayerEntity player = (PlayerEntity) entity; - PlayerInventory inventory = player.getInventory(); + Player player = (Player) entity; + Inventory inventory = player.getInventory(); IPocketUpgrade previousUpgrade = computer.getUpgrade(); // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite // one. We start from the position the item is currently in and loop round to the start. - IPocketUpgrade newUpgrade = findUpgrade( inventory.main, inventory.selectedSlot, previousUpgrade ); + IPocketUpgrade newUpgrade = findUpgrade( inventory.items, inventory.selected, previousUpgrade ); if( newUpgrade == null ) { - newUpgrade = findUpgrade( inventory.offHand, 0, previousUpgrade ); + newUpgrade = findUpgrade( inventory.offhand, 0, previousUpgrade ); } if( newUpgrade == null ) { @@ -89,10 +89,10 @@ public class PocketAPI implements ILuaAPI ItemStack stack = previousUpgrade.getCraftingItem(); if( !stack.isEmpty() ) { - stack = InventoryUtil.storeItems( stack, ItemStorage.wrap( inventory ), inventory.selectedSlot ); + stack = InventoryUtil.storeItems( stack, ItemStorage.wrap( inventory ), inventory.selected ); if( !stack.isEmpty() ) { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPos() ); + WorldUtil.dropItemStack( stack, player.getCommandSenderWorld(), player.position() ); } } } @@ -103,7 +103,7 @@ public class PocketAPI implements ILuaAPI return new Object[] { true }; } - private static IPocketUpgrade findUpgrade( DefaultedList inv, int start, IPocketUpgrade previous ) + private static IPocketUpgrade findUpgrade( NonNullList inv, int start, IPocketUpgrade previous ) { for( int i = 0; i < inv.size(); i++ ) { @@ -116,7 +116,7 @@ public class PocketAPI implements ILuaAPI { // Consume an item from this stack and exit the loop invStack = invStack.copy(); - invStack.decrement( 1 ); + invStack.shrink( 1 ); inv.set( (i + start) % inv.size(), invStack.isEmpty() ? ItemStack.EMPTY : invStack ); return newUpgrade; @@ -138,12 +138,12 @@ public class PocketAPI implements ILuaAPI public final Object[] unequipBack() { Entity entity = computer.getEntity(); - if( !(entity instanceof PlayerEntity) ) + if( !(entity instanceof Player) ) { return new Object[] { false, "Cannot find player" }; } - PlayerEntity player = (PlayerEntity) entity; - PlayerInventory inventory = player.getInventory(); + Player player = (Player) entity; + Inventory inventory = player.getInventory(); IPocketUpgrade previousUpgrade = computer.getUpgrade(); if( previousUpgrade == null ) @@ -156,10 +156,10 @@ public class PocketAPI implements ILuaAPI ItemStack stack = previousUpgrade.getCraftingItem(); if( !stack.isEmpty() ) { - stack = InventoryUtil.storeItems( stack, ItemStorage.wrap( inventory ), inventory.selectedSlot ); + stack = InventoryUtil.storeItems( stack, ItemStorage.wrap( inventory ), inventory.selected ); if( stack.isEmpty() ) { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPos() ); + WorldUtil.dropItemStack( stack, player.getCommandSenderWorld(), player.position() ); } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index 56b2e615a..3b69c6d1b 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -17,18 +17,17 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import java.util.Collections; import java.util.Map; @@ -40,7 +39,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces private Entity entity; private ItemStack stack; - public PocketServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family ) + public PocketServerComputer( Level world, int computerID, String label, int instanceID, ComputerFamily family ) { super( world, computerID, label, instanceID, family, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); } @@ -55,15 +54,15 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces return null; } - if( entity instanceof PlayerEntity ) + if( entity instanceof Player ) { - PlayerInventory inventory = ((PlayerEntity) entity).getInventory(); - return inventory.main.contains( stack ) || inventory.offHand.contains( stack ) ? entity : null; + Inventory inventory = ((Player) entity).getInventory(); + return inventory.items.contains( stack ) || inventory.offhand.contains( stack ) ? entity : null; } else if( entity instanceof LivingEntity ) { LivingEntity living = (LivingEntity) entity; - return living.getMainHandStack() == stack || living.getOffHandStack() == stack ? entity : null; + return living.getMainHandItem() == stack || living.getOffhandItem() == stack ? entity : null; } else { @@ -87,14 +86,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public int getLight() { - NbtCompound tag = getUserData(); + CompoundTag tag = getUserData(); return tag.contains( NBT_LIGHT, NBTUtil.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_LIGHT ) : -1; } @Override public void setLight( int colour ) { - NbtCompound tag = getUserData(); + CompoundTag tag = getUserData(); if( colour >= 0 && colour <= 0xFFFFFF ) { if( !tag.contains( NBT_LIGHT, NBTUtil.TAG_ANY_NUMERIC ) || tag.getInt( NBT_LIGHT ) != colour ) @@ -112,7 +111,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Nonnull @Override - public NbtCompound getUpgradeNBTData() + public CompoundTag getUpgradeNBTData() { return ItemPocketComputer.getUpgradeInfo( stack ); } @@ -120,9 +119,9 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public void updateUpgradeNBTData() { - if( entity instanceof PlayerEntity ) + if( entity instanceof Player ) { - ((PlayerEntity) entity).getInventory().markDirty(); + ((Player) entity).getInventory().setChanged(); } } @@ -135,7 +134,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Nonnull @Override - public Map getUpgrades() + public Map getUpgrades() { return upgrade == null ? Collections.emptyMap() : Collections.singletonMap( upgrade.getUpgradeID(), getPeripheral( ComputerSide.BACK ) ); } @@ -172,12 +171,12 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces { if( entity != null ) { - setWorld( entity.getEntityWorld() ); - setPosition( entity.getBlockPos() ); + setWorld( entity.getCommandSenderWorld() ); + setPosition( entity.blockPosition() ); } // If a new entity has picked it up then rebroadcast the terminal to them - if( entity != this.entity && entity instanceof ServerPlayerEntity ) + if( entity != this.entity && entity instanceof ServerPlayer ) { markTerminalChanged(); } @@ -197,11 +196,11 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces { super.broadcastState( force ); - if( (hasTerminalChanged() || force) && entity instanceof ServerPlayerEntity ) + if( (hasTerminalChanged() || force) && entity instanceof ServerPlayer ) { // Broadcast the state to the current entity if they're not already interacting with it. - ServerPlayerEntity player = (ServerPlayerEntity) entity; - if( player.networkHandler != null && !isInteracting( player ) ) + ServerPlayer player = (ServerPlayer) entity; + if( player.connection != null && !isInteracting( player ) ) { NetworkHandler.sendToPlayer( player, createTerminalPacket() ); } diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java index 2e1a066c2..47edf5f3e 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java @@ -10,31 +10,30 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import net.minecraft.util.Hand; - +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +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 javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PocketComputerMenuProvider implements NamedScreenHandlerFactory, ExtendedScreenHandlerFactory +public class PocketComputerMenuProvider implements MenuProvider, ExtendedScreenHandlerFactory { private final ServerComputer computer; - private final Text name; + private final Component name; private final ItemPocketComputer item; - private final Hand hand; + private final InteractionHand hand; private final boolean isTypingOnly; - public PocketComputerMenuProvider( ServerComputer computer, ItemStack stack, ItemPocketComputer item, Hand hand, boolean isTypingOnly ) + public PocketComputerMenuProvider( ServerComputer computer, ItemStack stack, ItemPocketComputer item, InteractionHand hand, boolean isTypingOnly ) { this.computer = computer; - name = stack.getName(); + name = stack.getHoverName(); this.item = item; this.hand = hand; this.isTypingOnly = isTypingOnly; @@ -43,19 +42,19 @@ public class PocketComputerMenuProvider implements NamedScreenHandlerFactory, Ex @Nonnull @Override - public Text getDisplayName() + public Component getDisplayName() { return name; } @Nullable @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity entity ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player entity ) { return new ComputerMenuWithoutInventory( isTypingOnly ? ComputerCraftRegistry.ModContainers.POCKET_COMPUTER_NO_TERM : ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, id, inventory, p -> { - ItemStack stack = p.getStackInHand( hand ); + ItemStack stack = p.getItemInHand( hand ); return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer; }, computer, item.getFamily() @@ -63,9 +62,9 @@ public class PocketComputerMenuProvider implements NamedScreenHandlerFactory, Ex } @Override - public void writeScreenOpeningData( ServerPlayerEntity player, PacketByteBuf packetByteBuf ) + public void writeScreenOpeningData( ServerPlayer player, FriendlyByteBuf packetByteBuf ) { packetByteBuf.writeInt( computer.getInstanceID() ); - packetByteBuf.writeEnumConstant( computer.getFamily() ); + packetByteBuf.writeEnum( computer.getFamily() ); } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 69d586869..ca845be99 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -26,24 +26,23 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Formatting; -import net.minecraft.util.Hand; -import net.minecraft.util.TypedActionResult; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - +import net.minecraft.ChatFormatting; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; @@ -58,7 +57,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I private final ComputerFamily family; - public ItemPocketComputer( Settings settings, ComputerFamily family ) + public ItemPocketComputer( Properties settings, ComputerFamily family ) { super( settings ); this.family = family; @@ -92,7 +91,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I ClientComputer computer = getClientComputer( stack ); if( computer != null && computer.isOn() ) { - NbtCompound computerNBT = computer.getUserData(); + CompoundTag computerNBT = computer.getUserData(); if( computerNBT != null && computerNBT.contains( NBT_LIGHT ) ) { return computerNBT.getInt( NBT_LIGHT ); @@ -103,7 +102,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I public static void setUpgrade( @Nonnull ItemStack stack, IPocketUpgrade upgrade ) { - NbtCompound compound = stack.getOrCreateNbt(); + CompoundTag compound = stack.getOrCreateTag(); if( upgrade == null ) { @@ -119,9 +118,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I compound.remove( NBT_UPGRADE_INFO ); } - public static NbtCompound getUpgradeInfo( @Nonnull ItemStack stack ) + public static CompoundTag getUpgradeInfo( @Nonnull ItemStack stack ) { - return stack.getOrCreateSubNbt( NBT_UPGRADE_INFO ); + return stack.getOrCreateTagElement( NBT_UPGRADE_INFO ); } // @Nullable @@ -142,10 +141,10 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Nonnull @Override - public TypedActionResult use( World world, PlayerEntity player, @Nonnull Hand hand ) + public InteractionResultHolder use( Level world, Player player, @Nonnull InteractionHand hand ) { - ItemStack stack = player.getStackInHand( hand ); - if( !world.isClient ) + ItemStack stack = player.getItemInHand( hand ); + if( !world.isClientSide ) { PocketServerComputer computer = createServerComputer( world, player.getInventory(), player, stack ); @@ -164,20 +163,20 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I if( !stop && computer != null ) { - boolean isTypingOnly = hand == Hand.OFF_HAND; + boolean isTypingOnly = hand == InteractionHand.OFF_HAND; new ComputerContainerData( computer ).open( player, new PocketComputerMenuProvider( computer, stack, this, hand, isTypingOnly ) ); } } - return new TypedActionResult<>( ActionResult.SUCCESS, stack ); + return new InteractionResultHolder<>( InteractionResult.SUCCESS, stack ); } @Override - public void inventoryTick( @Nonnull ItemStack stack, World world, @Nonnull Entity entity, int slotNum, boolean selected ) + public void inventoryTick( @Nonnull ItemStack stack, Level world, @Nonnull Entity entity, int slotNum, boolean selected ) { - if( !world.isClient ) + if( !world.isClientSide ) { // Server side - Inventory inventory = entity instanceof PlayerEntity ? ((PlayerEntity) entity).getInventory() : null; + Container inventory = entity instanceof Player ? ((Player) entity).getInventory() : null; PocketServerComputer computer = createServerComputer( world, inventory, entity, stack ); if( computer != null ) { @@ -195,7 +194,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I setComputerID( stack, id ); if( inventory != null ) { - inventory.markDirty(); + inventory.setChanged(); } } @@ -206,7 +205,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I setLabel( stack, label ); if( inventory != null ) { - inventory.markDirty(); + inventory.setChanged(); } } @@ -225,27 +224,27 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } @Override - public void appendTooltip( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, TooltipContext flag ) + public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List list, TooltipFlag flag ) { if( flag.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) { - list.add( new TranslatableText( "gui.computercraft.tooltip.computer_id", id ).formatted( Formatting.GRAY ) ); + list.add( new TranslatableComponent( "gui.computercraft.tooltip.computer_id", id ).withStyle( ChatFormatting.GRAY ) ); } } } @Nonnull @Override - public Text getName( @Nonnull ItemStack stack ) + public Component getName( @Nonnull ItemStack stack ) { - String baseString = getTranslationKey( stack ); + String baseString = getDescriptionId( stack ); IPocketUpgrade upgrade = getUpgrade( stack ); if( upgrade != null ) { - return new TranslatableText( baseString + ".upgraded", new TranslatableText( upgrade.getUnlocalisedAdjective() ) ); + return new TranslatableComponent( baseString + ".upgraded", new TranslatableComponent( upgrade.getUnlocalisedAdjective() ) ); } else { @@ -256,9 +255,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I // IComputerItem implementation @Override - public void appendStacks( @Nonnull ItemGroup group, @Nonnull DefaultedList stacks ) + public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList stacks ) { - if( !isIn( group ) ) + if( !allowdedIn( group ) ) { return; } @@ -274,31 +273,31 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I ItemStack result = new ItemStack( this ); if( id >= 0 ) { - result.getOrCreateNbt() + result.getOrCreateTag() .putInt( NBT_ID, id ); } if( label != null ) { - result.setCustomName( new LiteralText( label ) ); + result.setHoverName( new TextComponent( label ) ); } if( upgrade != null ) { - result.getOrCreateNbt() + result.getOrCreateTag() .putString( NBT_UPGRADE, upgrade.getUpgradeID() .toString() ); } if( colour != -1 ) { - result.getOrCreateNbt() + result.getOrCreateTag() .putInt( NBT_COLOUR, colour ); } return result; } - public PocketServerComputer createServerComputer( final World world, Inventory inventory, Entity entity, @Nonnull ItemStack stack ) + public PocketServerComputer createServerComputer( final Level world, Container inventory, Entity entity, @Nonnull ItemStack stack ) { - if( world.isClient ) + if( world.isClientSide ) { return null; } @@ -332,7 +331,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I ComputerCraft.serverComputerRegistry.add( instanceID, computer ); if( inventory != null ) { - inventory.markDirty(); + inventory.setChanged(); } } computer.setWorld( world ); @@ -341,7 +340,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I public static IPocketUpgrade getUpgrade( @Nonnull ItemStack stack ) { - NbtCompound compound = stack.getNbt(); + CompoundTag compound = stack.getTag(); return compound != null && compound.contains( NBT_UPGRADE ) ? PocketUpgrades.get( compound.getString( NBT_UPGRADE ) ) : null; } @@ -350,7 +349,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I private static void setComputerID( @Nonnull ItemStack stack, int computerID ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_ID, computerID ); } @@ -377,11 +376,11 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { if( label != null ) { - stack.setCustomName( new LiteralText( label ) ); + stack.setHoverName( new TextComponent( label ) ); } else { - stack.removeCustomName(); + stack.resetHoverName(); } return true; } @@ -402,30 +401,30 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I private static int getInstanceID( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; } private static int getSessionID( @Nonnull ItemStack stack ) { - NbtCompound nbt = stack.getNbt(); + CompoundTag nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_SESSION ) ? nbt.getInt( NBT_SESSION ) : -1; } private static void setInstanceID( @Nonnull ItemStack stack, int instanceID ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_INSTANCE, instanceID ); } private static void setSessionID( @Nonnull ItemStack stack, int sessionID ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_SESSION, sessionID ); } @Override - public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) + public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull Level world ) { int id = getComputerID( stack ); if( id >= 0 ) diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index ac2d7303d..e7554d664 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -9,9 +9,8 @@ package dan200.computercraft.shared.pocket.items; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; public final class PocketComputerItemFactory { diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index 6ba68d559..7735aa453 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -11,11 +11,10 @@ import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.peripheral.modem.ModemState; -import net.minecraft.entity.Entity; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; public class PocketModem extends AbstractPocketUpgrade { @@ -23,7 +22,7 @@ public class PocketModem extends AbstractPocketUpgrade public PocketModem( boolean advanced ) { - super( new Identifier( "computercraft", advanced ? "wireless_modem_advanced" : "wireless_modem_normal" ), + super( new ResourceLocation( "computercraft", advanced ? "wireless_modem_advanced" : "wireless_modem_normal" ), advanced ? ComputerCraftRegistry.ModBlocks.WIRELESS_MODEM_ADVANCED : ComputerCraftRegistry.ModBlocks.WIRELESS_MODEM_NORMAL ); this.advanced = advanced; } @@ -49,7 +48,7 @@ public class PocketModem extends AbstractPocketUpgrade if( entity != null ) { - modem.setLocation( entity.getEntityWorld(), entity.getCameraPosVec( 1 ) ); + modem.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) ); } ModemState state = modem.getModemState(); diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index d43c860b4..abf9bde16 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -9,22 +9,21 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; public class PocketModemPeripheral extends WirelessModemPeripheral { - private World world = null; - private Vec3d position = Vec3d.ZERO; + private Level world = null; + private Vec3 position = Vec3.ZERO; public PocketModemPeripheral( boolean advanced ) { super( new ModemState(), advanced ); } - void setLocation( World world, Vec3d position ) + void setLocation( Level world, Vec3 position ) { this.position = position; this.world = world; @@ -32,14 +31,14 @@ public class PocketModemPeripheral extends WirelessModemPeripheral @Nonnull @Override - public World getWorld() + public Level getWorld() { return world; } @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { return position; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index b5c98c7ad..beaa53a36 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -10,17 +10,16 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.ComputerCraftRegistry; -import net.minecraft.entity.Entity; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; public class PocketSpeaker extends AbstractPocketUpgrade { public PocketSpeaker() { - super( new Identifier( "computercraft", "speaker" ), ComputerCraftRegistry.ModBlocks.SPEAKER ); + super( new ResourceLocation( "computercraft", "speaker" ), ComputerCraftRegistry.ModBlocks.SPEAKER ); } @Nullable @@ -43,7 +42,7 @@ public class PocketSpeaker extends AbstractPocketUpgrade Entity entity = access.getEntity(); if( entity != null ) { - speaker.setLocation( entity.getEntityWorld(), entity.getCameraPosVec( 1 ) ); + speaker.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) ); } speaker.update(); diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java index 315abd72c..366d9ac58 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java @@ -8,28 +8,28 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral { - private World world = null; - private Vec3d position = Vec3d.ZERO; + private Level world = null; + private Vec3 position = Vec3.ZERO; - void setLocation( World world, Vec3d position ) + void setLocation( Level world, Vec3 position ) { this.position = position; this.world = world; } @Override - public World getWorld() + public Level getWorld() { return world; } @Override - public Vec3d getPosition() + public Vec3 getPosition() { return world != null ? position : null; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index 279a2ad1c..a952baaa1 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -11,41 +11,40 @@ import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.SpecialCraftingRecipe; -import net.minecraft.recipe.SpecialRecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; -public final class PocketComputerUpgradeRecipe extends SpecialCraftingRecipe +public final class PocketComputerUpgradeRecipe extends CustomRecipe { - public static final RecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( PocketComputerUpgradeRecipe::new ); + public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( PocketComputerUpgradeRecipe::new ); - private PocketComputerUpgradeRecipe( Identifier identifier ) + private PocketComputerUpgradeRecipe( ResourceLocation identifier ) { super( identifier ); } @Nonnull @Override - public ItemStack getOutput() + public ItemStack getResultItem() { return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null ); } @Override - public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { return !craft( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack craft( @Nonnull CraftingContainer inventory ) { // Scan the grid for a pocket computer ItemStack computer = ItemStack.EMPTY; @@ -56,7 +55,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialCraftingRecipe { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStack( x + y * inventory.getWidth() ); + ItemStack item = inventory.getItem( x + y * inventory.getWidth() ); if( !item.isEmpty() && item.getItem() instanceof ItemPocketComputer ) { computer = item; @@ -84,7 +83,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialCraftingRecipe { for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStack( x + y * inventory.getWidth() ); + ItemStack item = inventory.getItem( x + y * inventory.getWidth() ); if( x == computerX && y == computerY ) { continue; @@ -119,7 +118,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialCraftingRecipe } @Override - public boolean fits( int x, int y ) + public boolean canCraftInDimensions( int x, int y ) { return x >= 2 && y >= 2; } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index cdbdc0c66..d617ae3aa 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -36,14 +36,14 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.CommandBlockBlockEntity; -import net.minecraft.item.Item; -import net.minecraft.item.MusicDiscItem; -import net.minecraft.loot.condition.LootConditionType; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.RecordItem; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.CommandBlockEntity; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; public final class ComputerCraftProxyCommon { @@ -70,8 +70,8 @@ public final class ComputerCraftProxyCommon ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> { BlockEntity tile = world.getBlockEntity( pos ); - return ComputerCraft.enableCommandBlock && tile instanceof CommandBlockBlockEntity ? - new CommandBlockPeripheral( (CommandBlockBlockEntity) tile ) : null; + return ComputerCraft.enableCommandBlock && tile instanceof CommandBlockEntity ? + new CommandBlockPeripheral( (CommandBlockEntity) tile ) : null; } ); // Register bundled power providers @@ -84,7 +84,7 @@ public final class ComputerCraftProxyCommon { return (IMedia) item; } - if( item instanceof MusicDiscItem ) + if( item instanceof RecordItem ) { return RecordMedia.INSTANCE; } @@ -146,8 +146,8 @@ public final class ComputerCraftProxyCommon registerCondition( "has_id", HasComputerIdLootCondition.TYPE ); } - private static void registerCondition( String name, LootConditionType serializer ) + private static void registerCondition( String name, LootItemConditionType serializer ) { - Registry.register( Registry.LOOT_CONDITION_TYPE, new Identifier( ComputerCraft.MOD_ID, name ), serializer ); + Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index 6ca4aaadd..fd32629bc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -12,11 +12,10 @@ import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.entity.FurnaceBlockEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.FurnaceBlockEntity; public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler { @@ -44,7 +43,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler // Store the replacement item in the inventory Item replacementStack = stack.getItem() - .getRecipeRemainder(); + .getCraftingRemainingItem(); if( replacementStack != null ) { ItemStack remainder = InventoryUtil.storeItems( new ItemStack( replacementStack ), storage, turtle.getSelectedSlot() ); @@ -63,7 +62,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler private static int getFuelPerItem( @Nonnull ItemStack stack ) { - int burnTime = FurnaceBlockEntity.createFuelTimeMap() + int burnTime = FurnaceBlockEntity.getFuel() .getOrDefault( stack.getItem(), 0 ); return (burnTime * 5) / 100; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java index f54c6f882..7cfbeb8af 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java @@ -8,11 +8,10 @@ package dan200.computercraft.shared.turtle; import com.google.common.eventbus.Subscribe; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.fabric.mixin.SignBlockEntityAccess; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.SignBlockEntity; - import java.util.HashMap; import java.util.Map; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; public class SignInspectHandler { @@ -26,7 +25,7 @@ public class SignInspectHandler Map textTable = new HashMap<>(); for( int k = 0; k < 4; k++ ) { - textTable.put( k + 1, ((SignBlockEntityAccess) sbe).getTexts()[k].asString() ); + textTable.put( k + 1, ((SignBlockEntityAccess) sbe).getTexts()[k].getContents() ); } event.getData().put( "text", textTable ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 801f62d12..dc18b63cc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -19,11 +19,10 @@ import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.turtle.core.*; -import net.minecraft.item.ItemStack; - import java.util.HashMap; import java.util.Map; import java.util.Optional; +import net.minecraft.world.item.ItemStack; /** * The turtle API allows you to control your turtle. @@ -331,7 +330,7 @@ public class TurtleAPI implements ILuaAPI { int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); return turtle.getInventory() - .getStack( actualSlot ) + .getItem( actualSlot ) .getCount(); } @@ -354,8 +353,8 @@ public class TurtleAPI implements ILuaAPI { int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); ItemStack stack = turtle.getInventory() - .getStack( actualSlot ); - return stack.isEmpty() ? 64 : Math.min( stack.getMaxCount(), 64 ) - stack.getCount(); + .getItem( actualSlot ); + return stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount(); } /** @@ -763,7 +762,7 @@ public class TurtleAPI implements ILuaAPI private Object[] getItemDetail( int slot, boolean detailed ) { ItemStack stack = turtle.getInventory() - .getStack( slot ); + .getItem( slot ); if( stack.isEmpty() ) { return new Object[] { null }; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 942214057..a30399a23 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -15,60 +15,64 @@ import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import net.minecraft.block.*; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityTicker; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.FluidState; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.state.StateManager; -import net.minecraft.state.property.DirectionProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockView; -import net.minecraft.world.World; -import net.minecraft.world.WorldAccess; - +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +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.FluidState; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; import javax.annotation.Nonnull; import javax.annotation.Nullable; import static dan200.computercraft.shared.util.WaterloggableHelpers.*; -import static net.minecraft.state.property.Properties.WATERLOGGED; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; -public class BlockTurtle extends BlockComputerBase implements Waterloggable +public class BlockTurtle extends BlockComputerBase implements SimpleWaterloggedBlock { - public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - private static final VoxelShape DEFAULT_SHAPE = VoxelShapes.cuboid( 0.125, 0.125, 0.125, 0.875, 0.875, 0.875 ); + private static final VoxelShape DEFAULT_SHAPE = Shapes.box( 0.125, 0.125, 0.125, 0.875, 0.875, 0.875 ); - public BlockTurtle( Settings settings, ComputerFamily family, BlockEntityType type ) + public BlockTurtle( Properties settings, ComputerFamily family, BlockEntityType type ) { super( settings, family, type ); - setDefaultState( getStateManager().getDefaultState() - .with( FACING, Direction.NORTH ) - .with( WATERLOGGED, false ) ); + registerDefaultState( getStateDefinition().any() + .setValue( FACING, Direction.NORTH ) + .setValue( WATERLOGGED, false ) ); } @Nonnull @Override @Deprecated - public BlockRenderType getRenderType( @Nonnull BlockState state ) + public RenderShape getRenderShape( @Nonnull BlockState state ) { - return BlockRenderType.ENTITYBLOCK_ANIMATED; + return RenderShape.ENTITYBLOCK_ANIMATED; } @Nonnull @Override @Deprecated - public BlockState getStateForNeighborUpdate( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull WorldAccess world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return state; @@ -85,15 +89,15 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nonnull @Override @Deprecated - public VoxelShape getOutlineShape( @Nonnull BlockState state, BlockView world, @Nonnull BlockPos pos, @Nonnull ShapeContext context ) + public VoxelShape getShape( @Nonnull BlockState state, BlockGetter world, @Nonnull BlockPos pos, @Nonnull CollisionContext context ) { BlockEntity tile = world.getBlockEntity( pos ); - Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO; - return offset.equals( Vec3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.offset( offset.x, offset.y, offset.z ); + Vec3 offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3.ZERO; + return offset.equals( Vec3.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.move( offset.x, offset.y, offset.z ); } @Override - public float getBlastResistance() + public float getExplosionResistance() { // TODO Implement below functionality return 2000; @@ -101,14 +105,14 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nullable @Override - public BlockState getPlacementState( ItemPlacementContext placement ) + public BlockState getStateForPlacement( BlockPlaceContext placement ) { - return getDefaultState().with( FACING, placement.getPlayerFacing() ) - .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); + return defaultBlockState().setValue( FACING, placement.getHorizontalDirection() ) + .setValue( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); } @Override - protected void appendProperties( StateManager.Builder builder ) + protected void createBlockStateDefinition( StateDefinition.Builder builder ) { builder.add( FACING, WATERLOGGED ); } @@ -133,17 +137,17 @@ public class BlockTurtle extends BlockComputerBase implements Waterl // } @Override - public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack ) + public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack ) { - super.onPlaced( world, pos, state, player, stack ); + super.setPlacedBy( world, pos, state, player, stack ); BlockEntity tile = world.getBlockEntity( pos ); - if( !world.isClient && tile instanceof TileTurtle turtle ) + if( !world.isClientSide && tile instanceof TileTurtle turtle ) { - if( player instanceof PlayerEntity ) + if( player instanceof Player ) { - ((TileTurtle) tile).setOwningPlayer( ((PlayerEntity) player).getGameProfile() ); + ((TileTurtle) tile).setOwningPlayer( ((Player) player).getGameProfile() ); } if( stack.getItem() instanceof ITurtleItem ) @@ -169,7 +173,7 @@ public class BlockTurtle extends BlockComputerBase implements Waterl } // Set overlay - Identifier overlay = item.getOverlay( stack ); + ResourceLocation overlay = item.getOverlay( stack ); if( overlay != null ) { ((TurtleBrain) turtle.getAccess()).setOverlay( overlay ); @@ -189,15 +193,15 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nullable @Override - public BlockEntity createBlockEntity( BlockPos pos, BlockState state ) + public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { return new TileTurtle( getTypeByFamily( getFamily() ), pos, state, getFamily() ); } @Nullable @Override - public BlockEntityTicker getTicker( World world, BlockState state, BlockEntityType type ) + public BlockEntityTicker getTicker( Level world, BlockState state, BlockEntityType type ) { - return world.isClient ? BlockTurtle.checkType( type, getTypeByFamily( getFamily() ), ( world1, pos, state1, computer ) -> computer.clientTick() ) : super.getTicker( world, state, type ); + return world.isClientSide ? BlockTurtle.createTickerHelper( type, getTypeByFamily( getFamily() ), ( world1, pos, state1, computer ) -> computer.clientTick() ) : super.getTicker( world, state, type ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 38224df84..8ea8006f0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -10,20 +10,20 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.blocks.IComputerTile; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Vec3d; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; public interface ITurtleTile extends IComputerTile { int getColour(); - Identifier getOverlay(); + ResourceLocation getOverlay(); ITurtleUpgrade getUpgrade( TurtleSide side ); ITurtleAccess getAccess(); - Vec3d getRenderOffset( float f ); + Vec3 getRenderOffset( float f ); float getRenderYaw( float f ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index ba6112a82..483aa134b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -22,28 +22,27 @@ import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.util.*; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.DyeItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.util.ActionResult; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +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.DyeColor; +import net.minecraft.world.item.DyeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import java.util.Collections; public class TileTurtle extends TileComputerBase @@ -52,10 +51,10 @@ public class TileTurtle extends TileComputerBase public static final int INVENTORY_SIZE = 16; public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; - private final DefaultedList inventory = DefaultedList - .ofSize( INVENTORY_SIZE, ItemStack.EMPTY ); - private final DefaultedList previousInventory = DefaultedList - .ofSize( INVENTORY_SIZE, ItemStack.EMPTY ); + private final NonNullList inventory = NonNullList + .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + private final NonNullList previousInventory = NonNullList + .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); private boolean inventoryChanged = false; private TurtleBrain brain = new TurtleBrain( this ); private MoveState moveState = MoveState.NOT_MOVED; @@ -83,15 +82,15 @@ public class TileTurtle extends TileComputerBase super.destroy(); // Drop contents - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - int size = size(); + int size = getContainerSize(); for( int i = 0; i < size; i++ ) { - ItemStack stack = getStack( i ); + ItemStack stack = getItem( i ); if( !stack.isEmpty() ) { - WorldUtil.dropItemStack( stack, getWorld(), getPos() ); + WorldUtil.dropItemStack( stack, getLevel(), getBlockPos() ); } } } @@ -101,7 +100,7 @@ public class TileTurtle extends TileComputerBase // Just turn off any redstone we had on for( Direction dir : DirectionUtil.FACINGS ) { - RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); + RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir ); } } } @@ -112,7 +111,7 @@ public class TileTurtle extends TileComputerBase } @Override - public int size() + public int getContainerSize() { return INVENTORY_SIZE; } @@ -132,7 +131,7 @@ public class TileTurtle extends TileComputerBase @Nonnull @Override - public ItemStack getStack( int slot ) + public ItemStack getItem( int slot ) { return slot >= 0 && slot < INVENTORY_SIZE ? inventory.get( slot ) : ItemStack.EMPTY; @@ -140,14 +139,14 @@ public class TileTurtle extends TileComputerBase @Nonnull @Override - public ItemStack removeStack( int slot, int count ) + public ItemStack removeItem( int slot, int count ) { if( count == 0 ) { return ItemStack.EMPTY; } - ItemStack stack = getStack( slot ); + ItemStack stack = getItem( slot ); if( stack.isEmpty() ) { return ItemStack.EMPTY; @@ -155,7 +154,7 @@ public class TileTurtle extends TileComputerBase if( stack.getCount() <= count ) { - setStack( slot, ItemStack.EMPTY ); + setItem( slot, ItemStack.EMPTY ); return stack; } @@ -166,15 +165,15 @@ public class TileTurtle extends TileComputerBase @Nonnull @Override - public ItemStack removeStack( int slot ) + public ItemStack removeItemNoUpdate( int slot ) { - ItemStack result = getStack( slot ); - setStack( slot, ItemStack.EMPTY ); + ItemStack result = getItem( slot ); + setItem( slot, ItemStack.EMPTY ); return result; } @Override - public void setStack( int i, @Nonnull ItemStack stack ) + public void setItem( int i, @Nonnull ItemStack stack ) { if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) @@ -185,66 +184,66 @@ public class TileTurtle extends TileComputerBase } @Override - public boolean canPlayerUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { return isUsable( player, false ); } private void onInventoryDefinitelyChanged() { - super.markDirty(); + super.setChanged(); inventoryChanged = true; } @Override - protected boolean canNameWithTag( PlayerEntity player ) + protected boolean canNameWithTag( Player player ) { return true; } @Nonnull @Override - public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit ) + public InteractionResult onActivate( Player player, InteractionHand hand, BlockHitResult hit ) { // Apply dye - ItemStack currentItem = player.getStackInHand( hand ); + ItemStack currentItem = player.getItemInHand( hand ); if( !currentItem.isEmpty() ) { if( currentItem.getItem() instanceof DyeItem ) { // Dye to change turtle colour - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { - DyeColor dye = ((DyeItem) currentItem.getItem()).getColor(); + DyeColor dye = ((DyeItem) currentItem.getItem()).getDyeColor(); if( brain.getDyeColour() != dye ) { brain.setDyeColour( dye ); if( !player.isCreative() ) { - currentItem.decrement( 1 ); + currentItem.shrink( 1 ); } } } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } else if( currentItem.getItem() == Items.WATER_BUCKET && brain.getColour() != -1 ) { // Water to remove turtle colour - if( !getWorld().isClient ) + if( !getLevel().isClientSide ) { if( brain.getColour() != -1 ) { brain.setColour( -1 ); if( !player.isCreative() ) { - player.setStackInHand( hand, + player.setItemInHand( hand, new ItemStack( Items.BUCKET ) ); - player.getInventory().markDirty(); + player.getInventory().setChanged(); } } } - return ActionResult.SUCCESS; + return InteractionResult.SUCCESS; } } @@ -284,9 +283,9 @@ public class TileTurtle extends TileComputerBase } inventoryChanged = false; - for( int n = 0; n < size(); n++ ) + for( int n = 0; n < getContainerSize(); n++ ) { - previousInventory.set( n, getStack( n ).copy() ); + previousInventory.set( n, getItem( n ).copy() ); } } } @@ -302,17 +301,17 @@ public class TileTurtle extends TileComputerBase @Nonnull @Override - public NbtCompound writeNbt( @Nonnull NbtCompound nbt ) + public CompoundTag save( @Nonnull CompoundTag nbt ) { // Write inventory - NbtList nbttaglist = new NbtList(); + ListTag nbttaglist = new ListTag(); for( int i = 0; i < INVENTORY_SIZE; i++ ) { if( !inventory.get( i ).isEmpty() ) { - NbtCompound tag = new NbtCompound(); + CompoundTag tag = new CompoundTag(); tag.putByte( "Slot", (byte) i ); - inventory.get( i ).writeNbt( tag ); + inventory.get( i ).save( tag ); nbttaglist.add( tag ); } } @@ -321,27 +320,27 @@ public class TileTurtle extends TileComputerBase // Write brain nbt = brain.writeToNBT( nbt ); - return super.writeNbt( nbt ); + return super.save( nbt ); } // IDirectionalTile @Override - public void readNbt( @Nonnull NbtCompound nbt ) + public void load( @Nonnull CompoundTag nbt ) { - super.readNbt( nbt ); + super.load( nbt ); // Read inventory - NbtList nbttaglist = nbt.getList( "Items", NBTUtil.TAG_COMPOUND ); + ListTag nbttaglist = nbt.getList( "Items", NBTUtil.TAG_COMPOUND ); inventory.clear(); previousInventory.clear(); for( int i = 0; i < nbttaglist.size(); i++ ) { - NbtCompound tag = nbttaglist.getCompound( i ); + CompoundTag tag = nbttaglist.getCompound( i ); int slot = tag.getByte( "Slot" ) & 0xff; - if( slot < size() ) + if( slot < getContainerSize() ) { - inventory.set( slot, ItemStack.fromNbt( tag ) ); + inventory.set( slot, ItemStack.of( tag ) ); previousInventory.set( slot, inventory.get( slot ).copy() ); } } @@ -361,30 +360,30 @@ public class TileTurtle extends TileComputerBase @Override public Direction getDirection() { - return getCachedState().get( BlockTurtle.FACING ); + return getBlockState().getValue( BlockTurtle.FACING ); } @Override protected ServerComputer createComputer( int instanceID, int id ) { - ServerComputer computer = new ServerComputer( getWorld(), id, label, instanceID, + ServerComputer computer = new ServerComputer( getLevel(), id, label, instanceID, getFamily(), ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight ); - computer.setPosition( getPos() ); + computer.setPosition( getBlockPos() ); computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) ); brain.setupComputer( computer ); return computer; } @Override - protected void writeDescription( @Nonnull NbtCompound nbt ) + protected void writeDescription( @Nonnull CompoundTag nbt ) { super.writeDescription( nbt ); brain.writeDescription( nbt ); } @Override - protected void readDescription( @Nonnull NbtCompound nbt ) + protected void readDescription( @Nonnull CompoundTag nbt ) { super.readDescription( nbt ); brain.readDescription( nbt ); @@ -402,7 +401,7 @@ public class TileTurtle extends TileComputerBase { dir = Direction.NORTH; } - world.setBlockState( pos, getCachedState().with( BlockTurtle.FACING, dir ) ); + level.setBlockAndUpdate( worldPosition, getBlockState().setValue( BlockTurtle.FACING, dir ) ); updateOutput(); updateInput(); onTileEntityChange(); @@ -410,7 +409,7 @@ public class TileTurtle extends TileComputerBase public void onTileEntityChange() { - super.markDirty(); + super.setChanged(); } private boolean hasPeripheralUpgradeOnSide( ComputerSide side ) @@ -433,7 +432,7 @@ public class TileTurtle extends TileComputerBase // IInventory @Override - protected double getInteractRange( PlayerEntity player ) + protected double getInteractRange( Player player ) { return 12.0; } @@ -462,7 +461,7 @@ public class TileTurtle extends TileComputerBase } @Override - public Identifier getOverlay() + public ResourceLocation getOverlay() { return brain.getOverlay(); } @@ -480,7 +479,7 @@ public class TileTurtle extends TileComputerBase } @Override - public Vec3d getRenderOffset( float f ) + public Vec3 getRenderOffset( float f ) { return brain.getRenderOffset( f ); } @@ -500,20 +499,20 @@ public class TileTurtle extends TileComputerBase void setOwningPlayer( GameProfile player ) { brain.setOwningPlayer( player ); - markDirty(); + setChanged(); } // Networking stuff @Override - public void markDirty() + public void setChanged() { - super.markDirty(); + super.setChanged(); if( !inventoryChanged ) { - for( int n = 0; n < size(); n++ ) + for( int n = 0; n < getContainerSize(); n++ ) { - if( !ItemStack.areEqual( getStack( n ), previousInventory.get( n ) ) ) + if( !ItemStack.matches( getItem( n ), previousInventory.get( n ) ) ) { inventoryChanged = true; break; @@ -523,7 +522,7 @@ public class TileTurtle extends TileComputerBase } @Override - public void clear() + public void clearContent() { boolean changed = false; for( int i = 0; i < INVENTORY_SIZE; i++ ) @@ -558,8 +557,8 @@ public class TileTurtle extends TileComputerBase @Nullable @Override - public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, - @Nonnull PlayerEntity player ) + public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, + @Nonnull Player player ) { return new ContainerTurtle( id, inventory, brain ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java index 2f22305e1..02f489575 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public enum InteractDirection { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java index 0364db549..b4bc5872b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public enum MoveDirection { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 391ea0f3e..3e4df5600 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -20,27 +20,26 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.util.*; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.Entity; -import net.minecraft.entity.MovementType; -import net.minecraft.fluid.FluidState; -import net.minecraft.inventory.Inventory; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.tag.FluidTags; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.FluidTags; +import net.minecraft.world.Container; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySelector; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.Level; +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.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import java.util.*; import java.util.concurrent.TimeUnit; @@ -62,17 +61,17 @@ public class TurtleBrain implements ITurtleAccess private final Queue commandQueue = new ArrayDeque<>(); private final Map upgrades = new EnumMap<>( TurtleSide.class ); private final Map peripherals = new EnumMap<>( TurtleSide.class ); - private final Map upgradeNBTData = new EnumMap<>( TurtleSide.class ); + private final Map upgradeNBTData = new EnumMap<>( TurtleSide.class ); TurtlePlayer cachedPlayer; private TileTurtle owner; - private final Inventory inventory = (InventoryDelegate) () -> owner; + private final Container inventory = (InventoryDelegate) () -> owner; private ComputerProxy proxy; private GameProfile owningPlayer; private int commandsIssued = 0; private int selectedSlot = 0; private int fuelLevel = 0; private int colourHex = -1; - private Identifier overlay = null; + private ResourceLocation overlay = null; private TurtleAnimation animation = TurtleAnimation.NONE; private int animationProgress = 0; private int lastAnimationProgress = 0; @@ -160,8 +159,8 @@ public class TurtleBrain implements ITurtleAccess public void update() { - World world = getWorld(); - if( !world.isClient ) + Level world = getWorld(); + if( !world.isClientSide ) { // Advance movement updateCommands(); @@ -187,31 +186,31 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public World getWorld() + public Level getWorld() { - return owner.getWorld(); + return owner.getLevel(); } @Nonnull @Override public BlockPos getPosition() { - return owner.getPos(); + return owner.getBlockPos(); } @Override - public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos ) + public boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ) { - if( world.isClient || getWorld().isClient ) + if( world.isClientSide || getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot teleport on the client" ); } // Cache info about the old turtle (so we don't access this after we delete ourselves) - World oldWorld = getWorld(); + Level oldWorld = getWorld(); TileTurtle oldOwner = owner; - BlockPos oldPos = owner.getPos(); - BlockState oldBlock = owner.getCachedState(); + BlockPos oldPos = owner.getBlockPos(); + BlockState oldBlock = owner.getBlockState(); if( oldWorld == world && oldPos.equals( pos ) ) { @@ -220,14 +219,14 @@ public class TurtleBrain implements ITurtleAccess } // Ensure the chunk is loaded - if( !world.isChunkLoaded( pos ) ) + if( !world.hasChunkAt( pos ) ) { return false; } // Ensure we're inside the world border if( !world.getWorldBorder() - .contains( pos ) ) + .isWithinBounds( pos ) ) { return false; } @@ -238,14 +237,14 @@ public class TurtleBrain implements ITurtleAccess // We only mark this as waterlogged when travelling into a source block. This prevents us from spreading // fluid by creating a new source when moving into a block, causing the next block to be almost full and // then moving into that. - .with( WATERLOGGED, existingFluid.isIn( FluidTags.WATER ) && existingFluid.isStill() ); + .setValue( WATERLOGGED, existingFluid.is( FluidTags.WATER ) && existingFluid.isSource() ); oldOwner.notifyMoveStart(); try { // Create a new turtle - if( world.setBlockState( pos, newState, 0 ) ) + if( world.setBlock( pos, newState, 0 ) ) { Block block = world.getBlockState( pos ) .getBlock(); @@ -255,7 +254,7 @@ public class TurtleBrain implements ITurtleAccess if( newTile instanceof TileTurtle newTurtle ) { // Copy the old turtle state into the new turtle - newTurtle.setWorld( world ); + newTurtle.setLevel( world ); newTurtle.transferStateFrom( oldOwner ); newTurtle.createServerComputer() .setWorld( world ); @@ -288,17 +287,17 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Vec3d getVisualPosition( float f ) + public Vec3 getVisualPosition( float f ) { - Vec3d offset = getRenderOffset( f ); - BlockPos pos = owner.getPos(); - return new Vec3d( pos.getX() + 0.5 + offset.x, pos.getY() + 0.5 + offset.y, pos.getZ() + 0.5 + offset.z ); + Vec3 offset = getRenderOffset( f ); + BlockPos pos = owner.getBlockPos(); + return new Vec3( pos.getX() + 0.5 + offset.x, pos.getY() + 0.5 + offset.y, pos.getZ() + 0.5 + offset.z ); } @Override public float getVisualYaw( float f ) { - float yaw = getDirection().asRotation(); + float yaw = getDirection().toYRot(); switch( animation ) { case TURN_LEFT: @@ -341,12 +340,12 @@ public class TurtleBrain implements ITurtleAccess @Override public void setSelectedSlot( int slot ) { - if( getWorld().isClient ) + if( getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot set the slot on the client" ); } - if( slot >= 0 && slot < owner.size() ) + if( slot >= 0 && slot < owner.getContainerSize() ) { selectedSlot = slot; owner.onTileEntityChange(); @@ -419,7 +418,7 @@ public class TurtleBrain implements ITurtleAccess @Override public boolean consumeFuel( int fuel ) { - if( getWorld().isClient ) + if( getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot consume fuel on the client" ); } @@ -441,7 +440,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void addFuel( int fuel ) { - if( getWorld().isClient ) + if( getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot add fuel on the client" ); } @@ -454,7 +453,7 @@ public class TurtleBrain implements ITurtleAccess @Override public MethodResult executeCommand( @Nonnull ITurtleCommand command ) { - if( getWorld().isClient ) + if( getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot run commands on the client" ); } @@ -474,7 +473,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void playAnimation( @Nonnull TurtleAnimation animation ) { - if( getWorld().isClient ) + if( getWorld().isClientSide ) { throw new UnsupportedOperationException( "Cannot play animations on the client" ); } @@ -528,7 +527,7 @@ public class TurtleBrain implements ITurtleAccess } // Notify clients and create peripherals - if( owner.getWorld() != null ) + if( owner.getLevel() != null ) { updatePeripherals( owner.createServerComputer() ); owner.updateBlock(); @@ -543,12 +542,12 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public NbtCompound getUpgradeNBTData( TurtleSide side ) + public CompoundTag getUpgradeNBTData( TurtleSide side ) { - NbtCompound nbt = upgradeNBTData.get( side ); + CompoundTag nbt = upgradeNBTData.get( side ); if( nbt == null ) { - upgradeNBTData.put( side, nbt = new NbtCompound() ); + upgradeNBTData.put( side, nbt = new CompoundTag() ); } return nbt; } @@ -561,7 +560,7 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Inventory getInventory() + public Container getInventory() { return inventory; } @@ -646,7 +645,7 @@ public class TurtleBrain implements ITurtleAccess { if( animation != TurtleAnimation.NONE ) { - World world = getWorld(); + Level world = getWorld(); if( ComputerCraft.turtlesCanPush ) { @@ -681,57 +680,57 @@ public class TurtleBrain implements ITurtleAccess float pushFrac = 1.0f - (float) (animationProgress + 1) / ANIM_DURATION; float push = Math.max( pushFrac + 0.0125f, 0.0f ); - if( moveDir.getOffsetX() < 0 ) + if( moveDir.getStepX() < 0 ) { - minX += moveDir.getOffsetX() * push; + minX += moveDir.getStepX() * push; } else { - maxX -= moveDir.getOffsetX() * push; + maxX -= moveDir.getStepX() * push; } - if( moveDir.getOffsetY() < 0 ) + if( moveDir.getStepY() < 0 ) { - minY += moveDir.getOffsetY() * push; + minY += moveDir.getStepY() * push; } else { - maxY -= moveDir.getOffsetY() * push; + maxY -= moveDir.getStepY() * push; } - if( moveDir.getOffsetZ() < 0 ) + if( moveDir.getStepZ() < 0 ) { - minZ += moveDir.getOffsetZ() * push; + minZ += moveDir.getStepZ() * push; } else { - maxZ -= moveDir.getOffsetZ() * push; + maxZ -= moveDir.getStepZ() * push; } - Box aabb = new Box( minX, minY, minZ, maxX, maxY, maxZ ); - List list = world.getEntitiesByClass( Entity.class, aabb, EntityPredicates.EXCEPT_SPECTATOR ); + AABB aabb = new AABB( minX, minY, minZ, maxX, maxY, maxZ ); + List list = world.getEntitiesOfClass( Entity.class, aabb, EntitySelector.NO_SPECTATORS ); if( !list.isEmpty() ) { double pushStep = 1.0f / ANIM_DURATION; - double pushStepX = moveDir.getOffsetX() * pushStep; - double pushStepY = moveDir.getOffsetY() * pushStep; - double pushStepZ = moveDir.getOffsetZ() * pushStep; + double pushStepX = moveDir.getStepX() * pushStep; + double pushStepY = moveDir.getStepY() * pushStep; + double pushStepZ = moveDir.getStepZ() * pushStep; for( Entity entity : list ) { - entity.move( MovementType.PISTON, new Vec3d( pushStepX, pushStepY, pushStepZ ) ); + entity.move( MoverType.PISTON, new Vec3( pushStepX, pushStepY, pushStepZ ) ); } } } } // Advance valentines day easter egg - if( world.isClient && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4 ) + if( world.isClientSide && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4 ) { // Spawn love pfx if valentines day Holiday currentHoliday = HolidayUtil.getCurrentHoliday(); if( currentHoliday == Holiday.VALENTINES ) { - Vec3d position = getVisualPosition( 1.0f ); + Vec3 position = getVisualPosition( 1.0f ); if( position != null ) { double x = position.x + world.random.nextGaussian() * 0.1; @@ -759,7 +758,7 @@ public class TurtleBrain implements ITurtleAccess } } - public Vec3d getRenderOffset( float f ) + public Vec3 getRenderOffset( float f ) { switch( animation ) { @@ -787,9 +786,9 @@ public class TurtleBrain implements ITurtleAccess } double distance = -1.0 + getAnimationFraction( f ); - return new Vec3d( distance * dir.getOffsetX(), distance * dir.getOffsetY(), distance * dir.getOffsetZ() ); + return new Vec3( distance * dir.getStepX(), distance * dir.getStepY(), distance * dir.getStepZ() ); default: - return Vec3d.ZERO; + return Vec3.ZERO; } } @@ -800,7 +799,7 @@ public class TurtleBrain implements ITurtleAccess return previous + (next - previous) * f; } - public void readFromNBT( NbtCompound nbt ) + public void readFromNBT( CompoundTag nbt ) { readCommon( nbt ); @@ -810,7 +809,7 @@ public class TurtleBrain implements ITurtleAccess // Read owner if( nbt.contains( "Owner", NBTUtil.TAG_COMPOUND ) ) { - NbtCompound owner = nbt.getCompound( "Owner" ); + CompoundTag owner = nbt.getCompound( "Owner" ); owningPlayer = new GameProfile( new UUID( owner.getLong( "UpperId" ), owner.getLong( "LowerId" ) ), owner.getString( "Name" ) ); } else @@ -824,12 +823,12 @@ public class TurtleBrain implements ITurtleAccess * * @param nbt The tag to read from */ - private void readCommon( NbtCompound nbt ) + private void readCommon( CompoundTag nbt ) { // Read fields colourHex = nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : -1; fuelLevel = nbt.contains( NBT_FUEL ) ? nbt.getInt( NBT_FUEL ) : 0; - overlay = nbt.contains( NBT_OVERLAY ) ? new Identifier( nbt.getString( NBT_OVERLAY ) ) : null; + overlay = nbt.contains( NBT_OVERLAY ) ? new ResourceLocation( nbt.getString( NBT_OVERLAY ) ) : null; // Read upgrades setUpgrade( TurtleSide.LEFT, nbt.contains( NBT_LEFT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_LEFT_UPGRADE ) ) : null ); @@ -851,7 +850,7 @@ public class TurtleBrain implements ITurtleAccess } } - public NbtCompound writeToNBT( NbtCompound nbt ) + public CompoundTag writeToNBT( CompoundTag nbt ) { writeCommon( nbt ); @@ -861,7 +860,7 @@ public class TurtleBrain implements ITurtleAccess // Write owner if( owningPlayer != null ) { - NbtCompound owner = new NbtCompound(); + CompoundTag owner = new CompoundTag(); nbt.put( "Owner", owner ); owner.putLong( "UpperId", owningPlayer.getId() @@ -874,7 +873,7 @@ public class TurtleBrain implements ITurtleAccess return nbt; } - private void writeCommon( NbtCompound nbt ) + private void writeCommon( CompoundTag nbt ) { nbt.putInt( NBT_FUEL, fuelLevel ); if( colourHex != -1 ) @@ -917,7 +916,7 @@ public class TurtleBrain implements ITurtleAccess .toString() : null; } - public void readDescription( NbtCompound nbt ) + public void readDescription( CompoundTag nbt ) { readCommon( nbt ); @@ -931,18 +930,18 @@ public class TurtleBrain implements ITurtleAccess } } - public void writeDescription( NbtCompound nbt ) + public void writeDescription( CompoundTag nbt ) { writeCommon( nbt ); nbt.putInt( "Animation", animation.ordinal() ); } - public Identifier getOverlay() + public ResourceLocation getOverlay() { return overlay; } - public void setOverlay( Identifier overlay ) + public void setOverlay( ResourceLocation overlay ) { if( !Objects.equal( this.overlay, overlay ) ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index b362f5d8b..1b6339af2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -9,15 +9,14 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; import java.util.List; public class TurtleCompareCommand implements ITurtleCommand @@ -38,15 +37,15 @@ public class TurtleCompareCommand implements ITurtleCommand // Get currently selected stack ItemStack selectedStack = turtle.getInventory() - .getStack( turtle.getSelectedSlot() ); + .getItem( turtle.getSelectedSlot() ); // Get stack representing thing in front - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); - BlockPos newPosition = oldPosition.offset( direction ); + BlockPos newPosition = oldPosition.relative( direction ); ItemStack lookAtStack = ItemStack.EMPTY; - if( !world.isAir( newPosition ) ) + if( !world.isEmptyBlock( newPosition ) ) { BlockState lookAtState = world.getBlockState( newPosition ); Block lookAtBlock = lookAtState.getBlock(); @@ -56,7 +55,7 @@ public class TurtleCompareCommand implements ITurtleCommand // (try 5 times to try and beat random number generators) for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ ) { - List drops = Block.getDroppedStacks( lookAtState, (ServerWorld) world, newPosition, world.getBlockEntity( newPosition ) ); + List drops = Block.getDrops( lookAtState, (ServerLevel) world, newPosition, world.getBlockEntity( newPosition ) ); if( !drops.isEmpty() ) { for( ItemStack drop : drops ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index e5a638828..ac4ed2f75 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -10,9 +10,8 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.InventoryUtil; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; public class TurtleCompareToCommand implements ITurtleCommand { @@ -28,9 +27,9 @@ public class TurtleCompareToCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { ItemStack selectedStack = turtle.getInventory() - .getStack( turtle.getSelectedSlot() ); + .getItem( turtle.getSelectedSlot() ); ItemStack stack = turtle.getInventory() - .getStack( slot ); + .getItem( slot ); if( InventoryUtil.areItemsStackable( selectedStack, stack ) ) { return TurtleCommandResult.success(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index 8b6d63e17..83fa33645 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -13,9 +13,8 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.turtle.upgrades.TurtleInventoryCrafting; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; import java.util.List; public class TurtleCraftCommand implements ITurtleCommand diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index cbc97f931..ce9a88690 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -10,11 +10,10 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; public class TurtleDetectCommand implements ITurtleCommand { @@ -33,10 +32,10 @@ public class TurtleDetectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); - BlockPos newPosition = oldPosition.offset( direction ); + BlockPos newPosition = oldPosition.relative( direction ); - return !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isAir( newPosition ) ? TurtleCommandResult.success() : TurtleCommandResult.failure(); + return !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isEmptyBlock( newPosition ) ? TurtleCommandResult.success() : TurtleCommandResult.failure(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index bd53b9c66..02b5a9f5f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -15,13 +15,12 @@ import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; public class TurtleDropCommand implements ITurtleCommand { @@ -56,12 +55,12 @@ public class TurtleDropCommand implements ITurtleCommand } // Get inventory for thing in front - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); - BlockPos newPosition = oldPosition.offset( direction ); + BlockPos newPosition = oldPosition.relative( direction ); Direction side = direction.getOpposite(); - Inventory inventory = InventoryUtil.getInventory( world, newPosition, side ); + Container inventory = InventoryUtil.getInventory( world, newPosition, side ); // Fire the event, restoring the inventory and exiting if it is cancelled. TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); @@ -97,7 +96,7 @@ public class TurtleDropCommand implements ITurtleCommand { // Drop the item into the world WorldUtil.dropItemStack( stack, world, oldPosition, direction ); - world.syncGlobalEvent( 1000, newPosition, 0 ); + world.globalLevelEvent( 1000, newPosition, 0 ); turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index d289efc40..865f6dae6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -14,11 +14,10 @@ import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; public class TurtleEquipCommand implements ITurtleCommand { @@ -36,8 +35,8 @@ public class TurtleEquipCommand implements ITurtleCommand // Determine the upgrade to equipLeft ITurtleUpgrade newUpgrade; ItemStack newUpgradeStack; - Inventory inventory = turtle.getInventory(); - ItemStack selectedStack = inventory.getStack( turtle.getSelectedSlot() ); + Container inventory = turtle.getInventory(); + ItemStack selectedStack = inventory.getItem( turtle.getSelectedSlot() ); if( !selectedStack.isEmpty() ) { newUpgradeStack = selectedStack.copy(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index 5e781b23a..bdb4e25e0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -12,13 +12,12 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.peripheral.generic.data.BlockData; -import net.minecraft.block.BlockState; -import net.minecraft.state.property.Property; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import java.util.HashMap; import java.util.Map; @@ -39,9 +38,9 @@ public class TurtleInspectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); - BlockPos newPosition = oldPosition.offset( direction ); + BlockPos newPosition = oldPosition.relative( direction ); BlockState state = world.getBlockState( newPosition ); if( state.isAir() ) @@ -72,6 +71,6 @@ public class TurtleInspectCommand implements ITurtleCommand { return value; } - return property.name( value ); + return property.getName( value ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 60e58e7dd..bae8eae89 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -15,21 +15,20 @@ import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; import java.util.List; public class TurtleMoveCommand implements ITurtleCommand { - private static final Box EMPTY_BOX = new Box( 0, 0, 0, 0, 0, 0 ); + private static final AABB EMPTY_BOX = new AABB( 0, 0, 0, 0, 0, 0 ); private final MoveDirection direction; public TurtleMoveCommand( MoveDirection direction ) @@ -45,9 +44,9 @@ public class TurtleMoveCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if we can move - World oldWorld = turtle.getWorld(); + Level oldWorld = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); - BlockPos newPosition = oldPosition.offset( direction ); + BlockPos newPosition = oldPosition.relative( direction ); TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); TurtleCommandResult canEnterResult = canEnter( turtlePlayer, oldWorld, newPosition ); @@ -58,7 +57,7 @@ public class TurtleMoveCommand implements ITurtleCommand // Check existing block is air or replaceable BlockState state = oldWorld.getBlockState( newPosition ); - if( !oldWorld.isAir( newPosition ) && !WorldUtil.isLiquidBlock( oldWorld, newPosition ) && !state.getMaterial() + if( !oldWorld.isEmptyBlock( newPosition ) && !WorldUtil.isLiquidBlock( oldWorld, newPosition ) && !state.getMaterial() .isReplaceable() ) { return TurtleCommandResult.failure( "Movement obstructed" ); @@ -66,9 +65,9 @@ public class TurtleMoveCommand implements ITurtleCommand // Check there isn't anything in the way VoxelShape collision = state.getCollisionShape( oldWorld, oldPosition ) - .offset( newPosition.getX(), newPosition.getY(), newPosition.getZ() ); + .move( newPosition.getX(), newPosition.getY(), newPosition.getZ() ); - if( !oldWorld.intersectsEntities( null, collision ) ) + if( !oldWorld.isUnobstructed( null, collision ) ) { if( !ComputerCraft.turtlesCanPush || this.direction == MoveDirection.UP || this.direction == MoveDirection.DOWN ) { @@ -76,12 +75,12 @@ public class TurtleMoveCommand implements ITurtleCommand } // Check there is space for all the pushable entities to be pushed - List list = oldWorld.getEntitiesByClass( Entity.class, getBox( collision ), x -> x != null && x.isAlive() && x.inanimate ); + List list = oldWorld.getEntitiesOfClass( Entity.class, getBox( collision ), x -> x != null && x.isAlive() && x.blocksBuilding ); for( Entity entity : list ) { - Box pushedBB = entity.getBoundingBox() - .offset( direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ() ); - if( !oldWorld.intersectsEntities( null, VoxelShapes.cuboid( pushedBB ) ) ) + AABB pushedBB = entity.getBoundingBox() + .move( direction.getStepX(), direction.getStepY(), direction.getStepZ() ); + if( !oldWorld.isUnobstructed( null, Shapes.create( pushedBB ) ) ) { return TurtleCommandResult.failure( "Movement obstructed" ); } @@ -129,13 +128,13 @@ public class TurtleMoveCommand implements ITurtleCommand return TurtleCommandResult.success(); } - private static TurtleCommandResult canEnter( TurtlePlayer turtlePlayer, World world, BlockPos position ) + private static TurtleCommandResult canEnter( TurtlePlayer turtlePlayer, Level world, BlockPos position ) { - if( world.isOutOfHeightLimit( position ) ) + if( world.isOutsideBuildHeight( position ) ) { return TurtleCommandResult.failure( position.getY() < 0 ? "Too low to move" : "Too high to move" ); } - if( !world.isInBuildLimit( position ) ) + if( !world.isInWorldBounds( position ) ) { return TurtleCommandResult.failure( "Cannot leave the world" ); } @@ -146,12 +145,12 @@ public class TurtleMoveCommand implements ITurtleCommand return TurtleCommandResult.failure( "Cannot enter protected area" ); } - if( !world.isChunkLoaded( position ) ) + if( !world.hasChunkAt( position ) ) { return TurtleCommandResult.failure( "Cannot leave loaded world" ); } if( !world.getWorldBorder() - .contains( position ) ) + .isWithinBounds( position ) ) { return TurtleCommandResult.failure( "Cannot pass the world border" ); } @@ -159,8 +158,8 @@ public class TurtleMoveCommand implements ITurtleCommand return TurtleCommandResult.success(); } - private static Box getBox( VoxelShape shape ) + private static AABB getBox( VoxelShape shape ) { - return shape.isEmpty() ? EMPTY_BOX : shape.getBoundingBox(); + return shape.isEmpty() ? EMPTY_BOX : shape.bounds(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index ea6c02a5a..f38ee775b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -18,21 +18,31 @@ import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DropConsumer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.item.*; -import net.minecraft.text.LiteralText; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.TypedActionResult; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.BoatItem; +import net.minecraft.world.item.BottleItem; +import net.minecraft.world.item.BucketItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.SignItem; +import net.minecraft.world.item.WaterLilyBlockItem; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -53,7 +63,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { // Create a fake player, and orient it appropriately BlockPos playerPosition = turtle.getPosition() - .offset( direction ); + .relative( direction ); TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction ); return deploy( stack, turtle, turtlePlayer, direction, extraArguments, outErrorMessage ); @@ -65,7 +75,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { // Get thing to place ItemStack stack = turtle.getInventory() - .getStack( turtle.getSelectedSlot() ); + .getItem( turtle.getSelectedSlot() ); if( stack.isEmpty() ) { return TurtleCommandResult.failure( "No items to place" ); @@ -74,11 +84,11 @@ public class TurtlePlaceCommand implements ITurtleCommand // Remember old block Direction direction = this.direction.toWorldDir( turtle ); BlockPos coordinates = turtle.getPosition() - .offset( direction ); + .relative( direction ); // Create a fake player, and orient it appropriately BlockPos playerPosition = turtle.getPosition() - .offset( direction ); + .relative( direction ); TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction ); TurtleBlockEvent.Place place = new TurtleBlockEvent.Place( turtle, turtlePlayer, turtle.getWorld(), coordinates, stack ); @@ -94,9 +104,9 @@ public class TurtlePlaceCommand implements ITurtleCommand { // Put the remaining items back turtle.getInventory() - .setStack( turtle.getSelectedSlot(), remainder ); + .setItem( turtle.getSelectedSlot(), remainder ); turtle.getInventory() - .markDirty(); + .setChanged(); // Animate and return success turtle.playAnimation( TurtleAnimation.WAIT ); @@ -138,7 +148,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Deploy on the block immediately in front BlockPos position = turtle.getPosition(); - BlockPos newPosition = position.offset( direction ); + BlockPos newPosition = position.relative( direction ); remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition, direction.getOpposite(), extraArguments, true, outErrorMessage ); if( remainder != stack ) { @@ -149,7 +159,7 @@ public class TurtlePlaceCommand implements ITurtleCommand remainder = deployOnBlock( stack, turtle, turtlePlayer, - newPosition.offset( direction ), + newPosition.relative( direction ), direction.getOpposite(), extraArguments, false, @@ -162,7 +172,7 @@ public class TurtlePlaceCommand implements ITurtleCommand if( direction.getAxis() != Direction.Axis.Y ) { // Deploy down on the block in front - remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.down(), Direction.UP, extraArguments, false, outErrorMessage ); + remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.below(), Direction.UP, extraArguments, false, outErrorMessage ); if( remainder != stack ) { return remainder; @@ -186,32 +196,32 @@ public class TurtlePlaceCommand implements ITurtleCommand if( turtle.getPosition() .equals( position ) ) { - posX += 0.48 * direction.getOffsetX(); - posY += 0.48 * direction.getOffsetY(); - posZ += 0.48 * direction.getOffsetZ(); + posX += 0.48 * direction.getStepX(); + posY += 0.48 * direction.getStepY(); + posZ += 0.48 * direction.getStepZ(); } if( direction.getAxis() != Direction.Axis.Y ) { - turtlePlayer.setYaw( direction.asRotation() ); - turtlePlayer.setPitch( 0.0f ); + turtlePlayer.setYRot( direction.toYRot() ); + turtlePlayer.setXRot( 0.0f ); } else { - turtlePlayer.setYaw( turtle.getDirection() - .asRotation() ); - turtlePlayer.setPitch( DirectionUtil.toPitchAngle( direction ) ); + turtlePlayer.setYRot( turtle.getDirection() + .toYRot() ); + turtlePlayer.setXRot( DirectionUtil.toPitchAngle( direction ) ); } - turtlePlayer.setPos( posX, posY, posZ ); - turtlePlayer.prevX = posX; - turtlePlayer.prevY = posY; - turtlePlayer.prevZ = posZ; - turtlePlayer.prevPitch = turtlePlayer.getPitch(); - turtlePlayer.prevYaw = turtlePlayer.getYaw(); + turtlePlayer.setPosRaw( posX, posY, posZ ); + turtlePlayer.xo = posX; + turtlePlayer.yo = posY; + turtlePlayer.zo = posZ; + turtlePlayer.xRotO = turtlePlayer.getXRot(); + turtlePlayer.yRotO = turtlePlayer.getYRot(); - turtlePlayer.headYaw = turtlePlayer.getYaw(); - turtlePlayer.prevHeadYaw = turtlePlayer.headYaw; + turtlePlayer.yHeadRot = turtlePlayer.getYRot(); + turtlePlayer.yHeadRotO = turtlePlayer.yHeadRot; } @Nonnull @@ -219,11 +229,11 @@ public class TurtlePlaceCommand implements ITurtleCommand Object[] extraArguments, String[] outErrorMessage ) { // See if there is an entity present - final World world = turtle.getWorld(); + final Level world = turtle.getWorld(); final BlockPos position = turtle.getPosition(); - Vec3d turtlePos = turtlePlayer.getPos(); - Vec3d rayDir = turtlePlayer.getRotationVec( 1.0f ); - Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); + Vec3 turtlePos = turtlePlayer.position(); + Vec3 rayDir = turtlePlayer.getViewVector( 1.0f ); + Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit == null ) { return stack; @@ -235,27 +245,27 @@ public class TurtlePlaceCommand implements ITurtleCommand // Start claiming entity drops Entity hitEntity = hit.getKey(); - Vec3d hitPos = hit.getValue(); + Vec3 hitPos = hit.getValue(); DropConsumer.set( hitEntity, drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ) ); // Place on the entity boolean placed = false; - ActionResult cancelResult = hitEntity.interactAt( turtlePlayer, hitPos, Hand.MAIN_HAND ); + InteractionResult cancelResult = hitEntity.interactAt( turtlePlayer, hitPos, InteractionHand.MAIN_HAND ); - if( cancelResult != null && cancelResult.isAccepted() ) + if( cancelResult != null && cancelResult.consumesAction() ) { placed = true; } else { - cancelResult = hitEntity.interact( turtlePlayer, Hand.MAIN_HAND ); - if( cancelResult != null && cancelResult.isAccepted() ) + cancelResult = hitEntity.interact( turtlePlayer, InteractionHand.MAIN_HAND ); + if( cancelResult != null && cancelResult.consumesAction() ) { placed = true; } else if( hitEntity instanceof LivingEntity ) { - placed = stackCopy.useOnEntity( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND ).isAccepted(); + placed = stackCopy.interactLivingEntity( turtlePlayer, (LivingEntity) hitEntity, InteractionHand.MAIN_HAND ).consumesAction(); if( placed ) turtlePlayer.loadInventory( stackCopy ); } } @@ -273,7 +283,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Put everything we collected into the turtles inventory, then return ItemStack remainder = turtlePlayer.unloadInventory( turtle ); - if( !placed && ItemStack.areEqual( stack, remainder ) ) + if( !placed && ItemStack.matches( stack, remainder ) ) { return stack; } @@ -293,26 +303,26 @@ public class TurtlePlaceCommand implements ITurtleCommand { // Re-orient the fake player Direction playerDir = side.getOpposite(); - BlockPos playerPosition = position.offset( side ); + BlockPos playerPosition = position.relative( side ); orientPlayer( turtle, turtlePlayer, playerPosition, playerDir ); ItemStack stackCopy = stack.copy(); turtlePlayer.loadInventory( stackCopy ); // Calculate where the turtle would hit the block - float hitX = 0.5f + side.getOffsetX() * 0.5f; - float hitY = 0.5f + side.getOffsetY() * 0.5f; - float hitZ = 0.5f + side.getOffsetZ() * 0.5f; + float hitX = 0.5f + side.getStepX() * 0.5f; + float hitY = 0.5f + side.getStepY() * 0.5f; + float hitZ = 0.5f + side.getStepZ() * 0.5f; if( Math.abs( hitY - 0.5f ) < 0.01f ) { hitY = 0.45f; } // Check if there's something suitable to place onto - BlockHitResult hit = new BlockHitResult( new Vec3d( hitX, hitY, hitZ ), side, position, false ); - ItemUsageContext context = new ItemUsageContext( turtlePlayer, Hand.MAIN_HAND, hit ); - ItemPlacementContext placementContext = new ItemPlacementContext( context ); - if( !canDeployOnBlock( new ItemPlacementContext( context ), turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) + BlockHitResult hit = new BlockHitResult( new Vec3( hitX, hitY, hitZ ), side, position, false ); + UseOnContext context = new UseOnContext( turtlePlayer, InteractionHand.MAIN_HAND, hit ); + BlockPlaceContext placementContext = new BlockPlaceContext( context ); + if( !canDeployOnBlock( new BlockPlaceContext( context ), turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) { return stack; } @@ -325,20 +335,20 @@ public class TurtlePlaceCommand implements ITurtleCommand BlockEntity existingTile = turtle.getWorld() .getBlockEntity( position ); - if( stackCopy.useOnBlock( context ).isAccepted() ) + if( stackCopy.useOn( context ).consumesAction() ) { placed = true; turtlePlayer.loadInventory( stackCopy ); } - if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem) ) + if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof WaterLilyBlockItem || item instanceof BottleItem) ) { - TypedActionResult result = stackCopy.use( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND ); + InteractionResultHolder result = stackCopy.use( turtle.getWorld(), turtlePlayer, InteractionHand.MAIN_HAND ); if( result.getResult() - .isAccepted() && !ItemStack.areEqual( stack, result.getValue() ) ) + .consumesAction() && !ItemStack.matches( stack, result.getObject() ) ) { placed = true; - turtlePlayer.loadInventory( result.getValue() ); + turtlePlayer.loadInventory( result.getObject() ); } } @@ -347,11 +357,11 @@ public class TurtlePlaceCommand implements ITurtleCommand { if( extraArguments != null && extraArguments.length >= 1 && extraArguments[0] instanceof String ) { - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockEntity tile = world.getBlockEntity( position ); if( tile == null || tile == existingTile ) { - tile = world.getBlockEntity( position.offset( side ) ); + tile = world.getBlockEntity( position.relative( side ) ); } if( tile instanceof SignBlockEntity ) { @@ -365,27 +375,27 @@ public class TurtlePlaceCommand implements ITurtleCommand { if( split[i - firstLine].length() > 15 ) { - signTile.setTextOnRow( i, new LiteralText( split[i - firstLine].substring( 0, 15 ) ) ); + signTile.setMessage( i, new TextComponent( split[i - firstLine].substring( 0, 15 ) ) ); } else { - signTile.setTextOnRow( i, new LiteralText( split[i - firstLine] ) ); + signTile.setMessage( i, new TextComponent( split[i - firstLine] ) ); } } else { - signTile.setTextOnRow( i, new LiteralText( "" ) ); + signTile.setMessage( i, new TextComponent( "" ) ); } } - signTile.markDirty(); - world.updateListeners( tile.getPos(), tile.getCachedState(), tile.getCachedState(), 3 ); + signTile.setChanged(); + world.sendBlockUpdated( tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), 3 ); } } } // Put everything we collected into the turtles inventory, then return ItemStack remainder = turtlePlayer.unloadInventory( turtle ); - if( !placed && ItemStack.areEqual( stack, remainder ) ) + if( !placed && ItemStack.matches( stack, remainder ) ) { return stack; } @@ -399,11 +409,11 @@ public class TurtlePlaceCommand implements ITurtleCommand } } - private static boolean canDeployOnBlock( @Nonnull ItemPlacementContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, + private static boolean canDeployOnBlock( @Nonnull BlockPlaceContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage ) { - World world = turtle.getWorld(); - if( !world.isInBuildLimit( position ) || world.isAir( position ) || (context.getStack() + Level world = turtle.getWorld(); + if( !world.isInWorldBounds( position ) || world.isEmptyBlock( position ) || (context.getItemInHand() .getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) { @@ -412,7 +422,7 @@ public class TurtlePlaceCommand implements ITurtleCommand BlockState state = world.getBlockState( position ); - boolean replaceable = state.canReplace( context ); + boolean replaceable = state.canBeReplaced( context ); if( !allowReplaceable && replaceable ) { return false; @@ -422,7 +432,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { // Check spawn protection boolean editable = replaceable ? TurtlePermissions.isBlockEditable( world, position, player ) : TurtlePermissions.isBlockEditable( world, - position.offset( + position.relative( side ), player ); if( !editable ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 896ade7a6..73b6a6113 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -14,24 +14,23 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityDimensions; -import net.minecraft.entity.EntityPose; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.passive.HorseBaseEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +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.Container; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.animal.horse.AbstractHorse; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; import java.util.OptionalInt; import java.util.UUID; @@ -41,18 +40,18 @@ public final class TurtlePlayer extends FakePlayer private static final GameProfile DEFAULT_PROFILE = new GameProfile( UUID.fromString( "0d0c4ca0-4ff1-11e4-916c-0800200c9a66" ), "[ComputerCraft]" ); // TODO [M3R1-01] Fix Turtle not giving player achievement for actions - private TurtlePlayer( ServerWorld world, GameProfile name ) + private TurtlePlayer( ServerLevel world, GameProfile name ) { super( world, name ); } private static TurtlePlayer create( ITurtleAccess turtle ) { - ServerWorld world = (ServerWorld) turtle.getWorld(); + ServerLevel world = (ServerLevel) turtle.getWorld(); GameProfile profile = turtle.getOwningPlayer(); TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); - player.networkHandler = new FakeNetHandler( player ); + player.connection = new FakeNetHandler( player ); player.setState( turtle ); if( profile != null && profile.getId() != null ) @@ -60,8 +59,8 @@ public final class TurtlePlayer extends FakePlayer // Constructing a player overrides the "active player" variable in advancements. As fake players cannot // get advancements, this prevents a normal player who has placed a turtle from getting advancements. // We try to locate the "actual" player and restore them. - ServerPlayerEntity actualPlayer = world.getServer().getPlayerManager().getPlayer( player.getUuid() ); - if( actualPlayer != null ) player.getAdvancementTracker().setOwner( actualPlayer ); + ServerPlayer actualPlayer = world.getServer().getPlayerList().getPlayer( player.getUUID() ); + if( actualPlayer != null ) player.getAdvancements().setPlayer( actualPlayer ); } return player; @@ -74,20 +73,20 @@ public final class TurtlePlayer extends FakePlayer private void setState( ITurtleAccess turtle ) { - if( currentScreenHandler != playerScreenHandler ) + if( containerMenu != inventoryMenu ) { - ComputerCraft.log.warn( "Turtle has open container ({})", currentScreenHandler ); - closeHandledScreen(); + ComputerCraft.log.warn( "Turtle has open container ({})", containerMenu ); + closeContainer(); } BlockPos position = turtle.getPosition(); - setPos( position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5 ); + setPosRaw( position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5 ); - setYaw( turtle.getDirection() - .asRotation() ); - setPitch( 0.0f ); + setYRot( turtle.getDirection() + .toYRot() ); + setXRot( 0.0f ); - getInventory().clear(); + getInventory().clearContent(); } public static TurtlePlayer get( ITurtleAccess access ) @@ -96,7 +95,7 @@ public final class TurtlePlayer extends FakePlayer TurtleBrain brain = (TurtleBrain) access; TurtlePlayer player = brain.cachedPlayer; - if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getEntityWorld() != access.getWorld() ) + if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getWorld() ) { player = brain.cachedPlayer = create( brain ); } @@ -111,23 +110,23 @@ public final class TurtlePlayer extends FakePlayer public void loadInventory( @Nonnull ItemStack currentStack ) { // Load up the fake inventory - getInventory().selectedSlot = 0; - getInventory().setStack( 0, currentStack ); + getInventory().selected = 0; + getInventory().setItem( 0, currentStack ); } public ItemStack unloadInventory( ITurtleAccess turtle ) { // Get the item we placed with - ItemStack results = getInventory().getStack( 0 ); - getInventory().setStack( 0, ItemStack.EMPTY ); + ItemStack results = getInventory().getItem( 0 ); + getInventory().setItem( 0, ItemStack.EMPTY ); // Store (or drop) anything else we found BlockPos dropPosition = turtle.getPosition(); Direction dropDirection = turtle.getDirection() .getOpposite(); - for( int i = 0; i < getInventory().size(); i++ ) + for( int i = 0; i < getInventory().getContainerSize(); i++ ) { - ItemStack stack = getInventory().getStack( i ); + ItemStack stack = getInventory().getItem( i ); if( !stack.isEmpty() ) { ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); @@ -135,10 +134,10 @@ public final class TurtlePlayer extends FakePlayer { WorldUtil.dropItemStack( remainder, turtle.getWorld(), dropPosition, dropDirection ); } - getInventory().setStack( i, ItemStack.EMPTY ); + getInventory().setItem( i, ItemStack.EMPTY ); } } - getInventory().markDirty(); + getInventory().setChanged(); return results; } @@ -150,30 +149,30 @@ public final class TurtlePlayer extends FakePlayer } @Override - public float getEyeHeight( @Nonnull EntityPose pose ) + public float getEyeHeight( @Nonnull Pose pose ) { return 0; } @Override - public Vec3d getPos() + public Vec3 position() { - return new Vec3d( getX(), getY(), getZ() ); + return new Vec3( getX(), getY(), getZ() ); } @Override - public float getActiveEyeHeight( @Nonnull EntityPose pose, @Nonnull EntityDimensions size ) + public float getStandingEyeHeight( @Nonnull Pose pose, @Nonnull EntityDimensions size ) { return 0; } @Override - public void enterCombat() + public void onEnterCombat() { } @Override - public void endCombat() + public void onLeaveCombat() { } @@ -189,30 +188,30 @@ public final class TurtlePlayer extends FakePlayer } @Override - public void openEditSignScreen( @Nonnull SignBlockEntity signTile ) + public void openTextEdit( @Nonnull SignBlockEntity signTile ) { } //region Code which depends on the connection @Nonnull @Override - public OptionalInt openHandledScreen( @Nullable NamedScreenHandlerFactory prover ) + public OptionalInt openMenu( @Nullable MenuProvider prover ) { return OptionalInt.empty(); } @Override - public void openHorseInventory( @Nonnull HorseBaseEntity horse, @Nonnull Inventory inventory ) + public void openHorseInventory( @Nonnull AbstractHorse horse, @Nonnull Container inventory ) { } @Override - public void closeHandledScreen() + public void closeContainer() { } @Override - protected void onStatusEffectRemoved( @Nonnull StatusEffectInstance effect ) + protected void onEffectRemoved( @Nonnull MobEffectInstance effect ) { } //endregion diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index d97e28ad8..be8a3585c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -12,9 +12,8 @@ import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; public class TurtleRefuelCommand implements ITurtleCommand { @@ -31,7 +30,7 @@ public class TurtleRefuelCommand implements ITurtleCommand { int slot = turtle.getSelectedSlot(); ItemStack stack = turtle.getInventory() - .getStack( slot ); + .getItem( slot ); if( stack.isEmpty() ) { return TurtleCommandResult.failure( "No items to combust" ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index f8aa7ffe8..74897fbe6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -14,16 +14,15 @@ import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; -import net.minecraft.entity.ItemEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.Container; +import net.minecraft.world.entity.EntitySelector; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; import java.util.List; public class TurtleSuckCommand implements ITurtleCommand @@ -52,12 +51,12 @@ public class TurtleSuckCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Get inventory for thing in front - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos turtlePosition = turtle.getPosition(); - BlockPos blockPosition = turtlePosition.offset( direction ); + BlockPos blockPosition = turtlePosition.relative( direction ); Direction side = direction.getOpposite(); - Inventory inventory = InventoryUtil.getInventory( world, blockPosition, side ); + Container inventory = InventoryUtil.getInventory( world, blockPosition, side ); // Fire the event, exiting if it is cancelled. TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); @@ -98,13 +97,13 @@ public class TurtleSuckCommand implements ITurtleCommand else { // Suck up loose items off the ground - Box aabb = new Box( blockPosition.getX(), + AABB aabb = new AABB( blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockPosition.getX() + 1.0, blockPosition.getY() + 1.0, blockPosition.getZ() + 1.0 ); - List list = world.getEntitiesByClass( ItemEntity.class, aabb, EntityPredicates.VALID_ENTITY ); + List list = world.getEntitiesOfClass( ItemEntity.class, aabb, EntitySelector.ENTITY_STILL_ALIVE ); if( list.isEmpty() ) { return TurtleCommandResult.failure( "No items to take" ); @@ -113,7 +112,7 @@ public class TurtleSuckCommand implements ITurtleCommand for( ItemEntity entity : list ) { // Suck up the item - ItemStack stack = entity.getStack() + ItemStack stack = entity.getItem() .copy(); ItemStack storeStack; @@ -139,20 +138,20 @@ public class TurtleSuckCommand implements ITurtleCommand } else if( remainder.isEmpty() ) { - entity.setStack( leaveStack ); + entity.setItem( leaveStack ); } else if( leaveStack.isEmpty() ) { - entity.setStack( remainder ); + entity.setItem( remainder ); } else { - leaveStack.increment( remainder.getCount() ); - entity.setStack( leaveStack ); + leaveStack.grow( remainder.getCount() ); + entity.setItem( leaveStack ); } // Play fx - world.syncGlobalEvent( 1000, turtlePosition, 0 ); // BLOCK_DISPENSER_DISPENSE + world.globalLevelEvent( 1000, turtlePosition, 0 ); // BLOCK_DISPENSER_DISPENSE turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index 608d3196e..eb98cd731 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -11,9 +11,8 @@ import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.InventoryUtil; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.item.ItemStack; public class TurtleTransferToCommand implements ITurtleCommand { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index fd669ac8d..add8d1fec 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -39,12 +39,12 @@ public class TurtleTurnCommand implements ITurtleCommand { case LEFT: turtle.setDirection( turtle.getDirection() - .rotateYCounterclockwise() ); + .getCounterClockWise() ); turtle.playAnimation( TurtleAnimation.TURN_LEFT ); return TurtleCommandResult.success(); case RIGHT: turtle.setDirection( turtle.getDirection() - .rotateYClockwise() ); + .getClockWise() ); turtle.playAnimation( TurtleAnimation.TURN_RIGHT ); return TurtleCommandResult.success(); default: diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 17a06de7c..1e25ce1c7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -15,17 +15,16 @@ import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.util.SingleIntArray; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.SimpleInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.ArrayPropertyDelegate; -import net.minecraft.screen.PropertyDelegate; -import net.minecraft.screen.slot.Slot; - import javax.annotation.Nonnull; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.Container; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ContainerData; +import net.minecraft.world.inventory.SimpleContainerData; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; import java.util.function.Predicate; public class ContainerTurtle extends ContainerComputerBase @@ -35,13 +34,13 @@ public class ContainerTurtle extends ContainerComputerBase public static final int TURTLE_START_X = ComputerSidebar.WIDTH + 175; public static final int PLAYER_START_X = ComputerSidebar.WIDTH + BORDER; - private final PropertyDelegate properties; + private final ContainerData properties; - public ContainerTurtle( int id, PlayerInventory player, TurtleBrain turtle ) + public ContainerTurtle( int id, Inventory player, TurtleBrain turtle ) { this( id, p -> turtle.getOwner() - .canPlayerUse( p ), + .stillValid( p ), turtle.getOwner() .createServerComputer(), turtle.getFamily(), @@ -50,13 +49,13 @@ public class ContainerTurtle extends ContainerComputerBase (SingleIntArray) turtle::getSelectedSlot ); } - private ContainerTurtle( int id, Predicate canUse, IComputer computer, ComputerFamily family, PlayerInventory playerInventory, - Inventory inventory, PropertyDelegate properties ) + private ContainerTurtle( int id, Predicate canUse, IComputer computer, ComputerFamily family, Inventory playerInventory, + Container inventory, ContainerData properties ) { super( ComputerCraftRegistry.ModContainers.TURTLE, id, canUse, computer, family ); this.properties = properties; - addProperties( properties ); + addDataSlots( properties ); // Turtle inventory for( int y = 0; y < 4; y++ ) @@ -83,20 +82,20 @@ public class ContainerTurtle extends ContainerComputerBase } } - public ContainerTurtle( int id, PlayerInventory player, PacketByteBuf packetByteBuf ) + public ContainerTurtle( int id, Inventory player, FriendlyByteBuf packetByteBuf ) { this( id, player, new ComputerContainerData( packetByteBuf ) ); } - public ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) + public ContainerTurtle( int id, Inventory player, ComputerContainerData data ) { this( id, x -> true, getComputer( player, data ), data.getFamily(), player, - new SimpleInventory( TileTurtle.INVENTORY_SIZE ), - new ArrayPropertyDelegate( 1 ) ); + new SimpleContainer( TileTurtle.INVENTORY_SIZE ), + new SimpleContainerData( 1 ) ); } public int getSelectedSlot() @@ -106,7 +105,7 @@ public class ContainerTurtle extends ContainerComputerBase @Nonnull @Override - public ItemStack transferSlot( @Nonnull PlayerEntity player, int slotNum ) + public ItemStack quickMoveStack( @Nonnull Player player, int slotNum ) { if( slotNum >= 0 && slotNum < 16 ) { @@ -120,31 +119,31 @@ public class ContainerTurtle extends ContainerComputerBase } @Nonnull - private ItemStack tryItemMerge( PlayerEntity player, int slotNum, int firstSlot, int lastSlot, boolean reverse ) + private ItemStack tryItemMerge( Player player, int slotNum, int firstSlot, int lastSlot, boolean reverse ) { Slot slot = slots.get( slotNum ); ItemStack originalStack = ItemStack.EMPTY; - if( slot != null && slot.hasStack() ) + if( slot != null && slot.hasItem() ) { - ItemStack clickedStack = slot.getStack(); + ItemStack clickedStack = slot.getItem(); originalStack = clickedStack.copy(); - if( !insertItem( clickedStack, firstSlot, lastSlot, reverse ) ) + if( !moveItemStackTo( clickedStack, firstSlot, lastSlot, reverse ) ) { return ItemStack.EMPTY; } if( clickedStack.isEmpty() ) { - slot.setStack( ItemStack.EMPTY ); + slot.set( ItemStack.EMPTY ); } else { - slot.markDirty(); + slot.setChanged(); } if( clickedStack.getCount() != originalStack.getCount() ) { - slot.onTakeItem( player, clickedStack ); + slot.onTake( player, clickedStack ); } else { diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java index 349fc3cab..52cadb86b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java @@ -10,11 +10,10 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; public interface ITurtleItem extends IComputerItem, IColouredItem { @@ -24,5 +23,5 @@ public interface ITurtleItem extends IComputerItem, IColouredItem int getFuelLevel( @Nonnull ItemStack stack ); @Nullable - Identifier getOverlay( @Nonnull ItemStack stack ); + ResourceLocation getOverlay( @Nonnull ItemStack stack ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 4193f3e32..8843e6a56 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -13,30 +13,29 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.ItemComputerBase; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; import static dan200.computercraft.shared.turtle.core.TurtleBrain.*; public class ItemTurtle extends ItemComputerBase implements ITurtleItem { - public ItemTurtle( BlockTurtle block, Settings settings ) + public ItemTurtle( BlockTurtle block, Properties settings ) { super( block, settings ); } @Override - public void appendStacks( @Nonnull ItemGroup group, @Nonnull DefaultedList list ) + public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList list ) { - if( !isIn( group ) ) + if( !allowdedIn( group ) ) { return; } @@ -50,34 +49,34 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem .forEach( list::add ); } - public ItemStack create( int id, String label, int colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, int fuelLevel, Identifier overlay ) + public ItemStack create( int id, String label, int colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, int fuelLevel, ResourceLocation overlay ) { // Build the stack ItemStack stack = new ItemStack( this ); if( label != null ) { - stack.setCustomName( new LiteralText( label ) ); + stack.setHoverName( new TextComponent( label ) ); } if( id >= 0 ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_ID, id ); } IColouredItem.setColourBasic( stack, colour ); if( fuelLevel > 0 ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putInt( NBT_FUEL, fuelLevel ); } if( overlay != null ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putString( NBT_OVERLAY, overlay.toString() ); } if( leftUpgrade != null ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putString( NBT_LEFT_UPGRADE, leftUpgrade.getUpgradeID() .toString() ); @@ -85,7 +84,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem if( rightUpgrade != null ) { - stack.getOrCreateNbt() + stack.getOrCreateTag() .putString( NBT_RIGHT_UPGRADE, rightUpgrade.getUpgradeID() .toString() ); @@ -96,28 +95,28 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem @Nonnull @Override - public Text getName( @Nonnull ItemStack stack ) + public Component getName( @Nonnull ItemStack stack ) { - String baseString = getTranslationKey( stack ); + String baseString = getDescriptionId( stack ); ITurtleUpgrade left = getUpgrade( stack, TurtleSide.LEFT ); ITurtleUpgrade right = getUpgrade( stack, TurtleSide.RIGHT ); if( left != null && right != null ) { - return new TranslatableText( baseString + ".upgraded_twice", - new TranslatableText( right.getUnlocalisedAdjective() ), - new TranslatableText( left.getUnlocalisedAdjective() ) ); + return new TranslatableComponent( baseString + ".upgraded_twice", + new TranslatableComponent( right.getUnlocalisedAdjective() ), + new TranslatableComponent( left.getUnlocalisedAdjective() ) ); } else if( left != null ) { - return new TranslatableText( baseString + ".upgraded", new TranslatableText( left.getUnlocalisedAdjective() ) ); + return new TranslatableComponent( baseString + ".upgraded", new TranslatableComponent( left.getUnlocalisedAdjective() ) ); } else if( right != null ) { - return new TranslatableText( baseString + ".upgraded", new TranslatableText( right.getUnlocalisedAdjective() ) ); + return new TranslatableComponent( baseString + ".upgraded", new TranslatableComponent( right.getUnlocalisedAdjective() ) ); } else { - return new TranslatableText( baseString ); + return new TranslatableComponent( baseString ); } } @@ -148,7 +147,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem @Override public ITurtleUpgrade getUpgrade( @Nonnull ItemStack stack, @Nonnull TurtleSide side ) { - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); if( tag == null ) { return null; @@ -161,15 +160,15 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem @Override public int getFuelLevel( @Nonnull ItemStack stack ) { - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); return tag != null && tag.contains( NBT_FUEL ) ? tag.getInt( NBT_FUEL ) : 0; } @Override - public Identifier getOverlay( @Nonnull ItemStack stack ) + public ResourceLocation getOverlay( @Nonnull ItemStack stack ) { - NbtCompound tag = stack.getNbt(); - return tag != null && tag.contains( NBT_OVERLAY ) ? new Identifier( tag.getString( NBT_OVERLAY ) ) : null; + CompoundTag tag = stack.getTag(); + return tag != null && tag.contains( NBT_OVERLAY ) ? new ResourceLocation( tag.getString( NBT_OVERLAY ) ) : null; } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 9d604502f..908dd8709 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -12,10 +12,9 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.ITurtleTile; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; public final class TurtleItemFactory { @@ -38,7 +37,7 @@ public final class TurtleItemFactory @Nonnull public static ItemStack create( int id, String label, int colour, ComputerFamily family, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, - int fuelLevel, Identifier overlay ) + int fuelLevel, ResourceLocation overlay ) { switch( family ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index 3fda22471..f4e53bef9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -10,13 +10,12 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.util.collection.DefaultedList; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; public final class TurtleRecipe extends ComputerFamilyRecipe { @@ -24,13 +23,13 @@ public final class TurtleRecipe extends ComputerFamilyRecipe new ComputerFamilyRecipe.Serializer() { @Override - protected TurtleRecipe create( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result, ComputerFamily family ) + protected TurtleRecipe create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { return new TurtleRecipe( identifier, group, width, height, ingredients, result, family ); } }; - private TurtleRecipe( Identifier identifier, String group, int width, int height, DefaultedList ingredients, ItemStack result, + private TurtleRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ) { super( identifier, group, width, height, ingredients, result, family ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index fc297291a..c68a539de 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -12,41 +12,40 @@ import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.SpecialCraftingRecipe; -import net.minecraft.recipe.SpecialRecipeSerializer; -import net.minecraft.util.Identifier; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; -public final class TurtleUpgradeRecipe extends SpecialCraftingRecipe +public final class TurtleUpgradeRecipe extends CustomRecipe { - public static final RecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( TurtleUpgradeRecipe::new ); + public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( TurtleUpgradeRecipe::new ); - private TurtleUpgradeRecipe( Identifier id ) + private TurtleUpgradeRecipe( ResourceLocation id ) { super( id ); } @Nonnull @Override - public ItemStack getOutput() + public ItemStack getResultItem() { return TurtleItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null, null, 0, null ); } @Override - public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { return !craft( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack craft( @Nonnull CraftingContainer inventory ) { // Scan the grid for a row containing a turtle and 1 or 2 items ItemStack leftItem = ItemStack.EMPTY; @@ -61,7 +60,7 @@ public final class TurtleUpgradeRecipe extends SpecialCraftingRecipe boolean finishedRow = false; for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStack( x + y * inventory.getWidth() ); + ItemStack item = inventory.getItem( x + y * inventory.getWidth() ); if( !item.isEmpty() ) { if( finishedRow ) @@ -119,7 +118,7 @@ public final class TurtleUpgradeRecipe extends SpecialCraftingRecipe // Turtle is already found, just check this row is empty for( int x = 0; x < inventory.getWidth(); x++ ) { - ItemStack item = inventory.getStack( x + y * inventory.getWidth() ); + ItemStack item = inventory.getItem( x + y * inventory.getWidth() ); if( !item.isEmpty() ) { return ItemStack.EMPTY; @@ -171,12 +170,12 @@ public final class TurtleUpgradeRecipe extends SpecialCraftingRecipe String label = itemTurtle.getLabel( turtle ); int fuelLevel = itemTurtle.getFuelLevel( turtle ); int colour = itemTurtle.getColour( turtle ); - Identifier overlay = itemTurtle.getOverlay( turtle ); + ResourceLocation overlay = itemTurtle.getOverlay( turtle ); return TurtleItemFactory.create( computerID, label, colour, family, upgrades[0], upgrades[1], fuelLevel, overlay ); } @Override - public boolean fits( int x, int y ) + public boolean canCraftInDimensions( int x, int y ) { return x >= 3 && y >= 1; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index 635536c0f..cdc91c422 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -6,23 +6,23 @@ package dan200.computercraft.shared.turtle.upgrades; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; public class TurtleAxe extends TurtleTool { - public TurtleAxe( Identifier id, String adjective, Item item ) + public TurtleAxe( ResourceLocation id, String adjective, Item item ) { super( id, adjective, item ); } - public TurtleAxe( Identifier id, Item item ) + public TurtleAxe( ResourceLocation id, Item item ) { super( id, item ); } - public TurtleAxe( Identifier id, ItemStack craftItem, ItemStack toolItem ) + public TurtleAxe( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { super( id, craftItem, toolItem ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 88d668a87..d238dc706 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -14,21 +14,20 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.block.Blocks; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.util.Identifier; - +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Blocks; import javax.annotation.Nonnull; public class TurtleCraftingTable extends AbstractTurtleUpgrade { @Environment( EnvType.CLIENT ) - private ModelIdentifier leftModel; + private ModelResourceLocation leftModel; @Environment( EnvType.CLIENT ) - private ModelIdentifier rightModel; + private ModelResourceLocation rightModel; - public TurtleCraftingTable( Identifier id ) + public TurtleCraftingTable( ResourceLocation id ) { super( id, TurtleUpgradeType.PERIPHERAL, Blocks.CRAFTING_TABLE ); } @@ -53,8 +52,8 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade { if( leftModel == null ) { - leftModel = new ModelIdentifier( "computercraft:turtle_crafting_table_left", "inventory" ); - rightModel = new ModelIdentifier( "computercraft:turtle_crafting_table_right", "inventory" ); + leftModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_left", "inventory" ); + rightModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_right", "inventory" ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 1676455c6..e6e5ecf6e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -12,30 +12,29 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.block.BlockState; -import net.minecraft.block.Material; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; public class TurtleHoe extends TurtleTool { - public TurtleHoe( Identifier id, String adjective, Item item ) + public TurtleHoe( ResourceLocation id, String adjective, Item item ) { super( id, adjective, item ); } - public TurtleHoe( Identifier id, Item item ) + public TurtleHoe( ResourceLocation id, Item item ) { super( id, item ); } - public TurtleHoe( Identifier id, ItemStack craftItem, ItemStack toolItem ) + public TurtleHoe( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { super( id, craftItem, toolItem ); } @@ -57,7 +56,7 @@ public class TurtleHoe extends TurtleTool } @Override - protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, Level world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) { @@ -65,6 +64,6 @@ public class TurtleHoe extends TurtleTool } Material material = state.getMaterial(); - return material == Material.PLANT || material == Material.CACTUS || material == Material.GOURD || material == Material.LEAVES || material == Material.UNDERWATER_PLANT || material == Material.REPLACEABLE_PLANT; + return material == Material.PLANT || material == Material.CACTUS || material == Material.VEGETABLE || material == Material.LEAVES || material == Material.WATER_PLANT || material == Material.REPLACEABLE_PLANT; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 2b36437fd..eb264d95b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -9,22 +9,21 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Recipe; -import net.minecraft.recipe.RecipeType; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.NonNullList; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class TurtleInventoryCrafting extends CraftingInventory +public class TurtleInventoryCrafting extends CraftingContainer { private final ITurtleAccess turtle; private int xStart; @@ -42,7 +41,7 @@ public class TurtleInventoryCrafting extends CraftingInventory } @Nullable - private Recipe tryCrafting( int xStart, int yStart ) + private Recipe tryCrafting( int xStart, int yStart ) { this.xStart = xStart; this.yStart = yStart; @@ -55,7 +54,7 @@ public class TurtleInventoryCrafting extends CraftingInventory if( x < this.xStart || x >= this.xStart + 3 || y < this.yStart || y >= this.yStart + 3 ) { if( !turtle.getInventory() - .getStack( x + y * TileTurtle.INVENTORY_WIDTH ) + .getItem( x + y * TileTurtle.INVENTORY_WIDTH ) .isEmpty() ) { return null; @@ -67,20 +66,20 @@ public class TurtleInventoryCrafting extends CraftingInventory // Check the actual crafting return turtle.getWorld() .getRecipeManager() - .getFirstMatch( RecipeType.CRAFTING, this, turtle.getWorld() ) + .getRecipeFor( RecipeType.CRAFTING, this, turtle.getWorld() ) .orElse( null ); } @Nullable - public List doCrafting( World world, int maxCount ) + public List doCrafting( Level world, int maxCount ) { - if( world.isClient || !(world instanceof ServerWorld) ) + if( world.isClientSide || !(world instanceof ServerLevel) ) { return null; } // Find out what we can craft - Recipe recipe = tryCrafting( 0, 0 ); + Recipe recipe = tryCrafting( 0, 0 ); if( recipe == null ) { recipe = tryCrafting( 0, 1 ); @@ -109,25 +108,25 @@ public class TurtleInventoryCrafting extends CraftingInventory ArrayList results = new ArrayList<>(); for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ ) { - ItemStack result = recipe.craft( this ); + ItemStack result = recipe.assemble( this ); if( result.isEmpty() ) { break; } results.add( result ); - result.onCraft( world, player, result.getCount() ); - DefaultedList remainders = recipe.getRemainder( this ); + result.onCraftedBy( world, player, result.getCount() ); + NonNullList remainders = recipe.getRemainingItems( this ); for( int slot = 0; slot < remainders.size(); slot++ ) { - ItemStack existing = getStack( slot ); + ItemStack existing = getItem( slot ); ItemStack remainder = remainders.get( slot ); if( !existing.isEmpty() ) { - removeStack( slot, 1 ); - existing = getStack( slot ); + removeItem( slot, 1 ); + existing = getItem( slot ); } if( remainder.isEmpty() ) @@ -139,12 +138,12 @@ public class TurtleInventoryCrafting extends CraftingInventory // afterwards). if( existing.isEmpty() ) { - setStack( slot, remainder ); + setItem( slot, remainder ); } - else if( ItemStack.areItemsEqualIgnoreDamage( existing, remainder ) && ItemStack.areNbtEqual( existing, remainder ) ) + else if( ItemStack.isSame( existing, remainder ) && ItemStack.tagMatches( existing, remainder ) ) { - remainder.increment( existing.getCount() ); - setStack( slot, remainder ); + remainder.grow( existing.getCount() ); + setItem( slot, remainder ); } else { @@ -157,10 +156,10 @@ public class TurtleInventoryCrafting extends CraftingInventory } @Override - public int getMaxCountPerStack() + public int getMaxStackSize() { return turtle.getInventory() - .getMaxCountPerStack(); + .getMaxStackSize(); } @Override @@ -170,11 +169,11 @@ public class TurtleInventoryCrafting extends CraftingInventory } @Override - public boolean isValid( int i, @Nonnull ItemStack stack ) + public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); return turtle.getInventory() - .isValid( i, stack ); + .canPlaceItem( i, stack ); } @Override @@ -193,69 +192,69 @@ public class TurtleInventoryCrafting extends CraftingInventory // IInventory implementation @Override - public int size() + public int getContainerSize() { return getWidth() * getHeight(); } @Nonnull @Override - public ItemStack getStack( int i ) + public ItemStack getItem( int i ) { i = modifyIndex( i ); return turtle.getInventory() - .getStack( i ); + .getItem( i ); } @Nonnull @Override - public ItemStack removeStack( int i ) + public ItemStack removeItemNoUpdate( int i ) { i = modifyIndex( i ); return turtle.getInventory() - .removeStack( i ); + .removeItemNoUpdate( i ); } @Nonnull @Override - public ItemStack removeStack( int i, int size ) + public ItemStack removeItem( int i, int size ) { i = modifyIndex( i ); return turtle.getInventory() - .removeStack( i, size ); + .removeItem( i, size ); } @Override - public void setStack( int i, @Nonnull ItemStack stack ) + public void setItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); turtle.getInventory() - .setStack( i, stack ); + .setItem( i, stack ); } @Override - public void markDirty() + public void setChanged() { turtle.getInventory() - .markDirty(); + .setChanged(); } @Override - public boolean canPlayerUse( @Nonnull PlayerEntity player ) + public boolean stillValid( @Nonnull Player player ) { return true; } @Override - public void clear() + public void clearContent() { - for( int i = 0; i < size(); i++ ) + for( int i = 0; i < getContainerSize(); i++ ) { int j = modifyIndex( i ); turtle.getInventory() - .setStack( j, ItemStack.EMPTY ); + .setItem( j, ItemStack.EMPTY ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 9ef5b0b6a..4c82d30b4 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -14,29 +14,28 @@ import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; public class TurtleModem extends AbstractTurtleUpgrade { private final boolean advanced; @Environment( EnvType.CLIENT ) - private ModelIdentifier leftOffModel; + private ModelResourceLocation leftOffModel; @Environment( EnvType.CLIENT ) - private ModelIdentifier rightOffModel; + private ModelResourceLocation rightOffModel; @Environment( EnvType.CLIENT ) - private ModelIdentifier leftOnModel; + private ModelResourceLocation leftOnModel; @Environment( EnvType.CLIENT ) - private ModelIdentifier rightOnModel; + private ModelResourceLocation rightOnModel; - public TurtleModem( boolean advanced, Identifier id ) + public TurtleModem( boolean advanced, ResourceLocation id ) { super( id, TurtleUpgradeType.PERIPHERAL, @@ -67,7 +66,7 @@ public class TurtleModem extends AbstractTurtleUpgrade boolean active = false; if( turtle != null ) { - NbtCompound turtleNBT = turtle.getUpgradeNBTData( side ); + CompoundTag turtleNBT = turtle.getUpgradeNBTData( side ); active = turtleNBT.contains( "active" ) && turtleNBT.getBoolean( "active" ); } @@ -81,17 +80,17 @@ public class TurtleModem extends AbstractTurtleUpgrade { if( advanced ) { - leftOffModel = new ModelIdentifier( "computercraft:turtle_modem_advanced_off_left", "inventory" ); - rightOffModel = new ModelIdentifier( "computercraft:turtle_modem_advanced_off_right", "inventory" ); - leftOnModel = new ModelIdentifier( "computercraft:turtle_modem_advanced_on_left", "inventory" ); - rightOnModel = new ModelIdentifier( "computercraft:turtle_modem_advanced_on_right", "inventory" ); + leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" ); + rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" ); + leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" ); + rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" ); } else { - leftOffModel = new ModelIdentifier( "computercraft:turtle_modem_normal_off_left", "inventory" ); - rightOffModel = new ModelIdentifier( "computercraft:turtle_modem_normal_off_right", "inventory" ); - leftOnModel = new ModelIdentifier( "computercraft:turtle_modem_normal_on_left", "inventory" ); - rightOnModel = new ModelIdentifier( "computercraft:turtle_modem_normal_on_right", "inventory" ); + leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" ); + rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" ); + leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" ); + rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" ); } } } @@ -100,7 +99,7 @@ public class TurtleModem extends AbstractTurtleUpgrade public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) { // Advance the modem - if( !turtle.getWorld().isClient ) + if( !turtle.getWorld().isClientSide ) { IPeripheral peripheral = turtle.getPeripheral( side ); if( peripheral instanceof Peripheral ) @@ -128,17 +127,17 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override - public World getWorld() + public Level getWorld() { return turtle.getWorld(); } @Nonnull @Override - public Vec3d getPosition() + public Vec3 getPosition() { BlockPos turtlePos = turtle.getPosition(); - return new Vec3d( turtlePos.getX(), turtlePos.getY(), turtlePos.getZ() ); + return new Vec3( turtlePos.getX(), turtlePos.getY(), turtlePos.getZ() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index f08164bb2..9255cccb2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -12,30 +12,29 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.block.BlockState; -import net.minecraft.block.Material; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; public class TurtleShovel extends TurtleTool { - public TurtleShovel( Identifier id, String adjective, Item item ) + public TurtleShovel( ResourceLocation id, String adjective, Item item ) { super( id, adjective, item ); } - public TurtleShovel( Identifier id, Item item ) + public TurtleShovel( ResourceLocation id, Item item ) { super( id, item ); } - public TurtleShovel( Identifier id, ItemStack craftItem, ItemStack toolItem ) + public TurtleShovel( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { super( id, craftItem, toolItem ); } @@ -57,7 +56,7 @@ public class TurtleShovel extends TurtleTool } @Override - protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, Level world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) { @@ -65,6 +64,6 @@ public class TurtleShovel extends TurtleTool } Material material = state.getMaterial(); - return material == Material.SOIL || material == Material.AGGREGATE || material == Material.SNOW_LAYER || material == Material.ORGANIC_PRODUCT || material == Material.SNOW_BLOCK || material == Material.PLANT || material == Material.CACTUS || material == Material.GOURD || material == Material.LEAVES || material == Material.REPLACEABLE_PLANT; + return material == Material.DIRT || material == Material.SAND || material == Material.TOP_SNOW || material == Material.CLAY || material == Material.SNOW || material == Material.PLANT || material == Material.CACTUS || material == Material.VEGETABLE || material == Material.LEAVES || material == Material.REPLACEABLE_PLANT; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index fe87ef4a3..e074a9237 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -15,22 +15,21 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import javax.annotation.Nonnull; public class TurtleSpeaker extends AbstractTurtleUpgrade { @Environment( EnvType.CLIENT ) - private ModelIdentifier leftModel; + private ModelResourceLocation leftModel; @Environment( EnvType.CLIENT ) - private ModelIdentifier rightModel; + private ModelResourceLocation rightModel; - public TurtleSpeaker( Identifier id ) + public TurtleSpeaker( ResourceLocation id ) { super( id, TurtleUpgradeType.PERIPHERAL, ComputerCraftRegistry.ModBlocks.SPEAKER ); } @@ -55,8 +54,8 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade { if( leftModel == null ) { - leftModel = new ModelIdentifier( "computercraft:turtle_speaker_upgrade_left", "inventory" ); - rightModel = new ModelIdentifier( "computercraft:turtle_speaker_upgrade_right", "inventory" ); + leftModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" ); + rightModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" ); } } @@ -81,16 +80,16 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade } @Override - public World getWorld() + public Level getWorld() { return turtle.getWorld(); } @Override - public Vec3d getPosition() + public Vec3 getPosition() { BlockPos pos = turtle.getPosition(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vec3( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 7c41f9b46..e5fc53abc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -7,27 +7,27 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.block.BlockState; -import net.minecraft.block.Material; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; public class TurtleSword extends TurtleTool { - public TurtleSword( Identifier id, String adjective, Item item ) + public TurtleSword( ResourceLocation id, String adjective, Item item ) { super( id, adjective, item ); } - public TurtleSword( Identifier id, Item item ) + public TurtleSword( ResourceLocation id, Item item ) { super( id, item ); } - public TurtleSword( Identifier id, ItemStack craftItem, ItemStack toolItem ) + public TurtleSword( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { super( id, craftItem, toolItem ); } @@ -39,7 +39,7 @@ public class TurtleSword extends TurtleTool } @Override - protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, Level world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) { @@ -47,6 +47,6 @@ public class TurtleSword extends TurtleTool } Material material = state.getMaterial(); - return material == Material.PLANT || material == Material.LEAVES || material == Material.REPLACEABLE_PLANT || material == Material.WOOL || material == Material.COBWEB; + return material == Material.PLANT || material == Material.LEAVES || material == Material.REPLACEABLE_PLANT || material == Material.WOOL || material == Material.WEB; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index c5bbd31f4..d37811c43 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.turtle.upgrades; +import com.mojang.math.Matrix4f; +import com.mojang.math.Transformation; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.*; @@ -24,22 +26,25 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.Entity; -import net.minecraft.entity.attribute.EntityAttributes; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.math.*; -import net.minecraft.world.World; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -53,19 +58,19 @@ public class TurtleTool extends AbstractTurtleUpgrade private static final int TAG_LIST = 9; private static final int TAG_COMPOUND = 10; - public TurtleTool( Identifier id, String adjective, Item item ) + public TurtleTool( ResourceLocation id, String adjective, Item item ) { super( id, TurtleUpgradeType.TOOL, adjective, item ); this.item = new ItemStack( item ); } - public TurtleTool( Identifier id, Item item ) + public TurtleTool( ResourceLocation id, Item item ) { super( id, TurtleUpgradeType.TOOL, item ); this.item = new ItemStack( item ); } - public TurtleTool( Identifier id, ItemStack craftItem, ItemStack toolItem ) + public TurtleTool( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { super( id, TurtleUpgradeType.TOOL, craftItem ); item = toolItem; @@ -74,12 +79,12 @@ public class TurtleTool extends AbstractTurtleUpgrade @Override public boolean isItemSuitable( @Nonnull ItemStack stack ) { - NbtCompound tag = stack.getNbt(); + CompoundTag tag = stack.getTag(); if( tag == null || tag.isEmpty() ) return true; // Check we've not got anything vaguely interesting on the item. We allow other mods to add their // own NBT, with the understanding such details will be lost to the mist of time. - if( stack.isDamaged() || stack.hasEnchantments() || stack.hasCustomName() ) return false; + if( stack.isDamaged() || stack.isEnchanted() || stack.hasCustomHoverName() ) return false; return !tag.contains( "AttributeModifiers", TAG_LIST ) || tag.getList( "AttributeModifiers", TAG_COMPOUND ).isEmpty(); } @@ -110,7 +115,7 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult attack( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Create a fake player, and orient it appropriately - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos position = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( position ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); @@ -118,9 +123,9 @@ public class TurtleTool extends AbstractTurtleUpgrade final TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction ); // See if there is an entity present - Vec3d turtlePos = turtlePlayer.getPos(); - Vec3d rayDir = turtlePlayer.getRotationVec( 1.0f ); - Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); + Vec3 turtlePos = turtlePlayer.position(); + Vec3 rayDir = turtlePlayer.getViewVector( 1.0f ); + Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit != null ) { // Load up the turtle's inventoryf @@ -133,9 +138,9 @@ public class TurtleTool extends AbstractTurtleUpgrade if( AttackEntityCallback.EVENT.invoker() .interact( turtlePlayer, world, - Hand.MAIN_HAND, + InteractionHand.MAIN_HAND, hitEntity, - null ) == ActionResult.FAIL || !hitEntity.isAttackable() ) + null ) == InteractionResult.FAIL || !hitEntity.isAttackable() ) { return TurtleCommandResult.failure( "Nothing to attack here" ); } @@ -151,26 +156,26 @@ public class TurtleTool extends AbstractTurtleUpgrade // Attack the entity boolean attacked = false; - if( !hitEntity.handleAttack( turtlePlayer ) ) + if( !hitEntity.skipAttackInteraction( turtlePlayer ) ) { - float damage = (float) turtlePlayer.getAttributeValue( EntityAttributes.GENERIC_ATTACK_DAMAGE ); + float damage = (float) turtlePlayer.getAttributeValue( Attributes.ATTACK_DAMAGE ); damage *= getDamageMultiplier(); if( damage > 0.0f ) { - DamageSource source = DamageSource.player( turtlePlayer ); - if( hitEntity instanceof ArmorStandEntity ) + DamageSource source = DamageSource.playerAttack( turtlePlayer ); + if( hitEntity instanceof ArmorStand ) { // Special case for armor stands: attack twice to guarantee destroy - hitEntity.damage( source, damage ); + hitEntity.hurt( source, damage ); if( hitEntity.isAlive() ) { - hitEntity.damage( source, damage ); + hitEntity.hurt( source, damage ); } attacked = true; } else { - if( hitEntity.damage( source, damage ) ) + if( hitEntity.hurt( source, damage ) ) { attacked = true; } @@ -195,15 +200,15 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult dig( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Get ready to dig - World world = turtle.getWorld(); + Level world = turtle.getWorld(); BlockPos turtlePosition = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( turtlePosition ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); - BlockPos blockPosition = turtlePosition.offset( direction ); + BlockPos blockPosition = turtlePosition.relative( direction ); - if( world.isAir( blockPosition ) || WorldUtil.isLiquidBlock( world, blockPosition ) ) + if( world.isEmptyBlock( blockPosition ) || WorldUtil.isLiquidBlock( world, blockPosition ) ) { return TurtleCommandResult.failure( "Nothing to dig here" ); } @@ -248,19 +253,19 @@ public class TurtleTool extends AbstractTurtleUpgrade // to consult there before making any changes. // Play the destruction sound and particles - world.syncWorldEvent( 2001, blockPosition, Block.getRawIdFromState( state ) ); + world.levelEvent( 2001, blockPosition, Block.getId( state ) ); // Destroy the block state.getBlock() - .onBreak( world, blockPosition, state, turtlePlayer ); + .playerWillDestroy( world, blockPosition, state, turtlePlayer ); if( world.removeBlock( blockPosition, false ) ) { state.getBlock() - .onBroken( world, blockPosition, state ); - if( turtlePlayer.canHarvest( state ) ) + .destroy( world, blockPosition, state ); + if( turtlePlayer.hasCorrectToolForDrops( state ) ) { state.getBlock() - .afterBreak( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getMainHandStack() ); + .playerDestroy( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getMainHandItem() ); } } @@ -293,18 +298,18 @@ public class TurtleTool extends AbstractTurtleUpgrade } } - protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, Level world, BlockPos pos, TurtlePlayer player ) { Block block = state.getBlock(); - return !state.isAir() && block != Blocks.BEDROCK && state.calcBlockBreakingDelta( player, world, pos ) > 0; + return !state.isAir() && block != Blocks.BEDROCK && state.getDestroyProgress( player, world, pos ) > 0; } private static class Transforms { - static final AffineTransformation leftTransform = getMatrixFor( -0.40625f ); - static final AffineTransformation rightTransform = getMatrixFor( 0.40625f ); + static final Transformation leftTransform = getMatrixFor( -0.40625f ); + static final Transformation rightTransform = getMatrixFor( 0.40625f ); - private static AffineTransformation getMatrixFor( float offset ) + private static Transformation getMatrixFor( float offset ) { Matrix4f matrix = new Matrix4f(); ((IMatrix4f) (Object) matrix).setFloatArray( new float[] { @@ -313,7 +318,7 @@ public class TurtleTool extends AbstractTurtleUpgrade 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, } ); - return new AffineTransformation( matrix ); + return new Transformation( matrix ); } } } diff --git a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java index da0e00bb1..c0d1532a0 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.util; -import net.minecraft.util.DyeColor; +import net.minecraft.world.item.DyeColor; /** * A reimplementation of the colour system in {@link ArmorDyeRecipe}, but bundled together as an object. diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 92a1a13fc..26f518c22 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -6,12 +6,11 @@ package dan200.computercraft.shared.util; -import net.minecraft.item.DyeItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.DyeColor; - import javax.annotation.Nullable; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.DyeItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; public final class ColourUtils { @@ -21,6 +20,6 @@ public final class ColourUtils public static DyeColor getStackColour( ItemStack stack ) { Item item = stack.getItem(); - return item instanceof DyeItem ? ((DyeItem) item).getColor() : null; + return item instanceof DyeItem ? ((DyeItem) item).getDyeColor() : null; } } diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java index 241f0282d..cb62f47f0 100644 --- a/src/main/java/dan200/computercraft/shared/util/Config.java +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -19,10 +19,9 @@ import dan200.computercraft.core.apis.http.options.AddressRuleConfig; import dan200.computercraft.fabric.mixin.WorldSavePathAccess; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import net.fabricmc.loader.FabricLoader; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.WorldSavePath; - +import net.minecraft.world.level.storage.LevelResource; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -41,7 +40,7 @@ public final class Config public static CommentedFileConfig serverConfig; public static CommentedFileConfig clientConfig; - private static final WorldSavePath serverDir = WorldSavePathAccess.createWorldSavePath( "serverconfig" ); + private static final LevelResource serverDir = WorldSavePathAccess.createWorldSavePath( "serverconfig" ); private static final String serverFileName = "computercraft-server.toml"; private static Path serverPath = null; @@ -283,7 +282,7 @@ public final class Config public static void serverStarting( MinecraftServer server ) { - serverPath = server.getSavePath( serverDir ).resolve( serverFileName ); + serverPath = server.getWorldPath( serverDir ).resolve( serverFileName ); try( CommentedFileConfig config = buildFileConfig( serverPath ) ) { @@ -301,7 +300,7 @@ public final class Config serverPath = null; } - public static void clientStarted( MinecraftClient client ) + public static void clientStarted( Minecraft client ) { try( CommentedFileConfig config = buildFileConfig( clientPath ) ) { diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 857fafd34..4a6699444 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -6,32 +6,31 @@ package dan200.computercraft.shared.util; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; -public interface DefaultInventory extends Inventory +public interface DefaultInventory extends Container { @Override - default int getMaxCountPerStack() + default int getMaxStackSize() { return 64; } @Override - default void onOpen( @Nonnull PlayerEntity player ) + default void startOpen( @Nonnull Player player ) { } @Override - default void onClose( @Nonnull PlayerEntity player ) + default void stopOpen( @Nonnull Player player ) { } @Override - default boolean isValid( int slot, @Nonnull ItemStack stack ) + default boolean canPlaceItem( int slot, @Nonnull ItemStack stack ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index 706a0047b..80c1f34c9 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -6,23 +6,22 @@ package dan200.computercraft.shared.util; -import net.minecraft.inventory.SidedInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.core.Direction; +import net.minecraft.world.WorldlyContainer; +import net.minecraft.world.item.ItemStack; -public interface DefaultSidedInventory extends DefaultInventory, SidedInventory +public interface DefaultSidedInventory extends DefaultInventory, WorldlyContainer { @Override - default boolean canInsert( int slot, @Nonnull ItemStack stack, @Nullable Direction side ) + default boolean canPlaceItemThroughFace( int slot, @Nonnull ItemStack stack, @Nullable Direction side ) { - return isValid( slot, stack ); + return canPlaceItem( slot, stack ); } @Override - default boolean canExtract( int slot, @Nonnull ItemStack stack, @Nonnull Direction side ) + default boolean canTakeItemThroughFace( int slot, @Nonnull ItemStack stack, @Nonnull Direction side ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index 9f6cb01a9..5744d00e4 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.util; import dan200.computercraft.core.computer.ComputerSide; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public final class DirectionUtil { @@ -30,11 +30,11 @@ public final class DirectionUtil { return ComputerSide.BACK; } - if( dir == front.rotateYCounterclockwise() ) + if( dir == front.getCounterClockWise() ) { return ComputerSide.LEFT; } - if( dir == front.rotateYClockwise() ) + if( dir == front.getClockWise() ) { return ComputerSide.RIGHT; } diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 43bb89d84..a33bc2928 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -6,25 +6,24 @@ package dan200.computercraft.shared.util; -import net.minecraft.entity.Entity; -import net.minecraft.entity.ItemEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.world.World; - import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.function.Function; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; public final class DropConsumer { private static Function dropConsumer; private static List remainingDrops; - private static WeakReference dropWorld; + private static WeakReference dropWorld; private static BlockPos dropPos; - private static Box dropBounds; + private static AABB dropBounds; private static WeakReference dropEntity; private DropConsumer() @@ -36,18 +35,18 @@ public final class DropConsumer dropConsumer = consumer; remainingDrops = new ArrayList<>(); dropEntity = new WeakReference<>( entity ); - dropWorld = new WeakReference<>( entity.world ); + dropWorld = new WeakReference<>( entity.level ); dropPos = null; - dropBounds = new Box( entity.getBlockPos() ).expand( 2, 2, 2 ); + dropBounds = new AABB( entity.blockPosition() ).inflate( 2, 2, 2 ); } - public static void set( World world, BlockPos pos, Function consumer ) + public static void set( Level world, BlockPos pos, Function consumer ) { dropConsumer = consumer; remainingDrops = new ArrayList<>( 2 ); dropEntity = null; dropWorld = new WeakReference<>( world ); - dropBounds = new Box( pos ).expand( 2, 2, 2 ); + dropBounds = new AABB( pos ).inflate( 2, 2, 2 ); } public static List clear() @@ -63,7 +62,7 @@ public final class DropConsumer return remainingStacks; } - public static boolean onHarvestDrops( World world, BlockPos pos, ItemStack stack ) + public static boolean onHarvestDrops( Level world, BlockPos pos, ItemStack stack ) { if( dropWorld != null && dropWorld.get() == world && dropPos != null && dropPos.equals( pos ) ) { @@ -85,9 +84,9 @@ public final class DropConsumer public static boolean onEntitySpawn( Entity entity ) { // Capture any nearby item spawns - if( dropWorld != null && dropWorld.get() == entity.getEntityWorld() && entity instanceof ItemEntity && dropBounds.contains( entity.getPos() ) ) + if( dropWorld != null && dropWorld.get() == entity.getCommandSenderWorld() && entity instanceof ItemEntity && dropBounds.contains( entity.position() ) ) { - handleDrops( ((ItemEntity) entity).getStack() ); + handleDrops( ((ItemEntity) entity).getItem() ); return true; } return false; diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index c955ae361..440665855 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -10,24 +10,67 @@ import dan200.computercraft.api.turtle.FakePlayer; import io.netty.channel.ChannelHandlerContext; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; -import net.minecraft.network.ClientConnection; -import net.minecraft.network.NetworkSide; -import net.minecraft.network.NetworkState; -import net.minecraft.network.Packet; -import net.minecraft.network.listener.PacketListener; +import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; import net.minecraft.network.packet.c2s.play.*; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.text.Text; - +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket; +import net.minecraft.network.protocol.game.ServerboundBlockEntityTagQuery; +import net.minecraft.network.protocol.game.ServerboundChangeDifficultyPacket; +import net.minecraft.network.protocol.game.ServerboundChatPacket; +import net.minecraft.network.protocol.game.ServerboundClientCommandPacket; +import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; +import net.minecraft.network.protocol.game.ServerboundCommandSuggestionPacket; +import net.minecraft.network.protocol.game.ServerboundContainerButtonClickPacket; +import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; +import net.minecraft.network.protocol.game.ServerboundContainerClosePacket; +import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.game.ServerboundEditBookPacket; +import net.minecraft.network.protocol.game.ServerboundEntityTagQuery; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.ServerboundJigsawGeneratePacket; +import net.minecraft.network.protocol.game.ServerboundKeepAlivePacket; +import net.minecraft.network.protocol.game.ServerboundLockDifficultyPacket; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket; +import net.minecraft.network.protocol.game.ServerboundPaddleBoatPacket; +import net.minecraft.network.protocol.game.ServerboundPickItemPacket; +import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket; +import net.minecraft.network.protocol.game.ServerboundPlayerAbilitiesPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; +import net.minecraft.network.protocol.game.ServerboundRecipeBookChangeSettingsPacket; +import net.minecraft.network.protocol.game.ServerboundRecipeBookSeenRecipePacket; +import net.minecraft.network.protocol.game.ServerboundRenameItemPacket; +import net.minecraft.network.protocol.game.ServerboundResourcePackPacket; +import net.minecraft.network.protocol.game.ServerboundSeenAdvancementsPacket; +import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; +import net.minecraft.network.protocol.game.ServerboundSetBeaconPacket; +import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; +import net.minecraft.network.protocol.game.ServerboundSetCommandBlockPacket; +import net.minecraft.network.protocol.game.ServerboundSetCommandMinecartPacket; +import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket; +import net.minecraft.network.protocol.game.ServerboundSetJigsawBlockPacket; +import net.minecraft.network.protocol.game.ServerboundSetStructureBlockPacket; +import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; +import net.minecraft.network.protocol.game.ServerboundSwingPacket; +import net.minecraft.network.protocol.game.ServerboundTeleportToEntityPacket; +import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; +import net.minecraft.server.network.ServerGamePacketListenerImpl; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.crypto.Cipher; -public class FakeNetHandler extends ServerPlayNetworkHandler +public class FakeNetHandler extends ServerGamePacketListenerImpl { public FakeNetHandler( @Nonnull FakePlayer player ) { - super( player.getServerWorld() + super( player.getLevel() .getServer(), new FakeNetworkManager(), player ); } @@ -37,208 +80,208 @@ public class FakeNetHandler extends ServerPlayNetworkHandler } @Override - public void disconnect( @Nonnull Text reason ) + public void disconnect( @Nonnull Component reason ) { } @Override - public void onPlayerInput( @Nonnull PlayerInputC2SPacket packet ) + public void handlePlayerInput( @Nonnull ServerboundPlayerInputPacket packet ) { } @Override - public void onVehicleMove( @Nonnull VehicleMoveC2SPacket packet ) + public void handleMoveVehicle( @Nonnull ServerboundMoveVehiclePacket packet ) { } @Override - public void onTeleportConfirm( @Nonnull TeleportConfirmC2SPacket packet ) + public void handleAcceptTeleportPacket( @Nonnull ServerboundAcceptTeleportationPacket packet ) { } @Override - public void onAdvancementTab( @Nonnull AdvancementTabC2SPacket packet ) + public void handleSeenAdvancements( @Nonnull ServerboundSeenAdvancementsPacket packet ) { } @Override - public void onRequestCommandCompletions( @Nonnull RequestCommandCompletionsC2SPacket packet ) + public void handleCustomCommandSuggestions( @Nonnull ServerboundCommandSuggestionPacket packet ) { } @Override - public void onUpdateCommandBlock( @Nonnull UpdateCommandBlockC2SPacket packet ) + public void handleSetCommandBlock( @Nonnull ServerboundSetCommandBlockPacket packet ) { } @Override - public void onUpdateCommandBlockMinecart( @Nonnull UpdateCommandBlockMinecartC2SPacket packet ) + public void handleSetCommandMinecart( @Nonnull ServerboundSetCommandMinecartPacket packet ) { } @Override - public void onPickFromInventory( @Nonnull PickFromInventoryC2SPacket packet ) + public void handlePickItem( @Nonnull ServerboundPickItemPacket packet ) { } @Override - public void onRenameItem( @Nonnull RenameItemC2SPacket packet ) + public void handleRenameItem( @Nonnull ServerboundRenameItemPacket packet ) { } @Override - public void onUpdateBeacon( @Nonnull UpdateBeaconC2SPacket packet ) + public void handleSetBeaconPacket( @Nonnull ServerboundSetBeaconPacket packet ) { } @Override - public void onStructureBlockUpdate( @Nonnull UpdateStructureBlockC2SPacket packet ) + public void handleSetStructureBlock( @Nonnull ServerboundSetStructureBlockPacket packet ) { } @Override - public void onJigsawUpdate( @Nonnull UpdateJigsawC2SPacket packet ) + public void handleSetJigsawBlock( @Nonnull ServerboundSetJigsawBlockPacket packet ) { } @Override - public void onJigsawGenerating( JigsawGeneratingC2SPacket packet ) + public void handleJigsawGenerate( ServerboundJigsawGeneratePacket packet ) { } @Override - public void onMerchantTradeSelect( SelectMerchantTradeC2SPacket packet ) + public void handleSelectTrade( ServerboundSelectTradePacket packet ) { } @Override - public void onBookUpdate( @Nonnull BookUpdateC2SPacket packet ) + public void handleEditBook( @Nonnull ServerboundEditBookPacket packet ) { } @Override - public void onRecipeBookData( RecipeBookDataC2SPacket packet ) + public void handleRecipeBookSeenRecipePacket( ServerboundRecipeBookSeenRecipePacket packet ) { } @Override - public void onRecipeCategoryOptions( RecipeCategoryOptionsC2SPacket packet ) + public void handleRecipeBookChangeSettingsPacket( ServerboundRecipeBookChangeSettingsPacket packet ) { - super.onRecipeCategoryOptions( packet ); + super.handleRecipeBookChangeSettingsPacket( packet ); } @Override - public void onQueryEntityNbt( @Nonnull QueryEntityNbtC2SPacket packet ) + public void handleEntityTagQuery( @Nonnull ServerboundEntityTagQuery packet ) { } @Override - public void onQueryBlockNbt( @Nonnull QueryBlockNbtC2SPacket packet ) + public void handleBlockEntityTagQuery( @Nonnull ServerboundBlockEntityTagQuery packet ) { } @Override - public void onPlayerMove( @Nonnull PlayerMoveC2SPacket packet ) + public void handleMovePlayer( @Nonnull ServerboundMovePlayerPacket packet ) { } @Override - public void onPlayerAction( @Nonnull PlayerActionC2SPacket packet ) + public void handlePlayerAction( @Nonnull ServerboundPlayerActionPacket packet ) { } @Override - public void onPlayerInteractBlock( @Nonnull PlayerInteractBlockC2SPacket packet ) + public void handleUseItemOn( @Nonnull ServerboundUseItemOnPacket packet ) { } @Override - public void onPlayerInteractItem( @Nonnull PlayerInteractItemC2SPacket packet ) + public void handleUseItem( @Nonnull ServerboundUseItemPacket packet ) { } @Override - public void onSpectatorTeleport( @Nonnull SpectatorTeleportC2SPacket packet ) + public void handleTeleportToEntityPacket( @Nonnull ServerboundTeleportToEntityPacket packet ) { } @Override - public void onResourcePackStatus( @Nonnull ResourcePackStatusC2SPacket packet ) + public void handleResourcePackResponse( @Nonnull ServerboundResourcePackPacket packet ) { } @Override - public void onBoatPaddleState( @Nonnull BoatPaddleStateC2SPacket packet ) + public void handlePaddleBoat( @Nonnull ServerboundPaddleBoatPacket packet ) { } @Override - public void onDisconnected( @Nonnull Text reason ) + public void onDisconnect( @Nonnull Component reason ) { } @Override - public void sendPacket( @Nonnull Packet packet ) + public void send( @Nonnull Packet packet ) { } @Override - public void sendPacket( @Nonnull Packet packet, @Nullable GenericFutureListener> whenSent ) + public void send( @Nonnull Packet packet, @Nullable GenericFutureListener> whenSent ) { } @Override - public void onUpdateSelectedSlot( @Nonnull UpdateSelectedSlotC2SPacket packet ) + public void handleSetCarriedItem( @Nonnull ServerboundSetCarriedItemPacket packet ) { } @Override - public void onGameMessage( @Nonnull ChatMessageC2SPacket packet ) + public void handleChat( @Nonnull ServerboundChatPacket packet ) { } @Override - public void onHandSwing( @Nonnull HandSwingC2SPacket packet ) + public void handleAnimate( @Nonnull ServerboundSwingPacket packet ) { } @Override - public void onClientCommand( @Nonnull ClientCommandC2SPacket packet ) + public void handlePlayerCommand( @Nonnull ServerboundPlayerCommandPacket packet ) { } @Override - public void onPlayerInteractEntity( @Nonnull PlayerInteractEntityC2SPacket packet ) + public void handleInteract( @Nonnull ServerboundInteractPacket packet ) { } @Override - public void onClientStatus( @Nonnull ClientStatusC2SPacket packet ) + public void handleClientCommand( @Nonnull ServerboundClientCommandPacket packet ) { } @Override - public void onCloseHandledScreen( CloseHandledScreenC2SPacket packet ) + public void handleContainerClose( ServerboundContainerClosePacket packet ) { } @Override - public void onClickSlot( ClickSlotC2SPacket packet ) + public void handleContainerClick( ServerboundContainerClickPacket packet ) { } @Override - public void onCraftRequest( @Nonnull CraftRequestC2SPacket packet ) + public void handlePlaceRecipe( @Nonnull ServerboundPlaceRecipePacket packet ) { } @Override - public void onButtonClick( @Nonnull ButtonClickC2SPacket packet ) + public void handleContainerButtonClick( @Nonnull ServerboundContainerButtonClickPacket packet ) { } @Override - public void onCreativeInventoryAction( @Nonnull CreativeInventoryActionC2SPacket packet ) + public void handleSetCreativeModeSlot( @Nonnull ServerboundSetCreativeModeSlotPacket packet ) { } @@ -248,48 +291,48 @@ public class FakeNetHandler extends ServerPlayNetworkHandler // } @Override - public void onSignUpdate( @Nonnull UpdateSignC2SPacket packet ) + public void handleSignUpdate( @Nonnull ServerboundSignUpdatePacket packet ) { } @Override - public void onKeepAlive( @Nonnull KeepAliveC2SPacket packet ) + public void handleKeepAlive( @Nonnull ServerboundKeepAlivePacket packet ) { } @Override - public void onPlayerAbilities( @Nonnull UpdatePlayerAbilitiesC2SPacket packet ) + public void handlePlayerAbilities( @Nonnull ServerboundPlayerAbilitiesPacket packet ) { } @Override - public void onClientSettings( @Nonnull ClientSettingsC2SPacket packet ) + public void handleClientInformation( @Nonnull ServerboundClientInformationPacket packet ) { } @Override - public void onCustomPayload( @Nonnull CustomPayloadC2SPacket packet ) + public void handleCustomPayload( @Nonnull ServerboundCustomPayloadPacket packet ) { } @Override - public void onUpdateDifficulty( @Nonnull UpdateDifficultyC2SPacket packet ) + public void handleChangeDifficulty( @Nonnull ServerboundChangeDifficultyPacket packet ) { } @Override - public void onUpdateDifficultyLock( @Nonnull UpdateDifficultyLockC2SPacket packet ) + public void handleLockDifficulty( @Nonnull ServerboundLockDifficultyPacket packet ) { } - private static class FakeNetworkManager extends ClientConnection + private static class FakeNetworkManager extends Connection { private PacketListener handler; - private Text closeReason; + private Component closeReason; FakeNetworkManager() { - super( NetworkSide.CLIENTBOUND ); + super( PacketFlow.CLIENTBOUND ); } @Override @@ -298,7 +341,7 @@ public class FakeNetHandler extends ServerPlayNetworkHandler } @Override - public void setState( @Nonnull NetworkState state ) + public void setProtocol( @Nonnull ConnectionProtocol state ) { } @@ -318,7 +361,7 @@ public class FakeNetHandler extends ServerPlayNetworkHandler } @Override - public void setPacketListener( @Nonnull PacketListener handler ) + public void setListener( @Nonnull PacketListener handler ) { this.handler = handler; } @@ -339,13 +382,13 @@ public class FakeNetHandler extends ServerPlayNetworkHandler } @Override - public void disconnect( @Nonnull Text message ) + public void disconnect( @Nonnull Component message ) { closeReason = message; } @Override - public void setupEncryption( Cipher cipher, Cipher cipher2 ) + public void setEncryptionKey( Cipher cipher, Cipher cipher2 ) { } @@ -358,13 +401,13 @@ public class FakeNetHandler extends ServerPlayNetworkHandler @Nullable @Override - public Text getDisconnectReason() + public Component getDisconnectedReason() { return closeReason; } @Override - public void disableAutoRead() + public void setReadOnly() { } } diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 6a10e44fa..0c4b14ec9 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -13,8 +13,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.fabric.mixin.WorldSavePathAccess; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.WorldSavePath; - +import net.minecraft.world.level.storage.LevelResource; import java.io.File; import java.io.Reader; import java.io.Writer; @@ -28,7 +27,7 @@ import java.util.Map; public final class IDAssigner { - private static final WorldSavePath FOLDER = WorldSavePathAccess.createWorldSavePath( ComputerCraft.MOD_ID ); + private static final LevelResource FOLDER = WorldSavePathAccess.createWorldSavePath( ComputerCraft.MOD_ID ); private static final Gson GSON = new GsonBuilder().setPrettyPrinting() .create(); private static final Type ID_TOKEN = new TypeToken>() @@ -116,7 +115,7 @@ public final class IDAssigner public static File getDir() { return GameInstanceUtils.getServer() - .getSavePath( FOLDER ) + .getWorldPath( FOLDER ) .toFile(); } } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index a9e8a3f2f..eed47d8d8 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -7,65 +7,64 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonObject; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.ShapedRecipe; -import net.minecraft.util.Identifier; -import net.minecraft.util.JsonHelper; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.level.Level; public final class ImpostorRecipe extends ShapedRecipe { public static final RecipeSerializer SERIALIZER = new RecipeSerializer() { @Override - public ImpostorRecipe read( @Nonnull Identifier identifier, @Nonnull JsonObject json ) + public ImpostorRecipe fromJson( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { - String group = JsonHelper.getString( json, "group", "" ); - ShapedRecipe recipe = RecipeSerializer.SHAPED.read( identifier, json ); - JsonObject resultObject = JsonHelper.getObject( json, "result" ); - ItemStack itemStack = ShapedRecipe.outputFromJson( resultObject ); + String group = GsonHelper.getAsString( json, "group", "" ); + ShapedRecipe recipe = RecipeSerializer.SHAPED_RECIPE.fromJson( identifier, json ); + JsonObject resultObject = GsonHelper.getAsJsonObject( json, "result" ); + ItemStack itemStack = ShapedRecipe.itemStackFromJson( resultObject ); RecipeUtil.setNbt( itemStack, resultObject ); return new ImpostorRecipe( identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), itemStack ); } @Override - public ImpostorRecipe read( @Nonnull Identifier identifier, @Nonnull PacketByteBuf buf ) + public ImpostorRecipe fromNetwork( @Nonnull ResourceLocation identifier, @Nonnull FriendlyByteBuf buf ) { int width = buf.readVarInt(); int height = buf.readVarInt(); - String group = buf.readString( Short.MAX_VALUE ); - DefaultedList items = DefaultedList.ofSize( width * height, Ingredient.EMPTY ); + String group = buf.readUtf( Short.MAX_VALUE ); + NonNullList items = NonNullList.withSize( width * height, Ingredient.EMPTY ); for( int k = 0; k < items.size(); ++k ) { - items.set( k, Ingredient.fromPacket( buf ) ); + items.set( k, Ingredient.fromNetwork( buf ) ); } - ItemStack result = buf.readItemStack(); + ItemStack result = buf.readItem(); return new ImpostorRecipe( identifier, group, width, height, items, result ); } @Override - public void write( @Nonnull PacketByteBuf buf, @Nonnull ImpostorRecipe recipe ) + public void write( @Nonnull FriendlyByteBuf buf, @Nonnull ImpostorRecipe recipe ) { buf.writeVarInt( recipe.getWidth() ); buf.writeVarInt( recipe.getHeight() ); - buf.writeString( recipe.getGroup() ); + buf.writeUtf( recipe.getGroup() ); for( Ingredient ingredient : recipe.getIngredients() ) { - ingredient.write( buf ); + ingredient.toNetwork( buf ); } - buf.writeItemStack( recipe.getOutput() ); + buf.writeItem( recipe.getResultItem() ); } }; private final String group; - private ImpostorRecipe( @Nonnull Identifier id, @Nonnull String group, int width, int height, DefaultedList ingredients, + private ImpostorRecipe( @Nonnull ResourceLocation id, @Nonnull String group, int width, int height, NonNullList ingredients, @Nonnull ItemStack result ) { super( id, group, width, height, ingredients, result ); @@ -87,14 +86,14 @@ public final class ImpostorRecipe extends ShapedRecipe } @Override - public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inv, @Nonnull Level world ) { return false; } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index c2191843a..c5c44a1a0 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -9,29 +9,28 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.RecipeSerializer; -import net.minecraft.recipe.ShapedRecipe; -import net.minecraft.recipe.ShapelessRecipe; -import net.minecraft.util.Identifier; -import net.minecraft.util.JsonHelper; -import net.minecraft.util.collection.DefaultedList; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.core.NonNullList; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.world.level.Level; public final class ImpostorShapelessRecipe extends ShapelessRecipe { public static final RecipeSerializer SERIALIZER = new RecipeSerializer() { @Override - public ImpostorShapelessRecipe read( @Nonnull Identifier id, @Nonnull JsonObject json ) + public ImpostorShapelessRecipe fromJson( @Nonnull ResourceLocation id, @Nonnull JsonObject json ) { - String s = JsonHelper.getString( json, "group", "" ); - DefaultedList ingredients = readIngredients( JsonHelper.getArray( json, "ingredients" ) ); + String s = GsonHelper.getAsString( json, "group", "" ); + NonNullList ingredients = readIngredients( GsonHelper.getAsJsonArray( json, "ingredients" ) ); if( ingredients.isEmpty() ) { @@ -41,15 +40,15 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe { throw new JsonParseException( "Too many ingredients for shapeless recipe the max is 9" ); } - JsonObject resultObject = JsonHelper.getObject( json, "result" ); - ItemStack itemStack = ShapedRecipe.outputFromJson( resultObject ); + JsonObject resultObject = GsonHelper.getAsJsonObject( json, "result" ); + ItemStack itemStack = ShapedRecipe.itemStackFromJson( resultObject ); RecipeUtil.setNbt( itemStack, resultObject ); return new ImpostorShapelessRecipe( id, s, itemStack, ingredients ); } - private DefaultedList readIngredients( JsonArray arrays ) + private NonNullList readIngredients( JsonArray arrays ) { - DefaultedList items = DefaultedList.of(); + NonNullList items = NonNullList.create(); for( int i = 0; i < arrays.size(); ++i ) { Ingredient ingredient = Ingredient.fromJson( arrays.get( i ) ); @@ -63,38 +62,38 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe } @Override - public ImpostorShapelessRecipe read( @Nonnull Identifier id, PacketByteBuf buffer ) + public ImpostorShapelessRecipe fromNetwork( @Nonnull ResourceLocation id, FriendlyByteBuf buffer ) { - String s = buffer.readString( 32767 ); + String s = buffer.readUtf( 32767 ); int i = buffer.readVarInt(); - DefaultedList items = DefaultedList.ofSize( i, Ingredient.EMPTY ); + NonNullList items = NonNullList.withSize( i, Ingredient.EMPTY ); for( int j = 0; j < items.size(); j++ ) { - items.set( j, Ingredient.fromPacket( buffer ) ); + items.set( j, Ingredient.fromNetwork( buffer ) ); } - ItemStack result = buffer.readItemStack(); + ItemStack result = buffer.readItem(); return new ImpostorShapelessRecipe( id, s, result, items ); } @Override - public void write( @Nonnull PacketByteBuf buffer, @Nonnull ImpostorShapelessRecipe recipe ) + public void write( @Nonnull FriendlyByteBuf buffer, @Nonnull ImpostorShapelessRecipe recipe ) { - buffer.writeString( recipe.getGroup() ); + buffer.writeUtf( recipe.getGroup() ); buffer.writeVarInt( recipe.getIngredients() .size() ); for( Ingredient ingredient : recipe.getIngredients() ) { - ingredient.write( buffer ); + ingredient.toNetwork( buffer ); } - buffer.writeItemStack( recipe.getOutput() ); + buffer.writeItem( recipe.getResultItem() ); } }; private final String group; - private ImpostorShapelessRecipe( @Nonnull Identifier id, @Nonnull String group, @Nonnull ItemStack result, DefaultedList ingredients ) + private ImpostorShapelessRecipe( @Nonnull ResourceLocation id, @Nonnull String group, @Nonnull ItemStack result, NonNullList ingredients ) { super( id, group, result, ingredients ); this.group = group; @@ -115,14 +114,14 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe } @Override - public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingContainer inv, @Nonnull Level world ) { return false; } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingInventory inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java index 41af4a582..9dbbfffd8 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -6,12 +6,11 @@ package dan200.computercraft.shared.util; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import java.util.Set; /** @@ -21,15 +20,15 @@ import java.util.Set; * inventories which change their backing store. */ @FunctionalInterface -public interface InventoryDelegate extends Inventory +public interface InventoryDelegate extends Container { @Override - default int size() + default int getContainerSize() { - return getInventory().size(); + return getInventory().getContainerSize(); } - Inventory getInventory(); + Container getInventory(); @Override default boolean isEmpty() @@ -39,82 +38,82 @@ public interface InventoryDelegate extends Inventory @Nonnull @Override - default ItemStack getStack( int slot ) + default ItemStack getItem( int slot ) { - return getInventory().getStack( slot ); + return getInventory().getItem( slot ); } @Nonnull @Override - default ItemStack removeStack( int slot, int count ) + default ItemStack removeItem( int slot, int count ) { - return getInventory().removeStack( slot, count ); + return getInventory().removeItem( slot, count ); } @Nonnull @Override - default ItemStack removeStack( int slot ) + default ItemStack removeItemNoUpdate( int slot ) { - return getInventory().removeStack( slot ); + return getInventory().removeItemNoUpdate( slot ); } @Override - default void setStack( int slot, @Nonnull ItemStack stack ) + default void setItem( int slot, @Nonnull ItemStack stack ) { - getInventory().setStack( slot, stack ); + getInventory().setItem( slot, stack ); } @Override - default int getMaxCountPerStack() + default int getMaxStackSize() { - return getInventory().getMaxCountPerStack(); + return getInventory().getMaxStackSize(); } @Override - default void markDirty() + default void setChanged() { - getInventory().markDirty(); + getInventory().setChanged(); } @Override - default boolean canPlayerUse( @Nonnull PlayerEntity player ) + default boolean stillValid( @Nonnull Player player ) { - return getInventory().canPlayerUse( player ); + return getInventory().stillValid( player ); } @Override - default void onOpen( @Nonnull PlayerEntity player ) + default void startOpen( @Nonnull Player player ) { - getInventory().onOpen( player ); + getInventory().startOpen( player ); } @Override - default void onClose( @Nonnull PlayerEntity player ) + default void stopOpen( @Nonnull Player player ) { - getInventory().onClose( player ); + getInventory().stopOpen( player ); } @Override - default boolean isValid( int slot, @Nonnull ItemStack stack ) + default boolean canPlaceItem( int slot, @Nonnull ItemStack stack ) { - return getInventory().isValid( slot, stack ); + return getInventory().canPlaceItem( slot, stack ); } @Override - default int count( @Nonnull Item stack ) + default int countItem( @Nonnull Item stack ) { - return getInventory().count( stack ); + return getInventory().countItem( stack ); } @Override - default boolean containsAny( @Nonnull Set set ) + default boolean hasAnyOf( @Nonnull Set set ) { - return getInventory().containsAny( set ); + return getInventory().hasAnyOf( set ); } @Override - default void clear() + default void clearContent() { - getInventory().clear(); + getInventory().clearContent(); } } diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 9d836718b..4dc196e95 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -6,22 +6,22 @@ package dan200.computercraft.shared.util; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ChestBlock; -import net.minecraft.block.InventoryProvider; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.ChestBlockEntity; -import net.minecraft.entity.Entity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.Container; +import net.minecraft.world.WorldlyContainerHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; public final class InventoryUtil { @@ -30,12 +30,12 @@ public final class InventoryUtil public static boolean areItemsStackable( @Nonnull ItemStack a, @Nonnull ItemStack b ) { - return a == b || (a.getItem() == b.getItem() && ItemStack.areNbtEqual( a, b )); + return a == b || (a.getItem() == b.getItem() && ItemStack.tagMatches( a, b )); } // Methods for finding inventories: - public static Inventory getInventory( World world, BlockPos pos, Direction side ) + public static Container getInventory( Level world, BlockPos pos, Direction side ) { // Look for tile with inventory int y = pos.getY(); @@ -44,16 +44,16 @@ public final class InventoryUtil // Check if block is InventoryProvider BlockState blockState = world.getBlockState( pos ); Block block = blockState.getBlock(); - if( block instanceof InventoryProvider ) + if( block instanceof WorldlyContainerHolder ) { - return ((InventoryProvider) block).getInventory( blockState, world, pos ); + return ((WorldlyContainerHolder) block).getContainer( blockState, world, pos ); } // Check if block is BlockEntity w/ Inventory if( blockState.hasBlockEntity() ) { BlockEntity tileEntity = world.getBlockEntity( pos ); - Inventory inventory = getInventory( tileEntity ); + Container inventory = getInventory( tileEntity ); if( inventory != null ) { return inventory; @@ -62,36 +62,36 @@ public final class InventoryUtil } // Look for entity with inventory - Vec3d vecStart = new Vec3d( pos.getX() + 0.5 + 0.6 * side.getOffsetX(), - pos.getY() + 0.5 + 0.6 * side.getOffsetY(), - pos.getZ() + 0.5 + 0.6 * side.getOffsetZ() ); + Vec3 vecStart = new Vec3( pos.getX() + 0.5 + 0.6 * side.getStepX(), + pos.getY() + 0.5 + 0.6 * side.getStepY(), + pos.getZ() + 0.5 + 0.6 * side.getStepZ() ); Direction dir = side.getOpposite(); - Vec3d vecDir = new Vec3d( dir.getOffsetX(), dir.getOffsetY(), dir.getOffsetZ() ); - Pair hit = WorldUtil.rayTraceEntities( world, vecStart, vecDir, 1.1 ); + Vec3 vecDir = new Vec3( dir.getStepX(), dir.getStepY(), dir.getStepZ() ); + Pair hit = WorldUtil.rayTraceEntities( world, vecStart, vecDir, 1.1 ); if( hit != null ) { Entity entity = hit.getKey(); - if( entity instanceof Inventory ) + if( entity instanceof Container ) { - return (Inventory) entity; + return (Container) entity; } } return null; } - public static Inventory getInventory( BlockEntity tileEntity ) + public static Container getInventory( BlockEntity tileEntity ) { - World world = tileEntity.getWorld(); - BlockPos pos = tileEntity.getPos(); + Level world = tileEntity.getLevel(); + BlockPos pos = tileEntity.getBlockPos(); BlockState blockState = world.getBlockState( pos ); Block block = blockState.getBlock(); - if( tileEntity instanceof Inventory ) + if( tileEntity instanceof Container ) { - Inventory inventory = (Inventory) tileEntity; + Container inventory = (Container) tileEntity; if( inventory instanceof ChestBlockEntity && block instanceof ChestBlock ) { - return ChestBlock.getInventory( (ChestBlock) block, blockState, world, pos, true ); + return ChestBlock.getContainer( (ChestBlock) block, blockState, world, pos, true ); } return inventory; } @@ -131,7 +131,7 @@ public final class InventoryUtil public static boolean areItemsEqual( @Nonnull ItemStack a, @Nonnull ItemStack b ) { - return a == b || ItemStack.areEqual( a, b ); + return a == b || ItemStack.matches( a, b ); } @Nonnull @@ -173,11 +173,11 @@ public final class InventoryUtil { // If we've extracted for this first time, then limit the count to the maximum stack size. partialStack = extracted; - count = Math.min( count, extracted.getMaxCount() ); + count = Math.min( count, extracted.getMaxStackSize() ); } else { - partialStack.increment( extracted.getCount() ); + partialStack.grow( extracted.getCount() ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java b/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java index 1e36de8ca..eea17b41f 100644 --- a/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java @@ -5,34 +5,33 @@ */ package dan200.computercraft.shared.util; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.slot.Slot; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; public class InvisibleSlot extends Slot { - public InvisibleSlot( Inventory container, int slot ) + public InvisibleSlot( Container container, int slot ) { super( container, slot, 0, 0 ); } @Override - public boolean canInsert( @Nonnull ItemStack stack ) + public boolean mayPlace( @Nonnull ItemStack stack ) { return false; } @Override - public boolean canTakeItems( @Nonnull PlayerEntity player ) + public boolean mayPickup( @Nonnull Player player ) { return false; } @Override - public boolean isEnabled() + public boolean isActive() { return false; } diff --git a/src/main/java/dan200/computercraft/shared/util/ItemStorage.java b/src/main/java/dan200/computercraft/shared/util/ItemStorage.java index 2868ad395..b11f445d5 100644 --- a/src/main/java/dan200/computercraft/shared/util/ItemStorage.java +++ b/src/main/java/dan200/computercraft/shared/util/ItemStorage.java @@ -5,36 +5,35 @@ */ package dan200.computercraft.shared.util; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.SidedInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Direction; - import javax.annotation.Nonnull; +import net.minecraft.core.Direction; +import net.minecraft.world.Container; +import net.minecraft.world.WorldlyContainer; +import net.minecraft.world.item.ItemStack; /** * The most cutesy alternative of {@code IItemHandler} the world has ever seen. */ public interface ItemStorage { - static ItemStorage wrap( Inventory inventory ) + static ItemStorage wrap( Container inventory ) { return new InventoryWrapper( inventory ); } - static ItemStorage wrap( @Nonnull SidedInventory inventory, @Nonnull Direction facing ) + static ItemStorage wrap( @Nonnull WorldlyContainer inventory, @Nonnull Direction facing ) { return new SidedInventoryWrapper( inventory, facing ); } - static ItemStorage wrap( @Nonnull Inventory inventory, @Nonnull Direction facing ) + static ItemStorage wrap( @Nonnull Container inventory, @Nonnull Direction facing ) { - return inventory instanceof SidedInventory ? new SidedInventoryWrapper( (SidedInventory) inventory, facing ) : new InventoryWrapper( inventory ); + return inventory instanceof WorldlyContainer ? new SidedInventoryWrapper( (WorldlyContainer) inventory, facing ) : new InventoryWrapper( inventory ); } static boolean areStackable( @Nonnull ItemStack a, @Nonnull ItemStack b ) { - return a == b || (a.getItem() == b.getItem() && ItemStack.areNbtEqual( a, b )); + return a == b || (a.getItem() == b.getItem() && ItemStack.tagMatches( a, b )); } int size(); @@ -55,9 +54,9 @@ public interface ItemStorage class InventoryWrapper implements ItemStorage { - private final Inventory inventory; + private final Container inventory; - InventoryWrapper( Inventory inventory ) + InventoryWrapper( Container inventory ) { this.inventory = inventory; } @@ -65,21 +64,21 @@ public interface ItemStorage @Override public int size() { - return inventory.size(); + return inventory.getContainerSize(); } @Override @Nonnull public ItemStack getStack( int slot ) { - return inventory.getStack( slot ); + return inventory.getItem( slot ); } @Override @Nonnull public ItemStack take( int slot, int limit, @Nonnull ItemStack filter, boolean simulate ) { - ItemStack existing = inventory.getStack( slot ); + ItemStack existing = inventory.getItem( slot ); if( existing.isEmpty() || !canExtract( slot, existing ) || (!filter.isEmpty() && !areStackable( existing, filter )) ) { return ItemStack.EMPTY; @@ -114,23 +113,23 @@ public interface ItemStorage private void setAndDirty( int slot, @Nonnull ItemStack stack ) { - inventory.setStack( slot, stack ); - inventory.markDirty(); + inventory.setItem( slot, stack ); + inventory.setChanged(); } @Override @Nonnull public ItemStack store( int slot, @Nonnull ItemStack stack, boolean simulate ) { - if( stack.isEmpty() || !inventory.isValid( slot, stack ) ) + if( stack.isEmpty() || !inventory.canPlaceItem( slot, stack ) ) { return stack; } - ItemStack existing = inventory.getStack( slot ); + ItemStack existing = inventory.getItem( slot ); if( existing.isEmpty() ) { - int limit = Math.min( stack.getMaxCount(), inventory.getMaxCountPerStack() ); + int limit = Math.min( stack.getMaxStackSize(), inventory.getMaxStackSize() ); if( limit <= 0 ) { return stack; @@ -157,7 +156,7 @@ public interface ItemStorage } else if( areStackable( stack, existing ) ) { - int limit = Math.min( existing.getMaxCount(), inventory.getMaxCountPerStack() ) - existing.getCount(); + int limit = Math.min( existing.getMaxStackSize(), inventory.getMaxStackSize() ) - existing.getCount(); if( limit <= 0 ) { return stack; @@ -167,7 +166,7 @@ public interface ItemStorage { if( !simulate ) { - existing.increment( stack.getCount() ); + existing.grow( stack.getCount() ); setAndDirty( slot, existing ); } return ItemStack.EMPTY; @@ -175,10 +174,10 @@ public interface ItemStorage else { stack = stack.copy(); - stack.decrement( limit ); + stack.shrink( limit ); if( !simulate ) { - existing.increment( limit ); + existing.grow( limit ); setAndDirty( slot, existing ); } return stack; @@ -193,10 +192,10 @@ public interface ItemStorage class SidedInventoryWrapper extends InventoryWrapper { - private final SidedInventory inventory; + private final WorldlyContainer inventory; private final Direction facing; - SidedInventoryWrapper( SidedInventory inventory, Direction facing ) + SidedInventoryWrapper( WorldlyContainer inventory, Direction facing ) { super( inventory ); this.inventory = inventory; @@ -206,20 +205,20 @@ public interface ItemStorage @Override protected boolean canExtract( int slot, ItemStack stack ) { - return super.canExtract( slot, stack ) && inventory.canExtract( slot, stack, facing ); + return super.canExtract( slot, stack ) && inventory.canTakeItemThroughFace( slot, stack, facing ); } @Override public int size() { - return inventory.getAvailableSlots( facing ).length; + return inventory.getSlotsForFace( facing ).length; } @Nonnull @Override public ItemStack take( int slot, int limit, @Nonnull ItemStack filter, boolean simulate ) { - int[] slots = inventory.getAvailableSlots( facing ); + int[] slots = inventory.getSlotsForFace( facing ); return slot >= 0 && slot < slots.length ? super.take( slots[slot], limit, filter, simulate ) : ItemStack.EMPTY; } @@ -227,14 +226,14 @@ public interface ItemStorage @Override public ItemStack store( int slot, @Nonnull ItemStack stack, boolean simulate ) { - int[] slots = inventory.getAvailableSlots( facing ); + int[] slots = inventory.getSlotsForFace( facing ); if( slot < 0 || slot >= slots.length ) { return stack; } int mappedSlot = slots[slot]; - if( !inventory.canInsert( slot, stack, facing ) ) + if( !inventory.canPlaceItemThroughFace( slot, stack, facing ) ) { return stack; } diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 38d4fb494..80d3c67f3 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -40,7 +40,7 @@ public final class NBTUtil private NBTUtil() {} - private static NbtElement toNBTTag( Object object ) + private static Tag toNBTTag( Object object ) { if( object == null ) { @@ -48,25 +48,25 @@ public final class NBTUtil } if( object instanceof Boolean ) { - return NbtByte.of( (byte) ((boolean) (Boolean) object ? 1 : 0) ); + return ByteTag.valueOf( (byte) ((boolean) (Boolean) object ? 1 : 0) ); } if( object instanceof Number ) { - return NbtDouble.of( ((Number) object).doubleValue() ); + return DoubleTag.valueOf( ((Number) object).doubleValue() ); } if( object instanceof String ) { - return NbtString.of( object.toString() ); + return StringTag.valueOf( object.toString() ); } if( object instanceof Map ) { Map m = (Map) object; - NbtCompound nbt = new NbtCompound(); + CompoundTag nbt = new CompoundTag(); int i = 0; for( Map.Entry entry : m.entrySet() ) { - NbtElement key = toNBTTag( entry.getKey() ); - NbtElement value = toNBTTag( entry.getKey() ); + Tag key = toNBTTag( entry.getKey() ); + Tag value = toNBTTag( entry.getKey() ); if( key != null && value != null ) { nbt.put( "k" + i, key ); @@ -81,18 +81,18 @@ public final class NBTUtil return null; } - public static NbtCompound encodeObjects( Object[] objects ) + public static CompoundTag encodeObjects( Object[] objects ) { if( objects == null || objects.length <= 0 ) { return null; } - NbtCompound nbt = new NbtCompound(); + CompoundTag nbt = new CompoundTag(); nbt.putInt( "len", objects.length ); for( int i = 0; i < objects.length; i++ ) { - NbtElement child = toNBTTag( objects[i] ); + Tag child = toNBTTag( objects[i] ); if( child != null ) { nbt.put( Integer.toString( i ), child ); @@ -101,23 +101,23 @@ public final class NBTUtil return nbt; } - private static Object fromNBTTag( NbtElement tag ) + private static Object fromNBTTag( Tag tag ) { if( tag == null ) { return null; } - switch( tag.getType() ) + switch( tag.getId() ) { case TAG_BYTE: - return ((NbtByte) tag).byteValue() > 0; + return ((ByteTag) tag).getAsByte() > 0; case TAG_DOUBLE: - return ((NbtDouble) tag).doubleValue(); + return ((DoubleTag) tag).getAsDouble(); default: case TAG_STRING: - return tag.asString(); + return tag.getAsString(); case TAG_COMPOUND: - NbtCompound c = (NbtCompound) tag; + CompoundTag c = (CompoundTag) tag; int len = c.getInt( "len" ); Map map = new HashMap<>( len ); for( int i = 0; i < len; i++ ) @@ -133,31 +133,31 @@ public final class NBTUtil } } - public static Object toLua( NbtElement tag ) + public static Object toLua( Tag tag ) { if( tag == null ) { return null; } - byte typeID = tag.getType(); + byte typeID = tag.getId(); switch( typeID ) { case TAG_BYTE: case TAG_SHORT: case TAG_INT: case TAG_LONG: - return ((AbstractNbtNumber) tag).longValue(); + return ((NumericTag) tag).getAsLong(); case TAG_FLOAT: case TAG_DOUBLE: - return ((AbstractNbtNumber) tag).doubleValue(); + return ((NumericTag) tag).getAsDouble(); case TAG_STRING: // String - return tag.asString(); + return tag.getAsString(); case TAG_COMPOUND: // Compound { - NbtCompound compound = (NbtCompound) tag; - Map map = new HashMap<>( compound.getSize() ); - for( String key : compound.getKeys() ) + CompoundTag compound = (CompoundTag) tag; + Map map = new HashMap<>( compound.size() ); + for( String key : compound.getAllKeys() ) { Object value = toLua( compound.get( key ) ); if( value != null ) @@ -169,7 +169,7 @@ public final class NBTUtil } case TAG_LIST: { - NbtList list = (NbtList) tag; + ListTag list = (ListTag) tag; Map map = new HashMap<>( list.size() ); for( int i = 0; i < list.size(); i++ ) { @@ -179,7 +179,7 @@ public final class NBTUtil } case TAG_BYTE_ARRAY: { - byte[] array = ((NbtByteArray) tag).getByteArray(); + byte[] array = ((ByteArrayTag) tag).getAsByteArray(); Map map = new HashMap<>( array.length ); for( int i = 0; i < array.length; i++ ) { @@ -188,7 +188,7 @@ public final class NBTUtil return map; } case TAG_INT_ARRAY: - int[] array = ((NbtIntArray) tag).getIntArray(); + int[] array = ((IntArrayTag) tag).getAsIntArray(); Map map = new HashMap<>( array.length ); for( int i = 0; i < array.length; i++ ) { @@ -201,7 +201,7 @@ public final class NBTUtil } } - public static Object[] decodeObjects( NbtCompound tag ) + public static Object[] decodeObjects( CompoundTag tag ) { int len = tag.getInt( "len" ); if( len <= 0 ) @@ -222,7 +222,7 @@ public final class NBTUtil } @Nullable - public static String getNBTHash( @Nullable NbtCompound tag ) + public static String getNBTHash( @Nullable CompoundTag tag ) { if( tag == null ) { diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 2b4d65b52..4f4713f30 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.util; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; public class Palette { @@ -61,7 +61,7 @@ public class Palette return null; } - public void write( PacketByteBuf buffer ) + public void write( FriendlyByteBuf buffer ) { for( double[] colour : colours ) { @@ -72,7 +72,7 @@ public class Palette } } - public void read( PacketByteBuf buffer ) + public void read( FriendlyByteBuf buffer ) { for( double[] colour : colours ) { @@ -83,7 +83,7 @@ public class Palette } } - public NbtCompound writeToNBT( NbtCompound nbt ) + public CompoundTag writeToNBT( CompoundTag nbt ) { int[] rgb8 = new int[colours.length]; @@ -105,7 +105,7 @@ public class Palette return (r << 16) | (g << 8) | b; } - public void readFromNBT( NbtCompound nbt ) + public void readFromNBT( CompoundTag nbt ) { if( !nbt.contains( "term_palette" ) ) { diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index 167933b8e..42d8d651c 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -11,14 +11,13 @@ import com.google.common.collect.Sets; import com.google.gson.*; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dan200.computercraft.shared.computer.core.ComputerFamily; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.StringNbtReader; -import net.minecraft.recipe.Ingredient; -import net.minecraft.util.JsonHelper; -import net.minecraft.util.collection.DefaultedList; - import java.util.Map; import java.util.Set; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.TagParser; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; // TODO: Replace some things with Forge?? @@ -30,7 +29,7 @@ public final class RecipeUtil public static ShapedTemplate getTemplate( JsonObject json ) { Map ingMap = Maps.newHashMap(); - for( Map.Entry entry : JsonHelper.getObject( json, "key" ) + for( Map.Entry entry : GsonHelper.getAsJsonObject( json, "key" ) .entrySet() ) { if( entry.getKey() @@ -49,7 +48,7 @@ public final class RecipeUtil ingMap.put( ' ', Ingredient.EMPTY ); - JsonArray patternJ = JsonHelper.getArray( json, "pattern" ); + JsonArray patternJ = GsonHelper.getAsJsonArray( json, "pattern" ); if( patternJ.size() == 0 ) { @@ -59,7 +58,7 @@ public final class RecipeUtil String[] pattern = new String[patternJ.size()]; for( int x = 0; x < pattern.length; x++ ) { - String line = JsonHelper.asString( patternJ.get( x ), "pattern[" + x + "]" ); + String line = GsonHelper.convertToString( patternJ.get( x ), "pattern[" + x + "]" ); if( x > 0 && pattern[0].length() != line.length() ) { throw new JsonSyntaxException( "Invalid pattern: each row must be the same width" ); @@ -69,7 +68,7 @@ public final class RecipeUtil int width = pattern[0].length(); int height = pattern.length; - DefaultedList ingredients = DefaultedList.ofSize( width * height, Ingredient.EMPTY ); + NonNullList ingredients = NonNullList.withSize( width * height, Ingredient.EMPTY ); Set missingKeys = Sets.newHashSet( ingMap.keySet() ); missingKeys.remove( ' ' ); @@ -99,7 +98,7 @@ public final class RecipeUtil public static ComputerFamily getFamily( JsonObject json, String name ) { - String familyName = JsonHelper.getString( json, name ); + String familyName = GsonHelper.getAsString( json, name ); for( ComputerFamily family : ComputerFamily.values() ) { if( family.name() @@ -119,7 +118,7 @@ public final class RecipeUtil { try { - itemStack.setNbt( StringNbtReader.parse( nbtElement.isJsonObject() ? GSON.toJson( nbtElement ) : JsonHelper.asString( nbtElement, "nbt" ) ) ); + itemStack.setTag( TagParser.parseTag( nbtElement.isJsonObject() ? GSON.toJson( nbtElement ) : GsonHelper.convertToString( nbtElement, "nbt" ) ) ); } catch( CommandSyntaxException e ) { @@ -132,9 +131,9 @@ public final class RecipeUtil { public final int width; public final int height; - public final DefaultedList ingredients; + public final NonNullList ingredients; - public ShapedTemplate( int width, int height, DefaultedList ingredients ) + public ShapedTemplate( int width, int height, NonNullList ingredients ) { this.width = width; this.height = height; diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 30de0b841..afe99a065 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -9,18 +9,18 @@ package dan200.computercraft.shared.util; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; -import net.minecraft.sound.SoundEvent; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; public final class RecordUtil { private RecordUtil() {} - public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos ) + public static void playRecord( SoundEvent record, String recordInfo, Level world, BlockPos pos ) { NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); - NetworkHandler.sendToAllAround( packet, world, Vec3d.ofCenter( pos ), 64 ); + NetworkHandler.sendToAllAround( packet, world, Vec3.atCenterOf( pos ), 64 ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index ca27dcde5..5de8bdd7f 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -6,19 +6,19 @@ package dan200.computercraft.shared.util; -import net.minecraft.block.BlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; public final class RedstoneUtil { - public static void propagateRedstoneOutput( World world, BlockPos pos, Direction side ) + public static void propagateRedstoneOutput( Level world, BlockPos pos, Direction side ) { // Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors BlockState block = world.getBlockState( pos ); - BlockPos neighbourPos = pos.offset( side ); - world.updateNeighbor( neighbourPos, block.getBlock(), pos ); - world.updateNeighborsExcept( neighbourPos, block.getBlock(), side.getOpposite() ); + BlockPos neighbourPos = pos.relative( side ); + world.neighborChanged( neighbourPos, block.getBlock(), pos ); + world.updateNeighborsAtExceptFromFacing( neighbourPos, block.getBlock(), side.getOpposite() ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java index 4e9141232..1329f1352 100644 --- a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java +++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java @@ -6,10 +6,10 @@ package dan200.computercraft.shared.util; -import net.minecraft.screen.PropertyDelegate; +import net.minecraft.world.inventory.ContainerData; @FunctionalInterface -public interface SingleIntArray extends PropertyDelegate +public interface SingleIntArray extends ContainerData { @Override default int get( int property ) @@ -25,7 +25,7 @@ public interface SingleIntArray extends PropertyDelegate } @Override - default int size() + default int getCount() { return 1; } diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 98e3a8036..31917f7ad 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -8,13 +8,12 @@ package dan200.computercraft.shared.util; import com.google.common.collect.MapMaker; import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - import java.util.Collections; import java.util.Iterator; import java.util.Set; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; /** * We use this when modems and other peripherals change a block in a different thread. @@ -30,8 +29,8 @@ public final class TickScheduler public static void schedule( TileGeneric tile ) { - World world = tile.getWorld(); - if( world != null && !world.isClient ) + Level world = tile.getLevel(); + if( world != null && !world.isClientSide ) { toTick.add( tile ); } @@ -45,14 +44,14 @@ public final class TickScheduler BlockEntity tile = iterator.next(); iterator.remove(); - World world = tile.getWorld(); - BlockPos pos = tile.getPos(); + Level world = tile.getLevel(); + BlockPos pos = tile.getBlockPos(); - if( world != null && pos != null && world.isChunkLoaded( pos ) && world.getBlockEntity( pos ) == tile ) + if( world != null && pos != null && world.hasChunkAt( pos ) && world.getBlockEntity( pos ) == tile ) { - world.getBlockTickScheduler() - .schedule( pos, - tile.getCachedState() + world.getBlockTicks() + .scheduleTick( pos, + tile.getBlockState() .getBlock(), 0 ); } diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index aa1e50940..bd9086102 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -6,21 +6,20 @@ package dan200.computercraft.shared.util; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.slot.Slot; - import javax.annotation.Nonnull; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; public class ValidatingSlot extends Slot { - public ValidatingSlot( Inventory inventoryIn, int index, int xPosition, int yPosition ) + public ValidatingSlot( Container inventoryIn, int index, int xPosition, int yPosition ) { super( inventoryIn, index, xPosition, yPosition ); } @Override - public boolean canInsert( @Nonnull ItemStack stack ) + public boolean mayPlace( @Nonnull ItemStack stack ) { return true; // inventory.isItemValidForSlot( slotNumber, stack ); } diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java index 7703ab8ef..414c88c3e 100644 --- a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java @@ -6,14 +6,14 @@ package dan200.computercraft.shared.util; -import net.minecraft.block.BlockState; -import net.minecraft.fluid.FluidState; -import net.minecraft.fluid.Fluids; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.state.property.BooleanProperty; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.WorldAccess; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; /** * Represents a block which can be filled with water @@ -22,43 +22,43 @@ import net.minecraft.world.WorldAccess; */ public final class WaterloggableHelpers { - public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED; + public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; private WaterloggableHelpers() { } /** - * Call from {@link net.minecraft.block.Block#getFluidState(BlockState)}. + * Call from {@link net.minecraft.world.level.block.Block#getFluidState(BlockState)}. * * @param state The current state * @return This waterlogged block's current fluid */ public static FluidState getWaterloggedFluidState( BlockState state ) { - return state.get( WATERLOGGED ) ? Fluids.WATER.getStill( false ) : Fluids.EMPTY.getDefaultState(); + return state.getValue( WATERLOGGED ) ? Fluids.WATER.getSource( false ) : Fluids.EMPTY.defaultFluidState(); } /** - * Call from {@link net.minecraft.block.Block#updatePostPlacement(BlockState, Direction, BlockState, IWorld, BlockPos, BlockPos)}. + * Call from {@link net.minecraft.world.level.block.Block#updatePostPlacement(BlockState, Direction, BlockState, IWorld, BlockPos, BlockPos)}. * * @param state The current state * @param world The position of this block * @param pos The world this block exists in */ - public static void updateWaterloggedPostPlacement( BlockState state, WorldAccess world, BlockPos pos ) + public static void updateWaterloggedPostPlacement( BlockState state, LevelAccessor world, BlockPos pos ) { - if( state.get( WATERLOGGED ) ) + if( state.getValue( WATERLOGGED ) ) { - world.getFluidTickScheduler() - .schedule( pos, Fluids.WATER, Fluids.WATER.getTickRate( world ) ); + world.getLiquidTicks() + .scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickDelay( world ) ); } } - public static boolean getWaterloggedStateForPlacement( ItemPlacementContext context ) + public static boolean getWaterloggedStateForPlacement( BlockPlaceContext context ) { - return context.getWorld() - .getFluidState( context.getBlockPos() ) - .getFluid() == Fluids.WATER; + return context.getLevel() + .getFluidState( context.getClickedPos() ) + .getType() == Fluids.WATER; } } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 33c153401..a962bef3d 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -8,17 +8,23 @@ package dan200.computercraft.shared.util; import com.google.common.base.Predicate; import com.google.common.collect.MapMaker; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.entity.*; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.world.RaycastContext; -import net.minecraft.world.World; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -28,15 +34,15 @@ import java.util.Map; public final class WorldUtil { @SuppressWarnings( "Guava" ) - private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.collides(); + private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable(); - private static final Map entityCache = new MapMaker().weakKeys() + private static final Map entityCache = new MapMaker().weakKeys() .weakValues() .makeMap(); - public static boolean isLiquidBlock( World world, BlockPos pos ) + public static boolean isLiquidBlock( Level world, BlockPos pos ) { - if( !world.isInBuildLimit( pos ) ) + if( !world.isInWorldBounds( pos ) ) { return false; } @@ -45,33 +51,33 @@ public final class WorldUtil .isLiquid(); } - public static boolean isVecInside( VoxelShape shape, Vec3d vec ) + public static boolean isVecInside( VoxelShape shape, Vec3 vec ) { if( shape.isEmpty() ) { return false; } // AxisAlignedBB.contains, but without strict inequalities. - Box bb = shape.getBoundingBox(); + AABB bb = shape.bounds(); return vec.x >= bb.minX && vec.x <= bb.maxX && vec.y >= bb.minY && vec.y <= bb.maxY && vec.z >= bb.minZ && vec.z <= bb.maxZ; } - public static Pair rayTraceEntities( World world, Vec3d vecStart, Vec3d vecDir, double distance ) + public static Pair rayTraceEntities( Level world, Vec3 vecStart, Vec3 vecDir, double distance ) { - Vec3d vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); + Vec3 vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); // Raycast for blocks Entity collisionEntity = getEntity( world ); - collisionEntity.setPosition( vecStart.x, vecStart.y, vecStart.z ); - RaycastContext context = new RaycastContext( vecStart, + collisionEntity.setPos( vecStart.x, vecStart.y, vecStart.z ); + ClipContext context = new ClipContext( vecStart, vecEnd, - RaycastContext.ShapeType.COLLIDER, - RaycastContext.FluidHandling.NONE, + ClipContext.Block.COLLIDER, + ClipContext.Fluid.NONE, collisionEntity ); - HitResult result = world.raycast( context ); + HitResult result = world.clip( context ); if( result != null && result.getType() == HitResult.Type.BLOCK ) { - distance = vecStart.distanceTo( result.getPos() ); + distance = vecStart.distanceTo( result.getLocation() ); vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); } @@ -79,7 +85,7 @@ public final class WorldUtil float xStretch = Math.abs( vecDir.x ) > 0.25f ? 0.0f : 1.0f; float yStretch = Math.abs( vecDir.y ) > 0.25f ? 0.0f : 1.0f; float zStretch = Math.abs( vecDir.z ) > 0.25f ? 0.0f : 1.0f; - Box bigBox = new Box( Math.min( vecStart.x, vecEnd.x ) - 0.375f * xStretch, + AABB bigBox = new AABB( Math.min( vecStart.x, vecEnd.x ) - 0.375f * xStretch, Math.min( vecStart.y, vecEnd.y ) - 0.375f * yStretch, Math.min( vecStart.z, vecEnd.z ) - 0.375f * zStretch, Math.max( vecStart.x, vecEnd.x ) + 0.375f * xStretch, @@ -88,10 +94,10 @@ public final class WorldUtil Entity closest = null; double closestDist = 99.0; - List list = world.getEntitiesByClass( Entity.class, bigBox, CAN_COLLIDE ); + List list = world.getEntitiesOfClass( Entity.class, bigBox, CAN_COLLIDE ); for( Entity entity : list ) { - Box littleBox = entity.getBoundingBox(); + AABB littleBox = entity.getBoundingBox(); if( littleBox.contains( vecStart ) ) { closest = entity; @@ -99,7 +105,7 @@ public final class WorldUtil continue; } - Vec3d littleBoxResult = littleBox.raycast( vecStart, vecEnd ) + Vec3 littleBoxResult = littleBox.clip( vecStart, vecEnd ) .orElse( null ); if( littleBoxResult != null ) { @@ -121,13 +127,13 @@ public final class WorldUtil } if( closest != null && closestDist <= distance ) { - Vec3d closestPos = vecStart.add( vecDir.x * closestDist, vecDir.y * closestDist, vecDir.z * closestDist ); + Vec3 closestPos = vecStart.add( vecDir.x * closestDist, vecDir.y * closestDist, vecDir.z * closestDist ); return Pair.of( closest, closestPos ); } return null; } - private static synchronized Entity getEntity( World world ) + private static synchronized Entity getEntity( Level world ) { // TODO: It'd be nice if we could avoid this. Maybe always use the turtle player (if it's available). Entity entity = entityCache.get( world ); @@ -140,45 +146,45 @@ public final class WorldUtil { @Nonnull @Override - public EntityDimensions getDimensions( @Nonnull EntityPose pose ) + public EntityDimensions getDimensions( @Nonnull Pose pose ) { return EntityDimensions.fixed( 0, 0 ); } }; - entity.noClip = true; - entity.calculateDimensions(); + entity.noPhysics = true; + entity.refreshDimensions(); entityCache.put( world, entity ); return entity; } - public static Vec3d getRayEnd( PlayerEntity player ) + public static Vec3 getRayEnd( Player player ) { double reach = 5; - Vec3d look = player.getRotationVector(); + Vec3 look = player.getLookAngle(); return getRayStart( player ).add( look.x * reach, look.y * reach, look.z * reach ); } - public static Vec3d getRayStart( LivingEntity entity ) + public static Vec3 getRayStart( LivingEntity entity ) { - return entity.getCameraPosVec( 1 ); + return entity.getEyePosition( 1 ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, BlockPos pos ) + public static void dropItemStack( @Nonnull ItemStack stack, Level world, BlockPos pos ) { dropItemStack( stack, world, pos, null ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, BlockPos pos, Direction direction ) + public static void dropItemStack( @Nonnull ItemStack stack, Level world, BlockPos pos, Direction direction ) { double xDir; double yDir; double zDir; if( direction != null ) { - xDir = direction.getOffsetX(); - yDir = direction.getOffsetY(); - zDir = direction.getOffsetZ(); + xDir = direction.getStepX(); + yDir = direction.getStepY(); + zDir = direction.getStepZ(); } else { @@ -190,23 +196,23 @@ public final class WorldUtil double xPos = pos.getX() + 0.5 + xDir * 0.4; double yPos = pos.getY() + 0.5 + yDir * 0.4; double zPos = pos.getZ() + 0.5 + zDir * 0.4; - dropItemStack( stack, world, new Vec3d( xPos, yPos, zPos ), xDir, yDir, zDir ); + dropItemStack( stack, world, new Vec3( xPos, yPos, zPos ), xDir, yDir, zDir ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos, double xDir, double yDir, double zDir ) + public static void dropItemStack( @Nonnull ItemStack stack, Level world, Vec3 pos, double xDir, double yDir, double zDir ) { ItemEntity item = new ItemEntity( world, pos.x, pos.y, pos.z, stack.copy() ); - item.setVelocity( xDir * 0.7 + world.getRandom() + item.setDeltaMovement( xDir * 0.7 + world.getRandom() .nextFloat() * 0.2 - 0.1, yDir * 0.7 + world.getRandom() .nextFloat() * 0.2 - 0.1, zDir * 0.7 + world.getRandom() .nextFloat() * 0.2 - 0.1 ); - item.setToDefaultPickupDelay(); - world.spawnEntity( item ); + item.setDefaultPickUpDelay(); + world.addFreshEntity( item ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos ) + public static void dropItemStack( @Nonnull ItemStack stack, Level world, Vec3 pos ) { dropItemStack( stack, world, pos, 0.0, 0.0, 0.0 ); } diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index ccbf63218..398e983f4 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -11,10 +11,9 @@ import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - import javax.annotation.Nonnull; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import java.util.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -59,8 +58,8 @@ public final class WiredNetwork implements IWiredNetwork TransmitPoint point; while( (point = transmitTo.pollFirst()) != null ) { - World world = point.node.element.getWorld(); - Vec3d position = point.node.element.getPosition(); + Level world = point.node.element.getWorld(); + Vec3 position = point.node.element.getPosition(); for( WiredNode neighbour : point.node.neighbours ) { TransmitPoint neighbourPoint = points.get( neighbour ); From 73e3e237ade09a5c642d633924e1210a5d515a98 Mon Sep 17 00:00:00 2001 From: Merith Date: Sat, 27 Nov 2021 04:16:29 +0000 Subject: [PATCH 2/5] apply squiddev mojmap patches, temporarily disable checkstyle --- build.gradle | 11 ++- .../computercraft/ComputerCraftAPIImpl.java | 5 +- .../computercraft/api/ComputerCraftAPI.java | 5 +- .../computercraft/api/IUpgradeBase.java | 3 +- .../api/client/TransformedModel.java | 7 +- .../computercraft/api/filesystem/IMount.java | 3 +- .../api/filesystem/IWritableMount.java | 3 +- .../computercraft/api/lua/GenericSource.java | 3 +- .../computercraft/api/media/IMedia.java | 5 +- .../api/media/IMediaProvider.java | 3 +- .../api/network/IPacketReceiver.java | 3 +- .../api/network/IPacketSender.java | 3 +- .../api/peripheral/IComputerAccess.java | 3 +- .../api/peripheral/IPeripheralProvider.java | 3 +- .../api/peripheral/IPeripheralTile.java | 5 +- .../api/pocket/AbstractPocketUpgrade.java | 3 +- .../api/pocket/IPocketAccess.java | 5 +- .../api/pocket/IPocketUpgrade.java | 3 +- .../redstone/IBundledRedstoneProvider.java | 3 +- .../api/turtle/AbstractTurtleUpgrade.java | 3 +- .../computercraft/api/turtle/FakePlayer.java | 4 +- .../api/turtle/ITurtleAccess.java | 5 +- .../api/turtle/ITurtleUpgrade.java | 1 + .../api/turtle/event/TurtleAttackEvent.java | 3 +- .../api/turtle/event/TurtleBlockEvent.java | 3 +- .../turtle/event/TurtleInspectItemEvent.java | 3 +- .../turtle/event/TurtleInventoryEvent.java | 5 +- .../api/turtle/event/TurtleRefuelEvent.java | 3 +- .../computercraft/client/ClientRegistry.java | 7 +- .../client/ClientTableFormatter.java | 12 +-- .../computercraft/client/SoundManager.java | 7 +- .../client/gui/ComputerScreenBase.java | 6 +- .../client/gui/FixedWidthFontRenderer.java | 12 +-- .../computercraft/client/gui/GuiComputer.java | 7 +- .../client/gui/GuiDiskDrive.java | 3 +- .../computercraft/client/gui/GuiPrinter.java | 3 +- .../computercraft/client/gui/GuiPrintout.java | 6 +- .../computercraft/client/gui/GuiTurtle.java | 3 +- .../client/gui/NoTermComputerScreen.java | 6 +- .../client/gui/OptionScreen.java | 3 +- .../client/gui/widgets/ComputerSidebar.java | 5 +- .../gui/widgets/DynamicImageButton.java | 3 +- .../client/gui/widgets/WidgetTerminal.java | 5 +- .../proxy/ComputerCraftProxyClient.java | 1 + .../client/render/CableHighlightRenderer.java | 1 - .../client/render/ComputerBorderRenderer.java | 3 +- .../client/render/ItemMapLikeRenderer.java | 14 ++-- .../client/render/ItemPocketRenderer.java | 7 +- .../client/render/ItemPrintoutRenderer.java | 7 +- .../client/render/ModelTransformer.java | 7 +- .../render/MonitorHighlightRenderer.java | 14 ++-- .../render/MonitorTextureBufferShader.java | 4 +- .../client/render/PrintoutRenderer.java | 5 +- .../client/render/RenderTypes.java | 2 +- .../render/TileEntityMonitorRenderer.java | 11 +-- .../render/TileEntityTurtleRenderer.java | 9 ++- .../client/render/TurtleModelLoader.java | 9 +-- .../client/render/TurtleMultiModel.java | 1 + .../client/render/TurtlePlayerRenderer.java | 5 +- .../client/render/TurtleSmartItemModel.java | 1 + .../core/computer/ComputerSide.java | 3 +- .../core/computer/MainThreadExecutor.java | 3 +- .../core/filesystem/ResourceMount.java | 5 +- .../computercraft/core/terminal/Terminal.java | 3 +- ...udAccess.java => ChatComponentAccess.java} | 4 +- ...ess.java => ItemInHandRendererAccess.java} | 8 +- ...thAccess.java => LevelResourceAccess.java} | 4 +- .../fabric/mixin/MinecraftServerAccess.java | 8 +- .../fabric/mixin/MixinBlock.java | 11 +-- .../fabric/mixin/MixinEntity.java | 6 +- .../fabric/mixin/MixinGameRenderer.java | 10 +-- .../fabric/mixin/MixinHandledScreen.java | 38 --------- ...derer.java => MixinItemFrameRenderer.java} | 4 +- ...erer.java => MixinItemInHandRenderer.java} | 22 +---- .../fabric/mixin/MixinLanguage.java | 19 ++--- .../{MixinWorld.java => MixinLevel.java} | 25 +++--- ...dRenderer.java => MixinLevelRenderer.java} | 23 ++---- .../fabric/mixin/MixinMatrix4f.java | 81 +++++++++++-------- ...necraftClient.java => MixinMinecraft.java} | 10 +-- ...ServerWorld.java => MixinServerLevel.java} | 6 +- ...er.java => MixinServerPlayerGameMode.java} | 10 ++- .../fabric/mixin/SignBlockEntityAccess.java | 18 ----- .../computercraft/shared/BundledRedstone.java | 3 +- .../shared/ComputerCraftRegistry.java | 10 +-- .../computercraft/shared/MediaProviders.java | 3 +- .../computercraft/shared/Peripherals.java | 5 +- .../computercraft/shared/PocketUpgrades.java | 1 + .../computercraft/shared/TurtleUpgrades.java | 3 +- .../shared/command/ClientCommands.java | 3 +- .../shared/command/CommandComputerCraft.java | 1 + .../shared/command/CommandUtils.java | 9 ++- .../shared/command/UserLevel.java | 1 + .../arguments/ComputerArgumentType.java | 3 +- .../arguments/ComputersArgumentType.java | 7 +- .../command/arguments/RepeatArgumentType.java | 7 +- .../command/builder/CommandBuilder.java | 3 +- .../builder/HelpingArgumentBuilder.java | 11 +-- .../shared/command/text/ChatHelpers.java | 8 +- .../command/text/ServerTableFormatter.java | 6 +- .../shared/command/text/TableBuilder.java | 5 +- .../shared/command/text/TableFormatter.java | 6 +- .../shared/common/BlockGeneric.java | 11 +-- .../shared/common/ColourableRecipe.java | 5 +- .../shared/common/ContainerHeldItem.java | 1 + .../DefaultBundledRedstoneProvider.java | 3 +- .../shared/common/ServerTerminal.java | 3 +- .../shared/common/TileGeneric.java | 1 + .../shared/computer/apis/CommandAPI.java | 1 + .../shared/computer/blocks/BlockComputer.java | 17 ++-- .../computer/blocks/BlockComputerBase.java | 9 ++- .../computer/blocks/TileCommandComputer.java | 1 + .../shared/computer/blocks/TileComputer.java | 5 +- .../computer/blocks/TileComputerBase.java | 1 + .../shared/computer/core/ComputerState.java | 3 +- .../computer/core/IContainerComputer.java | 3 +- .../shared/computer/core/ServerComputer.java | 1 + .../ComputerMenuWithoutInventory.java | 3 +- .../inventory/ContainerComputerBase.java | 7 +- .../inventory/ContainerViewComputer.java | 3 +- .../computer/items/ComputerItemFactory.java | 3 +- .../shared/computer/items/IComputerItem.java | 3 +- .../shared/computer/items/ItemComputer.java | 3 +- .../computer/items/ItemComputerBase.java | 5 +- .../recipe/ComputerConvertRecipe.java | 3 +- .../computer/recipe/ComputerFamilyRecipe.java | 5 +- .../recipe/ComputerUpgradeRecipe.java | 3 +- .../data/BlockNamedEntityLootCondition.java | 3 +- .../data/ConstantLootConditionSerializer.java | 5 +- .../data/HasComputerIdLootCondition.java | 3 +- .../data/PlayerCreativeLootCondition.java | 3 +- .../integration/ModMenuIntegration.java | 2 +- .../shared/media/items/ItemDisk.java | 5 +- .../shared/media/items/ItemPrintout.java | 3 +- .../shared/media/items/ItemTreasureDisk.java | 5 +- .../shared/media/items/RecordMedia.java | 3 +- .../shared/media/recipes/DiskRecipe.java | 5 +- .../shared/media/recipes/PrintoutRecipe.java | 7 +- .../shared/network/NetworkHandler.java | 3 +- .../shared/network/NetworkMessage.java | 1 + .../client/ChatTableClientMessage.java | 1 + .../network/client/ComputerClientMessage.java | 3 +- .../client/ComputerDataClientMessage.java | 1 + .../client/ComputerTerminalClientMessage.java | 1 + .../network/client/MonitorClientMessage.java | 1 + .../client/PlayRecordClientMessage.java | 1 + .../client/SpeakerMoveClientMessage.java | 1 + .../client/SpeakerPlayClientMessage.java | 1 + .../client/SpeakerStopClientMessage.java | 1 + .../shared/network/client/TerminalState.java | 3 +- .../network/client/UploadResultMessage.java | 1 + .../network/container/ContainerData.java | 4 +- .../container/HeldItemContainerData.java | 3 +- .../container/ViewComputerContainerData.java | 3 +- .../server/ComputerActionServerMessage.java | 1 + .../network/server/ComputerServerMessage.java | 1 + .../network/server/ContinueUploadMessage.java | 1 + .../network/server/KeyEventServerMessage.java | 1 + .../server/MouseEventServerMessage.java | 1 + .../server/QueueEventServerMessage.java | 1 + .../server/RequestComputerMessage.java | 1 + .../network/server/UploadFileMessage.java | 1 + .../commandblock/CommandBlockPeripheral.java | 3 +- .../peripheral/diskdrive/BlockDiskDrive.java | 5 +- .../diskdrive/ContainerDiskDrive.java | 3 +- .../diskdrive/DiskDrivePeripheral.java | 3 +- .../peripheral/diskdrive/DiskDriveState.java | 3 +- .../peripheral/diskdrive/TileDiskDrive.java | 5 +- .../peripheral/generic/GenericPeripheral.java | 5 +- .../generic/GenericPeripheralProvider.java | 5 +- .../peripheral/generic/data/BlockData.java | 3 +- .../peripheral/generic/data/DataHelpers.java | 7 +- .../peripheral/generic/data/ItemData.java | 5 +- .../generic/methods/InventoryMethods.java | 7 +- .../peripheral/modem/ModemPeripheral.java | 3 +- .../shared/peripheral/modem/ModemShapes.java | 3 +- .../peripheral/modem/wired/BlockCable.java | 12 +-- .../modem/wired/BlockWiredModemFull.java | 3 +- .../modem/wired/CableModemVariant.java | 5 +- .../peripheral/modem/wired/CableShapes.java | 17 ++-- .../modem/wired/ItemBlockCable.java | 3 +- .../peripheral/modem/wired/TileCable.java | 5 +- .../modem/wired/TileWiredModemFull.java | 3 +- .../wired/WiredModemLocalPeripheral.java | 5 +- .../modem/wired/WiredModemPeripheral.java | 3 +- .../modem/wireless/BlockWirelessModem.java | 21 ++--- .../modem/wireless/TileWirelessModem.java | 3 +- .../peripheral/monitor/BlockMonitor.java | 11 +-- .../peripheral/monitor/MonitorEdgeState.java | 3 +- .../peripheral/monitor/TileMonitor.java | 3 +- .../peripheral/printer/BlockPrinter.java | 5 +- .../peripheral/printer/ContainerPrinter.java | 3 +- .../peripheral/printer/TilePrinter.java | 11 +-- .../peripheral/speaker/BlockSpeaker.java | 3 +- .../peripheral/speaker/SpeakerPeripheral.java | 1 + .../peripheral/speaker/TileSpeaker.java | 5 +- .../pocket/core/PocketServerComputer.java | 5 +- .../inventory/PocketComputerMenuProvider.java | 1 + .../pocket/items/ItemPocketComputer.java | 1 + .../items/PocketComputerItemFactory.java | 3 +- .../pocket/peripherals/PocketModem.java | 5 +- .../peripherals/PocketModemPeripheral.java | 3 +- .../pocket/peripherals/PocketSpeaker.java | 5 +- .../recipes/PocketComputerUpgradeRecipe.java | 7 +- .../proxy/ComputerCraftProxyCommon.java | 5 +- .../shared/turtle/FurnaceRefuelHandler.java | 3 +- .../shared/turtle/SignInspectHandler.java | 8 +- .../shared/turtle/apis/TurtleAPI.java | 3 +- .../shared/turtle/blocks/BlockTurtle.java | 6 +- .../shared/turtle/blocks/TileTurtle.java | 31 +++---- .../shared/turtle/core/TurtleBrain.java | 5 +- .../turtle/core/TurtleCompareCommand.java | 3 +- .../turtle/core/TurtleCompareToCommand.java | 3 +- .../turtle/core/TurtleCraftCommand.java | 3 +- .../turtle/core/TurtleDetectCommand.java | 3 +- .../shared/turtle/core/TurtleDropCommand.java | 3 +- .../turtle/core/TurtleEquipCommand.java | 3 +- .../turtle/core/TurtleInspectCommand.java | 3 +- .../shared/turtle/core/TurtleMoveCommand.java | 3 +- .../turtle/core/TurtlePlaceCommand.java | 10 +-- .../shared/turtle/core/TurtlePlayer.java | 5 +- .../turtle/core/TurtleRefuelCommand.java | 3 +- .../shared/turtle/core/TurtleSuckCommand.java | 3 +- .../turtle/core/TurtleTransferToCommand.java | 3 +- .../turtle/inventory/ContainerTurtle.java | 3 +- .../shared/turtle/items/ITurtleItem.java | 5 +- .../shared/turtle/items/ItemTurtle.java | 3 +- .../turtle/items/TurtleItemFactory.java | 3 +- .../shared/turtle/recipes/TurtleRecipe.java | 3 +- .../turtle/recipes/TurtleUpgradeRecipe.java | 7 +- .../turtle/upgrades/TurtleCraftingTable.java | 1 + .../shared/turtle/upgrades/TurtleHoe.java | 3 +- .../upgrades/TurtleInventoryCrafting.java | 5 +- .../shared/turtle/upgrades/TurtleModem.java | 1 + .../shared/turtle/upgrades/TurtleShovel.java | 3 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 1 + .../shared/turtle/upgrades/TurtleTool.java | 1 - .../shared/util/ColourUtils.java | 3 +- .../shared/util/CommentedConfigSpec.java | 2 +- .../computercraft/shared/util/Config.java | 5 +- .../shared/util/DefaultInventory.java | 3 +- .../shared/util/DefaultSidedInventory.java | 5 +- .../shared/util/DropConsumer.java | 9 ++- .../shared/util/FakeNetHandler.java | 47 +---------- .../computercraft/shared/util/IDAssigner.java | 5 +- .../shared/util/ImpostorRecipe.java | 5 +- .../shared/util/ImpostorShapelessRecipe.java | 5 +- .../shared/util/InventoryDelegate.java | 3 +- .../shared/util/InventoryUtil.java | 6 +- .../shared/util/InvisibleSlot.java | 3 +- .../shared/util/ItemStorage.java | 3 +- .../computercraft/shared/util/RecipeUtil.java | 8 +- .../shared/util/TickScheduler.java | 7 +- .../shared/util/ValidatingSlot.java | 3 +- .../computercraft/shared/util/WorldUtil.java | 7 +- .../shared/wired/WiredNetwork.java | 3 +- src/main/resources/cc.accesswidener | 6 +- src/main/resources/computercraft.mixins.json | 28 +++---- 257 files changed, 734 insertions(+), 693 deletions(-) rename src/main/java/dan200/computercraft/fabric/mixin/{ChatHudAccess.java => ChatComponentAccess.java} (87%) rename src/main/java/dan200/computercraft/fabric/mixin/{HeldItemRendererAccess.java => ItemInHandRendererAccess.java} (62%) rename src/main/java/dan200/computercraft/fabric/mixin/{WorldSavePathAccess.java => LevelResourceAccess.java} (82%) delete mode 100644 src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java rename src/main/java/dan200/computercraft/fabric/mixin/{MixinItemFrameEntityRenderer.java => MixinItemFrameRenderer.java} (92%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinHeldItemRenderer.java => MixinItemInHandRenderer.java} (70%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinWorld.java => MixinLevel.java} (73%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinWorldRenderer.java => MixinLevelRenderer.java} (68%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinMinecraftClient.java => MixinMinecraft.java} (76%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinServerWorld.java => MixinServerLevel.java} (81%) rename src/main/java/dan200/computercraft/fabric/mixin/{MixinServerPlayerInteractionManager.java => MixinServerPlayerGameMode.java} (71%) delete mode 100644 src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java diff --git a/build.gradle b/build.gradle index de076b89b..77c713e26 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,13 @@ plugins { id 'fabric-loom' version '0.9-SNAPSHOT' id 'maven-publish' - id "checkstyle" + //id "checkstyle" id "com.github.hierynomus.license" version "0.16.1" } java { toolchain { languageVersion = JavaLanguageVersion.of(16) - vendor = JvmVendorSpec.ADOPTOPENJDK } } @@ -29,16 +28,16 @@ repositories { } } -//loom { -// accessWidenerPath = file("src/main/resources/cc.accesswidener") -//} +loom { + accessWidenerPath = file("src/main/resources/cc.accesswidener") +} configurations { implementation.extendsFrom shade } dependencies { - checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1' + //checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1' minecraft "com.mojang:minecraft:${mc_version}" //mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2" diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 5b6d83f23..068114705 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -40,6 +40,7 @@ import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.File; @@ -61,7 +62,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI MinecraftServer server = GameInstanceUtils.getServer(); if( server != null ) { - ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); + ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).callGetResourceManager(); try { return manager.getResource( new ResourceLocation( domain, subPath ) ) @@ -116,7 +117,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI MinecraftServer server = GameInstanceUtils.getServer(); if( server != null ) { - ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager(); + ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).callGetResourceManager(); ResourceMount mount = ResourceMount.get( domain, subPath, manager ); return mount.exists( "" ) ? mount : null; } diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 141ebfc6d..7e7ae52ee 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -21,13 +21,14 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * The static entry point to the ComputerCraft API. * diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java index 58b4a8b1b..6924160a0 100644 --- a/src/main/java/dan200/computercraft/api/IUpgradeBase.java +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -7,11 +7,12 @@ package dan200.computercraft.api; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import javax.annotation.Nonnull; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + /** * Common functionality between {@link ITurtleUpgrade} and {@link IPocketUpgrade}. */ diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index 5afe637ec..f0c3658ff 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -6,6 +6,9 @@ package dan200.computercraft.api.client; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -13,10 +16,8 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Transformation; -import com.mojang.math.Vector3f; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index b8a6c8f43..0e23748be 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -8,8 +8,9 @@ package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IComputerAccess; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.file.attribute.BasicFileAttributes; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index b6cd8f688..713e290fa 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -8,8 +8,9 @@ package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IComputerAccess; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; diff --git a/src/main/java/dan200/computercraft/api/lua/GenericSource.java b/src/main/java/dan200/computercraft/api/lua/GenericSource.java index b04c11ce9..1828ffb6b 100644 --- a/src/main/java/dan200/computercraft/api/lua/GenericSource.java +++ b/src/main/java/dan200/computercraft/api/lua/GenericSource.java @@ -9,9 +9,10 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.core.asm.LuaMethod; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; +import javax.annotation.Nonnull; + /** * A generic source of {@link LuaMethod} functions. * diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index e7f7bb7d6..414d9895b 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -7,13 +7,14 @@ package dan200.computercraft.api.media; import dan200.computercraft.api.filesystem.IMount; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Represents an item that can be placed in a disk drive and used by a Computer. * diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index 46c586ec8..023e4d12c 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -6,9 +6,10 @@ package dan200.computercraft.api.media; +import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.item.ItemStack; /** * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}. diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index e146c23e7..ccea2630f 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -6,10 +6,11 @@ package dan200.computercraft.api.network; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; + /** * An object on an {@link IPacketNetwork}, capable of receiving packets. */ diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index bf9adcead..310dd92d1 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -6,10 +6,11 @@ package dan200.computercraft.api.network; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; + /** * An object on a {@link IPacketNetwork}, capable of sending packets. */ diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index cd558f849..7012b482e 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -13,9 +13,10 @@ import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.MethodResult; +import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.level.Level; import java.util.Map; /** diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index c2b5c7af4..20e8e416f 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -6,11 +6,12 @@ package dan200.computercraft.api.peripheral; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; import java.util.Optional; /** diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java index 9cc83c5fa..683ee64cc 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java @@ -5,12 +5,13 @@ */ package dan200.computercraft.api.peripheral; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * A {@link net.minecraft.world.level.block.entity.BlockEntity} which may act as a peripheral. * diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index dc7f2fc9e..cd8a2f55e 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -7,12 +7,13 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.shared.util.NonNullSupplier; -import javax.annotation.Nonnull; import net.minecraft.Util; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; + +import javax.annotation.Nonnull; import java.util.function.Supplier; /** diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index f8adb22a6..f8ee4010b 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -7,11 +7,12 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Map; /** diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index 4bd5ee1de..d81e59d51 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -9,9 +9,10 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.level.Level; /** * Additional peripherals for pocket computers. diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index 2fc121e60..092f79d51 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -6,11 +6,12 @@ package dan200.computercraft.api.redstone; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + /** * This interface is used to provide bundled redstone output for blocks. * diff --git a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index d73dd641c..6d075b5fc 100644 --- a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -7,12 +7,13 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.shared.util.NonNullSupplier; -import javax.annotation.Nonnull; import net.minecraft.Util; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; + +import javax.annotation.Nonnull; import java.util.function.Supplier; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java b/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java index 994b83648..b1481f5c3 100644 --- a/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java +++ b/src/main/java/dan200/computercraft/api/turtle/FakePlayer.java @@ -10,7 +10,8 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import net.minecraft.commands.arguments.EntityAnchorArgument; -import net.minecraft.network.*; +import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; @@ -36,6 +37,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.entity.CommandBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nullable; import javax.crypto.Cipher; import java.util.Collection; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 0932709f0..0f876f109 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.ItemStorage; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -20,6 +18,9 @@ import net.minecraft.world.Container; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * The interface passed to turtle by turtles, providing methods that they can call. * diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index da1938e1d..4fc3d69f9 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -13,6 +13,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.core.Direction; + import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java index 0517bdf51..64126aa39 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java @@ -10,8 +10,9 @@ import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import javax.annotation.Nonnull; import net.minecraft.world.entity.Entity; + +import javax.annotation.Nonnull; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index 28ffd9b7d..ca757dd7d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -11,11 +11,12 @@ import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nonnull; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index 0aef37ca4..14a5e20aa 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -8,8 +8,9 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.turtle.ITurtleAccess; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nonnull; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java index 5cc15f9f0..83033a513 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java @@ -8,12 +8,13 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.api.turtle.ITurtleAccess; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index 6a3e64960..47327afee 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -7,9 +7,10 @@ package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; +import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.item.ItemStack; import java.util.Objects; /** diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index c84ff64c6..2e1b3074a 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -17,13 +17,10 @@ import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.BlockModelRotation; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; + import java.util.HashSet; import java.util.function.Consumer; diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 0d076d5ce..d401e6566 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -6,20 +6,20 @@ package dan200.computercraft.client; -import dan200.computercraft.fabric.mixin.ChatHudAccess; +import dan200.computercraft.fabric.mixin.ChatComponentAccess; import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.command.text.TableFormatter; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import org.apache.commons.lang3.StringUtils; - -import javax.annotation.Nullable; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.components.ChatComponent; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nullable; public class ClientTableFormatter implements TableFormatter { @@ -73,7 +73,7 @@ public class ClientTableFormatter implements TableFormatter // int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); // List list = RenderComponentsUtil.func_238505_a_( component, maxWidth, mc.fontRenderer ); // if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); - ((ChatHudAccess) chat).callAddMessage( component, id ); + ((ChatComponentAccess) chat).callAddMessage( component, id ); } @Override @@ -88,7 +88,7 @@ public class ClientTableFormatter implements TableFormatter for( int i = height; i < lastHeight; i++ ) { - ((ChatHudAccess) chat).callRemoveMessage( i + table.getId() ); + ((ChatComponentAccess) chat).callRemoveById( i + table.getId() ); } return height; } diff --git a/src/main/java/dan200/computercraft/client/SoundManager.java b/src/main/java/dan200/computercraft/client/SoundManager.java index 67827a498..e2fddf623 100644 --- a/src/main/java/dan200/computercraft/client/SoundManager.java +++ b/src/main/java/dan200/computercraft/client/SoundManager.java @@ -5,9 +5,6 @@ */ package dan200.computercraft.client; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.sounds.AbstractSoundInstance; import net.minecraft.client.resources.sounds.SoundInstance; @@ -16,6 +13,10 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundSource; import net.minecraft.world.phys.Vec3; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public class SoundManager { private static final Map sounds = new HashMap<>(); diff --git a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java index 42557de5c..e9c54163d 100644 --- a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java +++ b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java @@ -17,13 +17,13 @@ import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.ContinueUploadMessage; import dan200.computercraft.shared.network.server.UploadFileMessage; -import org.lwjgl.glfw.GLFW; - -import javax.annotation.Nonnull; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.entity.player.Inventory; +import org.lwjgl.glfw.GLFW; + +import javax.annotation.Nonnull; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index bb405b39b..d91b45ab1 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -6,23 +6,23 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.mojang.math.Transformation; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.resources.ResourceLocation; -import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix4f; -import com.mojang.math.Transformation; +import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; public final class FixedWidthFontRenderer { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 52772c7ea..b938d87f9 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.WidgetTerminal; @@ -13,15 +14,14 @@ import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import javax.annotation.Nonnull; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; +import javax.annotation.Nonnull; + import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; import static dan200.computercraft.client.render.ComputerBorderRenderer.getTexture; -import com.mojang.blaze3d.vertex.PoseStack; - public final class GuiComputer extends ComputerScreenBase { private final int termWidth; @@ -59,6 +59,7 @@ public final class GuiComputer extends Computer leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER, termWidth, termHeight ); } + @Override public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY ) { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 58e97f3f6..6c61b4021 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -9,13 +9,14 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import javax.annotation.Nonnull; 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 javax.annotation.Nonnull; + public class GuiDiskDrive extends AbstractContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index 7b3be404e..67905dff3 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -9,12 +9,13 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import javax.annotation.Nonnull; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import javax.annotation.Nonnull; + public class GuiPrinter extends AbstractContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index b985cf47a..299971999 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -12,14 +12,14 @@ import com.mojang.math.Matrix4f; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; -import org.lwjgl.glfw.GLFW; - -import javax.annotation.Nonnull; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; +import org.lwjgl.glfw.GLFW; + +import javax.annotation.Nonnull; import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 4f0434b17..c2faa896f 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -14,11 +14,12 @@ import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import javax.annotation.Nonnull; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import javax.annotation.Nonnull; + import static dan200.computercraft.shared.turtle.inventory.ContainerTurtle.BORDER; public class GuiTurtle extends ComputerScreenBase diff --git a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java index 67b720e99..300dd7def 100644 --- a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java +++ b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java @@ -10,9 +10,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; -import org.lwjgl.glfw.GLFW; - -import javax.annotation.Nonnull; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.MenuAccess; @@ -20,6 +17,9 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.entity.player.Inventory; +import org.lwjgl.glfw.GLFW; + +import javax.annotation.Nonnull; import java.util.List; public class NoTermComputerScreen extends Screen implements MenuAccess diff --git a/src/main/java/dan200/computercraft/client/gui/OptionScreen.java b/src/main/java/dan200/computercraft/client/gui/OptionScreen.java index 8ecdf2d38..532c08b94 100644 --- a/src/main/java/dan200/computercraft/client/gui/OptionScreen.java +++ b/src/main/java/dan200/computercraft/client/gui/OptionScreen.java @@ -7,7 +7,6 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import javax.annotation.Nonnull; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; @@ -15,6 +14,8 @@ import net.minecraft.client.gui.components.MultiLineLabel; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; + +import javax.annotation.Nonnull; import java.util.List; public final class OptionScreen extends Screen diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java index 2faf45680..afc8139ff 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java @@ -10,14 +10,15 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.computer.core.ClientComputer; -import java.util.Arrays; -import java.util.function.Consumer; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import java.util.Arrays; +import java.util.function.Consumer; + /** * Registers buttons to interact with a computer. */ diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java b/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java index a2ed56dc6..e14e0cde9 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/DynamicImageButton.java @@ -7,12 +7,13 @@ package dan200.computercraft.client.gui.widgets; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import javax.annotation.Nonnull; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; + +import javax.annotation.Nonnull; import java.util.List; import java.util.function.IntSupplier; import java.util.function.Supplier; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 0a79ad45a..8eaac4d80 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -6,6 +6,8 @@ package dan200.computercraft.client.gui.widgets; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ClientComputer; @@ -23,9 +25,6 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; - public class WidgetTerminal extends AbstractWidget { private static final float TERMINATE_TIME = 0.5f; diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index b8791841e..11dd8f378 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -44,6 +44,7 @@ import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.Item; + import java.util.function.Supplier; @Environment( EnvType.CLIENT ) diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index a1d2e03df..1f9935a78 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -20,7 +20,6 @@ import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; -import net.minecraft.util.math.*; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.HitResult; diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java index f5d85c67c..b5f58d77a 100644 --- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -10,11 +10,12 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix4f; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; +import javax.annotation.Nonnull; + public class ComputerBorderRenderer { public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index 2e07e7148..62f3069f3 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -8,7 +8,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import dan200.computercraft.fabric.mixin.HeldItemRendererAccess; +import dan200.computercraft.fabric.mixin.ItemInHandRendererAccess; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -72,16 +72,16 @@ public abstract class ItemMapLikeRenderer float tZ = -0.4f * Mth.sin( swingRt * (float) Math.PI ); transform.translate( 0, -tX / 2, tZ ); - HeldItemRendererAccess access = (HeldItemRendererAccess) renderer; - float pitchAngle = access.callGetMapAngle( pitch ); + ItemInHandRendererAccess access = (ItemInHandRendererAccess) renderer; + float pitchAngle = access.callCalculateMapTilt( pitch ); transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); transform.mulPose( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) ); if( !minecraft.player.isInvisible() ) { transform.pushPose(); transform.mulPose( Vector3f.YP.rotationDegrees( 90.0F ) ); - access.callRenderArm( transform, render, combinedLight, HumanoidArm.RIGHT ); - access.callRenderArm( transform, render, combinedLight, HumanoidArm.LEFT ); + access.callRenderMapHand( transform, render, combinedLight, HumanoidArm.RIGHT ); + access.callRenderMapHand( transform, render, combinedLight, HumanoidArm.LEFT ); transform.popPose(); } @@ -115,8 +115,8 @@ public abstract class ItemMapLikeRenderer { transform.pushPose(); transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) ); - ((HeldItemRendererAccess) minecraft.getItemInHandRenderer()) - .callRenderArmHoldingItem( transform, render, combinedLight, equipProgress, swingProgress, side ); + ((ItemInHandRendererAccess) minecraft.getItemInHandRenderer()) + .callRenderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side ); transform.popPose(); } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index e8057cb36..993c922f2 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -7,11 +7,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.*; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; import dan200.computercraft.ComputerCraft; @@ -22,7 +18,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.Minecraft; -import net.minecraft.client.render.*; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 466d043ea..d7f3ca2a6 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -6,6 +6,9 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.item.ItemStack; @@ -16,10 +19,6 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; -import com.mojang.math.Vector3f; - /** * Emulates map and item-frame rendering for printouts. */ diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 71cb4f673..44e44f307 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -5,14 +5,15 @@ */ package dan200.computercraft.client.render; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.renderer.block.model.BakedQuad; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; import com.mojang.math.Matrix4f; import com.mojang.math.Vector4f; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.renderer.block.model.BakedQuad; + import java.util.List; /** diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 9b5b9fafc..491b4514d 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -6,25 +6,25 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.util.math.*; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import java.util.EnumSet; -import static net.minecraft.core.Direction.*; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; +import java.util.EnumSet; + +import static net.minecraft.core.Direction.*; /** * Overrides monitor highlighting to only render the outline of the whole monitor, rather than the current block. This means you do not get an diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index fe6746854..3602574ec 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -9,13 +9,13 @@ import com.mojang.blaze3d.shaders.Uniform; import com.mojang.blaze3d.vertex.VertexFormat; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.shared.util.Palette; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.server.packs.resources.ResourceProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL13; import javax.annotation.Nullable; -import net.minecraft.client.renderer.ShaderInstance; -import net.minecraft.server.packs.resources.ResourceProvider; import java.io.IOException; import java.nio.FloatBuffer; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 405a9f4d2..2d9e49afa 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -6,6 +6,8 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; @@ -14,9 +16,6 @@ import net.minecraft.client.renderer.MultiBufferSource; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix4f; - public final class PrintoutRenderer { /** diff --git a/src/main/java/dan200/computercraft/client/render/RenderTypes.java b/src/main/java/dan200/computercraft/client/render/RenderTypes.java index 6be3ae0d6..857bbd74f 100644 --- a/src/main/java/dan200/computercraft/client/render/RenderTypes.java +++ b/src/main/java/dan200/computercraft/client/render/RenderTypes.java @@ -8,11 +8,11 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; import dan200.computercraft.client.gui.FixedWidthFontRenderer; -import net.minecraft.client.render.*; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.resources.ResourceLocation; + import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index b8324055a..29c8ca657 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,11 +8,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexBuffer; -import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.*; import com.mojang.math.Matrix4f; import com.mojang.math.Transformation; import com.mojang.math.Vector3f; @@ -26,14 +22,12 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.client.render.*; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.util.math.*; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL31; @@ -41,8 +35,8 @@ import org.lwjgl.opengl.GL31; import javax.annotation.Nonnull; import java.nio.ByteBuffer; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static com.mojang.blaze3d.platform.MemoryTracker.create; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; public class TileEntityMonitorRenderer implements BlockEntityRenderer { @@ -58,6 +52,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer } private void renderUpgrade( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, - TurtleSide side, float f ) + TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); if( upgrade == null ) @@ -170,7 +171,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer } private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, - ModelResourceLocation modelLocation, int[] tints ) + ModelResourceLocation modelLocation, int[] tints ) { ModelManager modelManager = Minecraft.getInstance() .getItemRenderer() @@ -180,7 +181,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer } private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, - int[] tints ) + int[] tints ) { random.setSeed( 0 ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index 194f43f66..01a32e812 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -11,12 +11,9 @@ import dan200.computercraft.ComputerCraft; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; + import javax.annotation.Nonnull; import java.util.Arrays; import java.util.Collection; @@ -73,7 +70,7 @@ public final class TurtleModelLoader @Override public Collection getMaterials( Function modelGetter, - Set> missingTextureErrors ) + Set> missingTextureErrors ) { return getDependencies() .stream() diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 9db354a9b..7f364725e 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -17,6 +17,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; + import javax.annotation.Nonnull; import java.util.*; diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java index 914a5e752..047ebd0e1 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -7,12 +7,13 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import javax.annotation.Nonnull; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; +import javax.annotation.Nonnull; + public class TurtlePlayerRenderer extends EntityRenderer { //FIXME Make sure this isn't an issue. Context was EntityRenderDispatcher. public TurtlePlayerRenderer( EntityRendererProvider.Context context ) @@ -28,7 +29,7 @@ public class TurtlePlayerRenderer extends EntityRenderer @Nonnull @Override - public ResourceLocation getTexture( @Nonnull TurtlePlayer entity ) + public ResourceLocation getTextureLocation( @Nonnull TurtlePlayer entity ) { return ComputerBorderRenderer.BACKGROUND_NORMAL; } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 706d46f2d..1b575234f 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -30,6 +30,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collections; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index 8f8d495af..484b361f7 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -5,9 +5,10 @@ */ package dan200.computercraft.core.computer; +import net.minecraft.core.Direction; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.core.Direction; /** * A side on a computer. Unlike {@link Direction}, this is relative to the direction the computer is diff --git a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java index b0267d5bd..301a9a606 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java @@ -9,8 +9,9 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.turtle.core.TurtleBrain; -import javax.annotation.Nonnull; import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 31c81095e..90566970e 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -13,14 +13,15 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.shared.util.IoUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index dc0556235..3081d4c29 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -7,10 +7,11 @@ package dan200.computercraft.core.terminal; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; -import javax.annotation.Nonnull; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; +import javax.annotation.Nonnull; + public class Terminal { private static final String base16 = "0123456789abcdef"; diff --git a/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/ChatComponentAccess.java similarity index 87% rename from src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java rename to src/main/java/dan200/computercraft/fabric/mixin/ChatComponentAccess.java index 9e5b48868..dbb945ea4 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/ChatHudAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/ChatComponentAccess.java @@ -11,11 +11,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; @Mixin( ChatComponent.class ) -public interface ChatHudAccess +public interface ChatComponentAccess { @Invoker void callAddMessage( Component text, int messageId ); @Invoker - void callRemoveMessage( int messageId ); + void callRemoveById( int messageId ); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/ItemInHandRendererAccess.java similarity index 62% rename from src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java rename to src/main/java/dan200/computercraft/fabric/mixin/ItemInHandRendererAccess.java index 056214624..d86132958 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/HeldItemRendererAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/ItemInHandRendererAccess.java @@ -13,14 +13,14 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; @Mixin( ItemInHandRenderer.class ) -public interface HeldItemRendererAccess +public interface ItemInHandRendererAccess { @Invoker - float callGetMapAngle( float tickDelta ); + float callCalculateMapTilt( float tickDelta ); @Invoker - void callRenderArm( PoseStack matrices, MultiBufferSource vertexConsumers, int light, HumanoidArm arm ); + void callRenderMapHand( PoseStack matrices, MultiBufferSource vertexConsumers, int light, HumanoidArm arm ); @Invoker - void callRenderArmHoldingItem( PoseStack matrices, MultiBufferSource vertexConsumers, int light, float equipProgress, float swingProgress, HumanoidArm arm ); + void callRenderPlayerArm( PoseStack matrices, MultiBufferSource vertexConsumers, int light, float equipProgress, float swingProgress, HumanoidArm arm ); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/LevelResourceAccess.java similarity index 82% rename from src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java rename to src/main/java/dan200/computercraft/fabric/mixin/LevelResourceAccess.java index d706e3545..cd777c710 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/WorldSavePathAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/LevelResourceAccess.java @@ -10,10 +10,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; @Mixin( LevelResource.class ) -public interface WorldSavePathAccess +public interface LevelResourceAccess { @Invoker( "" ) - static LevelResource createWorldSavePath( String relativePath ) + static LevelResource create( String relativePath ) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java index ed063d9f3..5e6efce13 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MinecraftServerAccess.java @@ -6,13 +6,13 @@ package dan200.computercraft.fabric.mixin; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.ServerResources; +import net.minecraft.server.packs.resources.ResourceManager; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; @Mixin( MinecraftServer.class ) public interface MinecraftServerAccess { - @Accessor - ServerResources getServerResourceManager(); + @Invoker + ResourceManager callGetResourceManager(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java index 3f5937fb2..01defc0f9 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinBlock.java @@ -6,8 +6,6 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.util.DropConsumer; -import java.util.function.Supplier; -import net.minecraft.core.BlockPos; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -18,18 +16,21 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.util.function.Supplier; + /** * Captures block drops. * - * @see Block#popResource(Level, BlockPos, ItemStack) + * @see Block#popResource(Level, Supplier, ItemStack) */ @Mixin( Block.class ) public class MixinBlock { - @Inject( method = "dropStack(Lnet/minecraft/world/World;Ljava/util/function/Supplier;Lnet/minecraft/item/ItemStack;)V", + @Inject( + method = "popResource(Lnet/minecraft/world/level/Level;Ljava/util/function/Supplier;Lnet/minecraft/world/item/ItemStack;)V", at = @At( value = "INVOKE", - target = "Lnet/minecraft/entity/ItemEntity;setToDefaultPickupDelay()V" + target = "Lnet/minecraft/world/entity/item/ItemEntity;setDefaultPickUpDelay()V" ), locals = LocalCapture.CAPTURE_FAILSOFT, cancellable = true ) diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java index c6ea58992..d2e63f1ef 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinEntity.java @@ -22,10 +22,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin( Entity.class ) public class MixinEntity { - @Inject( method = "dropStack(Lnet/minecraft/item/ItemStack;F)Lnet/minecraft/entity/ItemEntity;", - at = @At( value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z" ), + @Inject( method = "spawnAtLocation(Lnet/minecraft/world/item/ItemStack;F)Lnet/minecraft/world/entity/item/ItemEntity;", + at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z" ), cancellable = true ) - public void dropStack( ItemStack stack, float height, CallbackInfoReturnable callbackInfo ) + public void spawnAtLocation( ItemStack stack, float height, CallbackInfoReturnable callbackInfo ) { if( DropConsumer.onLivingDrops( (Entity) (Object) this, stack ) ) { diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java index 85563c4ac..11db72756 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinGameRenderer.java @@ -10,6 +10,9 @@ import com.mojang.blaze3d.shaders.Program; import com.mojang.datafixers.util.Pair; import dan200.computercraft.client.render.MonitorTextureBufferShader; import dan200.computercraft.client.render.RenderTypes; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.server.packs.resources.ResourceManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -19,15 +22,12 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.io.IOException; import java.util.List; import java.util.function.Consumer; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.ShaderInstance; -import net.minecraft.server.packs.resources.ResourceManager; @Mixin( GameRenderer.class ) public class MixinGameRenderer { - @Inject( method = "loadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT ) - private void loadShaders( ResourceManager manager, CallbackInfo info, List list, List>> list2 ) throws IOException + @Inject( method = "reloadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT ) + private void reloadShaders( ResourceManager manager, CallbackInfo info, List list, List>> list2 ) throws IOException { list2.add( Pair.of( new ShaderInstance( manager, diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java deleted file mode 100644 index f716eabd2..000000000 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinHandledScreen.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.fabric.mixin; - -import dan200.computercraft.client.gui.widgets.WidgetTerminal; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.network.chat.Component; -import net.minecraft.world.inventory.AbstractContainerMenu; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin( AbstractContainerScreen.class ) -public class MixinHandledScreen extends Screen -{ - protected MixinHandledScreen( Component title ) - { - super( title ); - } - - @Inject( method = "mouseReleased", at = @At ( "HEAD" ) ) - public void mouseReleased( double mouseX, double mouseY, int button, CallbackInfoReturnable cir ) - { - for ( GuiEventListener child : this.children() ) - { - if ( child instanceof WidgetTerminal ) - { - child.mouseReleased( mouseX, mouseY, button ); - } - } - } -} diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameRenderer.java similarity index 92% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameRenderer.java index 5fe83f6a1..f70265a5f 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameEntityRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemFrameRenderer.java @@ -22,13 +22,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin( ItemFrameRenderer.class ) @Environment( EnvType.CLIENT ) -public class MixinItemFrameEntityRenderer +public class MixinItemFrameRenderer { @Inject( method = "render", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/util/math/MatrixStack;multiply(Lnet/minecraft/util/math/Quaternion;)V", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lcom/mojang/math/Quaternion;)V", ordinal = 2, shift = At.Shift.AFTER ), diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemInHandRenderer.java similarity index 70% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinItemInHandRenderer.java index f521182c5..1b5b821b5 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinHeldItemRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinItemInHandRenderer.java @@ -16,35 +16,17 @@ import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin( ItemInHandRenderer.class ) @Environment( EnvType.CLIENT ) -public class MixinHeldItemRenderer +public class MixinItemInHandRenderer { - @Shadow - private void renderArmHoldingItem( PoseStack matrices, MultiBufferSource vertexConsumers, int light, float equipProgress, float swingProgress, - HumanoidArm arm ) - { - } - - @Shadow - private float getMapAngle( float pitch ) - { - return 0; - } - - @Inject( method = "Lnet/minecraft/client/render/item/HeldItemRenderer;renderFirstPersonItem(Lnet/minecraft/client/network/AbstractClientPlayerEntity;" + - "FFLnet/minecraft/util/Hand;FLnet/minecraft/item/ItemStack;FLnet/minecraft/client/util/math/MatrixStack;" + - "Lnet/minecraft/client/render/VertexConsumerProvider;I)V", - at = @At( "HEAD" ), - cancellable = true ) + @Inject( method = "renderArmWithItem", at = @At( "HEAD" ), cancellable = true ) public void renderFirstPersonItem( AbstractClientPlayer player, float var2, float pitch, InteractionHand hand, float swingProgress, ItemStack stack, float equipProgress, PoseStack matrixStack, MultiBufferSource provider, int light, diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java index 1e5723e6d..60fdb1a89 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLanguage.java @@ -22,7 +22,6 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; -import java.util.Map; import java.util.function.BiConsumer; /** @@ -38,7 +37,7 @@ public class MixinLanguage private static Logger LOGGER; @Shadow - public static void load( InputStream inputStream, BiConsumer entryConsumer ) + public static void loadFromJson( InputStream inputStream, BiConsumer entryConsumer ) { } @@ -46,21 +45,20 @@ public class MixinLanguage { String path = "/assets/" + modId + "/lang/en_us.json"; - try ( InputStream inputStream = Language.class.getResourceAsStream( path ) ) + try( InputStream inputStream = Language.class.getResourceAsStream( path ) ) { - if ( inputStream == null ) return; - load( inputStream, biConsumer ); + if( inputStream == null ) return; + loadFromJson( inputStream, biConsumer ); } - catch ( JsonParseException | IOException e ) + catch( JsonParseException | IOException e ) { LOGGER.error( "Couldn't read strings from " + path, e ); } } - @Inject( method = "create", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At( value = "INVOKE", remap = false, target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;" ) ) - private static void create( CallbackInfoReturnable cir, ImmutableMap.Builder builder ) + @Inject( method = "loadDefault", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At( value = "INVOKE", remap = false, target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;" ) ) + private static void loadDefault( CallbackInfoReturnable cir, ImmutableMap.Builder builder ) { - final Map originalTranslation = builder.build(); /* We must ensure that the keys are de-duplicated because we can't catch the error that might otherwise * occur when the injected function calls build() on the ImmutableMap builder. So we use our own hash map and * exclude "minecraft", as the injected function has already loaded those keys at this point. @@ -72,9 +70,6 @@ public class MixinLanguage loadModLangFile( id, translations::put ); } ); - // This is needed to remove keys that exist in vanilla Minecraft (Consistency+ does this) - translations.keySet().removeIf( originalTranslation::containsKey ); - builder.putAll( translations ); } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLevel.java similarity index 73% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinLevel.java index b2e72057f..f9132b54e 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorld.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLevel.java @@ -6,6 +6,8 @@ package dan200.computercraft.fabric.mixin; import dan200.computercraft.shared.common.TileGeneric; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -13,9 +15,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import javax.annotation.Nullable; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import java.util.Collection; /** @@ -24,21 +23,15 @@ import java.util.Collection; * Forge does this, this is just a bodge to get Fabric in line with that behaviour. */ @Mixin( Level.class ) -public class MixinWorld +public class MixinLevel { @Shadow - private boolean iteratingTickingBlockEntities; + protected boolean tickingBlockEntities; - @Shadow - public boolean isInBuildLimit( BlockPos pos ) + @Inject( method = "setBlockEntity", at = @At( "HEAD" ) ) + public void setBlockEntity( @Nullable BlockEntity entity, CallbackInfo info ) { - return false; - } - - @Inject( method = "addBlockEntity", at = @At( "HEAD" ) ) - public void addBlockEntity( @Nullable BlockEntity entity, CallbackInfo info ) - { - if( entity != null && !entity.isRemoved() && this.isInBuildLimit( entity.getBlockPos() ) && iteratingTickingBlockEntities ) + if( entity != null && !entity.isRemoved() && entity.getLevel().isInWorldBounds( entity.getBlockPos() ) && tickingBlockEntities ) { setWorld( entity, this ); } @@ -48,14 +41,14 @@ public class MixinWorld { if( entity.getLevel() != world && entity instanceof TileGeneric ) { - entity.setLevel( (Level) world ); + entity.setLevel( (Level) world ); //TODO why? } } // @Inject( method = "addBlockEntities", at = @At( "HEAD" ) ) public void addBlockEntities( Collection entities, CallbackInfo info ) { - if( iteratingTickingBlockEntities ) + if( tickingBlockEntities ) { for( BlockEntity entity : entities ) { diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinLevelRenderer.java similarity index 68% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinLevelRenderer.java index d88bab4eb..351799c13 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinWorldRenderer.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinLevelRenderer.java @@ -22,27 +22,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin( LevelRenderer.class ) @Environment( EnvType.CLIENT ) -public class MixinWorldRenderer +public class MixinLevelRenderer { - @Inject( method = "drawBlockOutline", cancellable = true, at = @At( "HEAD" ) ) - public void drawBlockOutline( PoseStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, + @Inject( method = "renderHitOutline", cancellable = true, at = @At( "HEAD" ) ) + public void renderHitOutline( PoseStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos blockPos, BlockState blockState, CallbackInfo info ) { - if( CableHighlightRenderer.drawHighlight( matrixStack, - vertexConsumer, - entity, - d, - e, - f, - blockPos, - blockState ) || MonitorHighlightRenderer.drawHighlight( matrixStack, - vertexConsumer, - entity, - d, - e, - f, - blockPos, - blockState ) ) + if( CableHighlightRenderer.drawHighlight( matrixStack, vertexConsumer, entity, d, e, f, blockPos, blockState ) + || MonitorHighlightRenderer.drawHighlight( matrixStack, vertexConsumer, entity, d, e, f, blockPos, blockState ) ) { info.cancel(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java index 38b36449c..35d427ff9 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java @@ -13,40 +13,57 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin( Matrix4f.class ) public class MixinMatrix4f implements IMatrix4f { - @Shadow protected float a00; - @Shadow protected float a01; - @Shadow protected float a02; - @Shadow protected float a03; - @Shadow protected float a10; - @Shadow protected float a11; - @Shadow protected float a12; - @Shadow protected float a13; - @Shadow protected float a20; - @Shadow protected float a21; - @Shadow protected float a22; - @Shadow protected float a23; - @Shadow protected float a30; - @Shadow protected float a31; - @Shadow protected float a32; - @Shadow protected float a33; + @Shadow + protected float m00; + @Shadow + protected float m01; + @Shadow + protected float m02; + @Shadow + protected float m03; + @Shadow + protected float m10; + @Shadow + protected float m11; + @Shadow + protected float m12; + @Shadow + protected float m13; + @Shadow + protected float m20; + @Shadow + protected float m21; + @Shadow + protected float m22; + @Shadow + protected float m23; + @Shadow + protected float m30; + @Shadow + protected float m31; + @Shadow + protected float m32; + @Shadow + protected float m33; + @Override public void setFloatArray( float[] values ) { - a00 = values[0]; - a01 = values[1]; - a02 = values[2]; - a03 = values[3]; - a10 = values[4]; - a11 = values[5]; - a12 = values[6]; - a13 = values[7]; - a20 = values[8]; - a21 = values[9]; - a22 = values[10]; - a23 = values[11]; - a30 = values[12]; - a31 = values[13]; - a32 = values[14]; - a33 = values[15]; + m00 = values[0]; + m01 = values[1]; + m02 = values[2]; + m03 = values[3]; + m10 = values[4]; + m11 = values[5]; + m12 = values[6]; + m13 = values[7]; + m20 = values[8]; + m21 = values[9]; + m22 = values[10]; + m23 = values[11]; + m30 = values[12]; + m31 = values[13]; + m32 = values[14]; + m33 = values[15]; } } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraft.java similarity index 76% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraft.java index 30a5f2919..dd2e82c0d 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraftClient.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinMinecraft.java @@ -16,22 +16,22 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin( Minecraft.class ) -public abstract class MixinMinecraftClient +public abstract class MixinMinecraft { - @Inject( method = "render", at = @At( "HEAD" ) ) + @Inject( method = "runTick", at = @At( "HEAD" ) ) private void onRender( CallbackInfo info ) { FrameInfo.onRenderFrame(); } - @Inject( method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At( "RETURN" ) ) + @Inject( method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At( "RETURN" ) ) private void disconnectAfter( Screen screen, CallbackInfo info ) { ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld(); } - @Inject( method = "joinWorld", at = @At( "RETURN" ) ) - private void joinWorldAfter( ClientLevel world, CallbackInfo info ) + @Inject( method = "setLevel", at = @At( "RETURN" ) ) + private void setLevel( ClientLevel world, CallbackInfo info ) { ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld(); } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerLevel.java similarity index 81% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinServerLevel.java index 7a0255f5f..4154327c6 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerWorld.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerLevel.java @@ -19,10 +19,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; * @see ServerLevel#addFreshEntity(Entity) */ @Mixin( ServerLevel.class ) -public class MixinServerWorld +public class MixinServerLevel { - @Inject( method = "spawnEntity", at = @At( "HEAD" ), cancellable = true ) - public void spawnEntity( Entity entity, CallbackInfoReturnable callbackInfo ) + @Inject( method = "addEntity", at = @At( "HEAD" ), cancellable = true ) + public void addEntity( Entity entity, CallbackInfoReturnable callbackInfo ) { if( DropConsumer.onEntitySpawn( entity ) ) { diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerGameMode.java similarity index 71% rename from src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java rename to src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerGameMode.java index 227a62e57..3a15aedda 100644 --- a/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerInteractionManager.java +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinServerPlayerGameMode.java @@ -22,10 +22,14 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin( ServerPlayerGameMode.class ) -public class MixinServerPlayerInteractionManager +public class MixinServerPlayerGameMode { - @Inject( at = @At( value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;copy()Lnet/minecraft/item/ItemStack;", ordinal = 0 ), method = "interactBlock(Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", cancellable = true ) - private void interact( ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable cir ) + @Inject( + at = @At( value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;copy()Lnet/minecraft/world/item/ItemStack;", ordinal = 0 ), + method = "useItemOn(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", + cancellable = true + ) + private void useItemOn( ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable cir ) { BlockPos pos = hitResult.getBlockPos(); BlockState state = world.getBlockState( pos ); diff --git a/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java deleted file mode 100644 index 979211e8b..000000000 --- a/src/main/java/dan200/computercraft/fabric/mixin/SignBlockEntityAccess.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.fabric.mixin; - -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin( SignBlockEntity.class ) -public interface SignBlockEntityAccess -{ - @Accessor - Component[] getTexts(); -} diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index 9e9eebf64..d99e13f9d 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -9,10 +9,11 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java b/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java index 9aaef9b57..ffc9e7b87 100644 --- a/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java +++ b/src/main/java/dan200/computercraft/shared/ComputerCraftRegistry.java @@ -50,7 +50,6 @@ import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; -import net.minecraft.block.*; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; @@ -70,6 +69,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; + import java.util.function.BiFunction; import static net.minecraft.core.Registry.BLOCK_ENTITY_TYPE; @@ -122,7 +122,7 @@ public final class ComputerCraftRegistry new BlockWiredModemFull( modemProperties(), ComputerCraftRegistry.ModTiles.WIRED_MODEM_FULL ) ); public static final BlockCable CABLE = register( "cable", new BlockCable( modemProperties() ) ); - private static Block.Settings properties() + private static BlockBehaviour.Properties properties() { //return FabricBlockSettings.copyOf(Blocks.GLASS) // .strength(2); @@ -132,13 +132,13 @@ public final class ComputerCraftRegistry .noOcclusion(); } - private static Block.Settings turtleProperties() + private static BlockBehaviour.Properties turtleProperties() { return FabricBlockSettings.copyOf( Blocks.STONE ) .strength( 2.5f ); } - private static Block.Settings modemProperties() + private static BlockBehaviour.Properties modemProperties() { return FabricBlockSettings.copyOf( Blocks.STONE ) .breakByHand( true ) @@ -274,7 +274,7 @@ public final class ComputerCraftRegistry public static final MenuType VIEW_COMPUTER = ContainerData.toType( new ResourceLocation( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new ); private static MenuType registerSimple( String id, - ScreenHandlerRegistry.SimpleClientHandlerFactory function ) + ScreenHandlerRegistry.SimpleClientHandlerFactory function ) { return ScreenHandlerRegistry.registerSimple( new ResourceLocation( MOD_ID, id ), function ); } diff --git a/src/main/java/dan200/computercraft/shared/MediaProviders.java b/src/main/java/dan200/computercraft/shared/MediaProviders.java index 9ec54354d..f934ea453 100644 --- a/src/main/java/dan200/computercraft/shared/MediaProviders.java +++ b/src/main/java/dan200/computercraft/shared/MediaProviders.java @@ -9,8 +9,9 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nonnull; import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 3bc7570b7..6f3329c4b 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -10,11 +10,12 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index 249e493a6..4c9cafa3c 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -11,6 +11,7 @@ import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.Util; import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 6b3e7ae62..514c56a59 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -8,9 +8,10 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; +import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.item.ItemStack; import java.util.*; import java.util.stream.Stream; diff --git a/src/main/java/dan200/computercraft/shared/command/ClientCommands.java b/src/main/java/dan200/computercraft/shared/command/ClientCommands.java index 0bfdc4205..f67453827 100644 --- a/src/main/java/dan200/computercraft/shared/command/ClientCommands.java +++ b/src/main/java/dan200/computercraft/shared/command/ClientCommands.java @@ -6,9 +6,10 @@ package dan200.computercraft.shared.command; import dan200.computercraft.shared.util.IDAssigner; -import java.io.File; import net.minecraft.Util; +import java.io.File; + /** * Basic client-side commands. * diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 9808d6345..b1586a1ac 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -37,6 +37,7 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import java.io.File; import java.util.*; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index 322339ebc..df4cd9f2d 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -10,15 +10,16 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dan200.computercraft.api.turtle.FakePlayer; -import java.util.Arrays; -import java.util.Locale; -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import java.util.Arrays; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + public final class CommandUtils { private CommandUtils() {} diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 3aa86dc1a..8f5715edb 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -9,6 +9,7 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; + import java.util.function.Predicate; /** diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java index c8cd4f668..2d6e0e77e 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java @@ -14,9 +14,10 @@ import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dan200.computercraft.shared.command.arguments.ComputersArgumentType.ComputersSupplier; import dan200.computercraft.shared.computer.core.ServerComputer; +import net.minecraft.commands.CommandSourceStack; + import java.util.Collection; import java.util.concurrent.CompletableFuture; -import net.minecraft.commands.CommandSourceStack; import static dan200.computercraft.shared.command.Exceptions.COMPUTER_ARG_MANY; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java index 54951fcd0..a3ad2e1c8 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -16,10 +16,11 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import javax.annotation.Nonnull; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.synchronization.ArgumentSerializer; import net.minecraft.network.FriendlyByteBuf; + +import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.Function; @@ -194,7 +195,7 @@ public final class ComputersArgumentType implements ArgumentType implements ArgumentType> public static class Serializer implements ArgumentSerializer> { @Override - public void toPacket( @Nonnull RepeatArgumentType arg, @Nonnull FriendlyByteBuf buf ) + public void serializeToNetwork( @Nonnull RepeatArgumentType arg, @Nonnull FriendlyByteBuf buf ) { buf.writeBoolean( arg.flatten ); ArgumentTypes.serialize( buf, arg.child ); @@ -160,7 +161,7 @@ public final class RepeatArgumentType implements ArgumentType> } @Override - public void toJson( @Nonnull RepeatArgumentType arg, @Nonnull JsonObject json ) + public void serializeToJson( @Nonnull RepeatArgumentType arg, @Nonnull JsonObject json ) { json.addProperty( "flatten", arg.flatten ); json.addProperty( "child", "<>" ); // TODO: Potentially serialize this using reflection. diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java index d4d779c60..07c5d9ee6 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -13,12 +13,13 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import dan200.computercraft.shared.command.arguments.RepeatArgumentType; +import net.minecraft.commands.CommandSourceStack; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Predicate; import java.util.function.Supplier; -import net.minecraft.commands.CommandSourceStack; import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED; import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index 9ec64900b..286b25986 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -13,13 +13,14 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; -import javax.annotation.Nonnull; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextComponent; + +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collection; @@ -165,10 +166,10 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder helpNode = LiteralArgumentBuilder.literal( "help" ).requires( x -> getArguments().stream() - .anyMatch( - y -> y.getRequirement() - .test( - x ) ) ) + .anyMatch( + y -> y.getRequirement() + .test( + x ) ) ) .executes( helpCommand ); // Add all normal command children to this and the help node diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index 470f38618..6bce38c25 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -7,13 +7,7 @@ package dan200.computercraft.shared.command.text; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.ClickEvent; -import net.minecraft.network.chat.HoverEvent; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.Style; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.text.*; +import net.minecraft.network.chat.*; /** * Various helpers for building chat messages. diff --git a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java index 61e9e2b41..2076f77f0 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java @@ -6,12 +6,12 @@ package dan200.computercraft.shared.command.text; -import org.apache.commons.lang3.StringUtils; - -import javax.annotation.Nullable; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nullable; public class ServerTableFormatter implements TableFormatter { diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index 5808311dd..8bdc6495a 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -9,11 +9,12 @@ package dan200.computercraft.shared.command.text; import dan200.computercraft.shared.command.CommandUtils; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.ChatTableClientMessage; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index a9b2a2a3e..a3db10584 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -6,12 +6,12 @@ package dan200.computercraft.shared.command.text; -import org.apache.commons.lang3.StringUtils; - -import javax.annotation.Nullable; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nullable; import static dan200.computercraft.shared.command.text.ChatHelpers.coloured; import static dan200.computercraft.shared.command.text.ChatHelpers.translate; diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 29e071d87..3ed0c90c7 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -6,8 +6,6 @@ package dan200.computercraft.shared.common; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; @@ -21,6 +19,9 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Random; public abstract class BlockGeneric extends BaseEntityBlock @@ -47,7 +48,7 @@ public abstract class BlockGeneric extends BaseEntityBlock @Override @Deprecated public final void neighborChanged( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, - @Nonnull BlockPos neighbourPos, boolean isMoving ) + @Nonnull BlockPos neighbourPos, boolean isMoving ) { BlockEntity tile = world.getBlockEntity( pos ); if( tile instanceof TileGeneric ) @@ -78,7 +79,7 @@ public abstract class BlockGeneric extends BaseEntityBlock @Override @Deprecated public final InteractionResult use( @Nonnull BlockState state, Level world, @Nonnull BlockPos pos, @Nonnull Player player, @Nonnull InteractionHand hand, - @Nonnull BlockHitResult hit ) + @Nonnull BlockHitResult hit ) { BlockEntity tile = world.getBlockEntity( pos ); return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : InteractionResult.PASS; @@ -99,7 +100,7 @@ public abstract class BlockGeneric extends BaseEntityBlock @Override public BlockEntity newBlockEntity( BlockPos pos, BlockState state ) { - if ( this.type != null ) + if( this.type != null ) { return type.create( pos, state ); } diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index 5ea821b69..21c0282ad 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.common; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.DyeColor; @@ -18,6 +17,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class ColourableRecipe extends CustomRecipe { public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( ColourableRecipe::new ); @@ -63,7 +64,7 @@ public final class ColourableRecipe extends CustomRecipe @Nonnull @Override - public ItemStack craft( @Nonnull CraftingContainer inv ) + public ItemStack assemble( @Nonnull CraftingContainer inv ) { ItemStack colourable = ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 56a08e3a8..e3492864e 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -18,6 +18,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index 97bfd646a..09800368b 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -7,12 +7,13 @@ package dan200.computercraft.shared.common; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import javax.annotation.Nonnull; + public class DefaultBundledRedstoneProvider implements IBundledRedstoneProvider { @Override diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 87010f4a8..6a95c9e5b 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -8,9 +8,10 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.network.client.TerminalState; -import java.util.concurrent.atomic.AtomicBoolean; import net.minecraft.nbt.CompoundTag; +import java.util.concurrent.atomic.AtomicBoolean; + public class ServerTerminal implements ITerminal { private final boolean colour; diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index de99c3dbd..7363d0b4b 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; + import javax.annotation.Nonnull; public abstract class TileGeneric extends BlockEntity implements BlockEntityClientSerializable diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index b1dbe5778..25cce42ed 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -24,6 +24,7 @@ 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.minecraft.world.level.block.state.properties.Property; + import java.util.*; /** diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 35e249c34..af607e6bb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -10,8 +10,6 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.items.ComputerItemFactory; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; @@ -25,6 +23,9 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class BlockComputer extends BlockComputerBase { public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class ); @@ -61,12 +62,12 @@ public class BlockComputer extends BlockComputerBase public BlockEntityType getTypeByFamily( ComputerFamily family ) { - return switch ( family ) - { - case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND; - case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED; - default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL; - }; + return switch( family ) + { + case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND; + case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED; + default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL; + }; } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index f2cc48927..00dd5a4ea 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -13,8 +13,6 @@ import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; @@ -33,6 +31,9 @@ import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock { private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); @@ -126,7 +127,7 @@ public abstract class BlockComputerBase extends Bloc @Override public void playerDestroy( @Nonnull Level world, Player player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile, - @Nonnull ItemStack tool ) + @Nonnull ItemStack tool ) { // Don't drop blocks here - see onBlockHarvested. player.awardStat( Stats.BLOCK_MINED.get( this ) ); @@ -217,7 +218,7 @@ public abstract class BlockComputerBase extends Bloc public BlockEntityTicker getTicker( Level world, BlockState state, BlockEntityType type ) { return world.isClientSide ? null : ( world1, pos, state1, tile ) -> { - if ( tile instanceof TileComputerBase computer ) + if( tile instanceof TileComputerBase computer ) { computer.serverTick(); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 55d69dc16..75dffb0b9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -24,6 +24,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 0af1ae53a..82fbdeac4 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -13,8 +13,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.player.Inventory; @@ -23,6 +21,9 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class TileComputer extends TileComputerBase { private ComputerProxy proxy; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 47292b391..4cd86d5ef 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -41,6 +41,7 @@ import net.minecraft.world.level.block.RedStoneWireBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java index c2a9873c1..35f815cde 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java @@ -6,9 +6,10 @@ package dan200.computercraft.shared.computer.core; -import javax.annotation.Nonnull; import net.minecraft.util.StringRepresentable; +import javax.annotation.Nonnull; + public enum ComputerState implements StringRepresentable { OFF( "off", "" ), ON( "on", "_on" ), BLINKING( "blinking", "_blink" ); diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java index 442fbd8d8..f33461ab6 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java @@ -8,9 +8,10 @@ package dan200.computercraft.shared.computer.core; import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; +import net.minecraft.server.level.ServerPlayer; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.server.level.ServerPlayer; import java.util.List; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 11358dd53..cdc9fdcad 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -30,6 +30,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.InputStream; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java index 849f3e307..8b7971397 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java @@ -9,11 +9,12 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.InvisibleSlot; -import java.util.function.Predicate; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.MenuType; +import java.util.function.Predicate; + /** * A computer menu which does not have any visible inventory. * diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index e49be66a0..3579669e6 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -17,14 +17,15 @@ import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.UploadResultMessage; import dan200.computercraft.shared.network.container.ComputerContainerData; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerPlayer; 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 javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.nio.channels.WritableByteChannel; import java.util.*; @@ -53,7 +54,7 @@ public abstract class ContainerComputerBase extends AbstractContainerMenu implem } public ContainerComputerBase( MenuType type, int id, Predicate canUse, IComputer computer, - ComputerFamily family ) + ComputerFamily family ) { super( type, id ); this.canUse = canUse; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 9f186b4cb..3f7013dd2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -12,10 +12,11 @@ import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.container.ViewComputerContainerData; -import javax.annotation.Nonnull; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import javax.annotation.Nonnull; + public class ContainerViewComputer extends ComputerMenuWithoutInventory { private final int width; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index 0394db48b..30dd6286d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -9,9 +9,10 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public final class ComputerItemFactory { private ComputerItemFactory() {} diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index aa26b0c68..06a0e46ae 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -7,10 +7,11 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public interface IComputerItem { String NBT_ID = "ComputerId"; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index ad0563612..26b6c26f9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -8,10 +8,11 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; import net.minecraft.network.chat.TextComponent; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class ItemComputer extends ItemComputerBase { public ItemComputer( BlockComputer block, Properties settings ) diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index d02e7b7cf..93bd3bc03 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -12,8 +12,6 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.computer.blocks.BlockComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; @@ -22,6 +20,9 @@ import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index 168b7e131..1ac0f93e1 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.items.IComputerItem; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; @@ -16,6 +15,8 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + /** * Represents a recipe which converts a computer from one form into another. */ diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index a0c6df14c..148d5967a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -9,7 +9,6 @@ package dan200.computercraft.shared.computer.recipe; import com.google.gson.JsonObject; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.util.RecipeUtil; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; @@ -18,6 +17,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; +import javax.annotation.Nonnull; + public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe { private final ComputerFamily family; @@ -72,7 +73,7 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe } @Override - public void write( @Nonnull FriendlyByteBuf buf, @Nonnull T recipe ) + public void toNetwork( @Nonnull FriendlyByteBuf buf, @Nonnull T recipe ) { buf.writeVarInt( recipe.getWidth() ); buf.writeVarInt( recipe.getHeight() ); diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java index 0a54e4f50..7f10134eb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -8,13 +8,14 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; +import javax.annotation.Nonnull; + public class ComputerUpgradeRecipe extends ComputerFamilyRecipe { public static final RecipeSerializer SERIALIZER = diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index f24697123..03e534461 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.data; -import javax.annotation.Nonnull; import net.minecraft.world.Nameable; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.storage.loot.LootContext; @@ -14,6 +13,8 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParam; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; + +import javax.annotation.Nonnull; import java.util.Collections; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index d26e63910..8480a3a57 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -9,11 +9,12 @@ package dan200.computercraft.shared.data; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import javax.annotation.Nonnull; import net.minecraft.world.level.storage.loot.Serializer; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; +import javax.annotation.Nonnull; + public final class ConstantLootConditionSerializer implements Serializer { private final T instance; @@ -29,7 +30,7 @@ public final class ConstantLootConditionSerializer } @Override - public void toJson( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context ) + public void serialize( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context ) { } diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java index 6e7601a13..a2221e74b 100644 --- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -7,13 +7,14 @@ package dan200.computercraft.shared.data; import dan200.computercraft.shared.computer.blocks.IComputerTile; -import javax.annotation.Nonnull; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParam; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; + +import javax.annotation.Nonnull; import java.util.Collections; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index fe48d81e5..006c8779a 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.data; -import javax.annotation.Nonnull; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.loot.LootContext; @@ -14,6 +13,8 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParam; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; + +import javax.annotation.Nonnull; import java.util.Collections; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java index eaba346e6..08c311416 100644 --- a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java @@ -42,7 +42,7 @@ public class ModMenuIntegration implements ModMenuApi client.addEntry( entryBuilder.startEnumSelector( new TextComponent( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) .setDefaultValue( MonitorRenderer.BEST ) - .setSaveConsumer( renderer -> { Config.clientConfig.set( "monitor_renderer", renderer ); } ) + .setSaveConsumer( renderer -> {Config.clientConfig.set( "monitor_renderer", renderer );} ) .setTooltip( Component.nullToEmpty( Config.clientConfig.getComment( "monitor_renderer" ) ) ) .build() ); diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 5e6b1e2d8..f7b5731b9 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -13,8 +13,6 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.util.Colour; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.ChatFormatting; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; @@ -26,6 +24,9 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; public class ItemDisk extends Item implements IMedia, IColouredItem diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 1120116b5..b27525b76 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -9,7 +9,6 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.network.container.HeldItemContainerData; -import javax.annotation.Nonnull; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; @@ -21,6 +20,8 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; import java.util.List; public class ItemPrintout extends Item diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index b00df1647..5c0fbfceb 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -12,8 +12,6 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.filesystem.SubMount; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.Colour; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -23,6 +21,9 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.util.List; diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index c090111dd..ff63c44a1 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -6,13 +6,14 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.api.media.IMedia; -import javax.annotation.Nonnull; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.RecordItem; +import javax.annotation.Nonnull; + /** * An implementation of IMedia for ItemRecords. */ diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index 61ac56ab1..d2f479581 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -10,7 +10,6 @@ import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.DyeColor; @@ -22,6 +21,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public class DiskRecipe extends CustomRecipe { public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( DiskRecipe::new ); @@ -74,7 +75,7 @@ public class DiskRecipe extends CustomRecipe @Nonnull @Override - public ItemStack craft( @Nonnull CraftingContainer inv ) + public ItemStack assemble( @Nonnull CraftingContainer inv ) { ColourTracker tracker = new ColourTracker(); diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index 2652c7018..5c9b48cde 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.media.recipes; import dan200.computercraft.shared.media.items.ItemPrintout; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; @@ -18,6 +17,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class PrintoutRecipe extends CustomRecipe { public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( PrintoutRecipe::new ); @@ -40,12 +41,12 @@ public final class PrintoutRecipe extends CustomRecipe @Override public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { - return !craft( inventory ).isEmpty(); + return !assemble( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingContainer inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { // See if we match the recipe, and extract the input disk ID and dye colour int numPages = 0; diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 0d24ce401..7d82ef22d 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -32,6 +32,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.phys.Vec3; + import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; @@ -153,7 +154,7 @@ public final class NetworkHandler { for( Player player : chunk.getLevel().players() ) { - if ( chunk.getLevel().dimension().location() == player.getCommandSenderWorld().dimension().location() && player.chunkPosition().equals( chunk.getPos() ) ) + if( chunk.getLevel().dimension().location() == player.getCommandSenderWorld().dimension().location() && player.chunkPosition().equals( chunk.getPos() ) ) { ((ServerPlayer) player).connection.send( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) ); } diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index 1f4c387b4..bcffe6950 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared.network; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; /** diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index 224e3c4fe..b3f93804c 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -14,6 +14,7 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; + import javax.annotation.Nonnull; public class ChatTableClientMessage implements NetworkMessage diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java index a9611c524..1368866bc 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java @@ -9,9 +9,10 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.network.NetworkMessage; -import javax.annotation.Nonnull; import net.minecraft.network.FriendlyByteBuf; +import javax.annotation.Nonnull; + /** * A packet, which performs an action on a {@link ClientComputer}. */ diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index 85f271ec4..8092fb5c5 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -11,6 +11,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; /** diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index 6e0b4cf1a..447ab42a6 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared.network.client; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; public class ComputerTerminalClientMessage extends ComputerClientMessage diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java index b003a6a88..00289ce75 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -13,6 +13,7 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.block.entity.BlockEntity; + import javax.annotation.Nonnull; public class MonitorClientMessage implements NetworkMessage diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index cc5c2a49a..4ee745101 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -16,6 +16,7 @@ import net.minecraft.core.Registry; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.TextComponent; import net.minecraft.sounds.SoundEvent; + import javax.annotation.Nonnull; /** diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java index a8e131ca2..f00c35d33 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerMoveClientMessage.java @@ -12,6 +12,7 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java index 9c93516f9..f0c8f7ecc 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerPlayClientMessage.java @@ -13,6 +13,7 @@ import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java index 5a14a23a6..ab7d5c57e 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/SpeakerStopClientMessage.java @@ -11,6 +11,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java index 49d704f8b..1b7bd8504 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java +++ b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java @@ -11,8 +11,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; -import javax.annotation.Nullable; import net.minecraft.network.FriendlyByteBuf; + +import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; diff --git a/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java b/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java index 3dbaa8406..8d8283665 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/UploadResultMessage.java @@ -14,6 +14,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; + import javax.annotation.Nonnull; public class UploadResultMessage implements NetworkMessage diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index 9f04a309a..2fd9e0406 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -14,6 +14,7 @@ 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 javax.annotation.Nonnull; import java.util.function.Function; @@ -30,6 +31,7 @@ public interface ContainerData playerInventory, reader.apply( packetByteBuf ) ) ); } + static MenuType toType( ResourceLocation identifier, MenuType type, Function reader, FixedFactory factory ) { @@ -43,7 +45,7 @@ public interface ContainerData default void open( Player player, MenuProvider owner ) { - if ( player.level.isClientSide ) return; + if( player.level.isClientSide ) return; player.openMenu( owner ); } diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index a63f6da75..04f9a2af3 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -7,10 +7,11 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.common.ContainerHeldItem; -import javax.annotation.Nonnull; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.InteractionHand; +import javax.annotation.Nonnull; + /** * Opens a printout GUI based on the currently held item. * diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index dc4cf0850..842783c1a 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -8,9 +8,10 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ServerComputer; -import javax.annotation.Nonnull; import net.minecraft.network.FriendlyByteBuf; +import javax.annotation.Nonnull; + /** * View an arbitrary computer on the client. * diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index d9bf0e045..212dd6eae 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -10,6 +10,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; public class ComputerActionServerMessage extends ComputerServerMessage diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index a4444ca44..867f5dcd4 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -12,6 +12,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; /** diff --git a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java index 038bb9278..bc1e0847a 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java @@ -10,6 +10,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; + import javax.annotation.Nonnull; public class ContinueUploadMessage extends ComputerServerMessage diff --git a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index b2408449b..99c514933 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -11,6 +11,7 @@ import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; public class KeyEventServerMessage extends ComputerServerMessage diff --git a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index 5959fca6b..024ca7547 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -11,6 +11,7 @@ import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.computer.core.ServerComputer; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; public class MouseEventServerMessage extends ComputerServerMessage diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index 991ee5a27..04506ad0f 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -12,6 +12,7 @@ import dan200.computercraft.shared.util.NBTUtil; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java index f7da4af24..81151437a 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java @@ -11,6 +11,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkMessage; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; + import javax.annotation.Nonnull; public class RequestComputerMessage implements NetworkMessage diff --git a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java index 8a1bd4f66..bf2ccc9d8 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java @@ -15,6 +15,7 @@ import io.netty.handler.codec.DecoderException; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; + import javax.annotation.Nonnull; import java.nio.ByteBuffer; import java.util.ArrayList; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index b6ada9750..1453aa7c7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -10,10 +10,11 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.computer.apis.CommandAPI; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.CommandBlockEntity; +import javax.annotation.Nonnull; + /** * This peripheral allows you to interact with command blocks. * diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java index 37e05fbc6..3839d391c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -8,8 +8,6 @@ package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.stats.Stats; @@ -29,6 +27,9 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class BlockDiskDrive extends BlockGeneric { static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index a5d2245d7..5053c5f0b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.shared.ComputerCraftRegistry; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; @@ -16,6 +15,8 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class ContainerDiskDrive extends AbstractContainerMenu { private final Container inventory; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index fe074ca4c..1be070474 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -14,9 +14,10 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.util.StringUtil; +import net.minecraft.world.item.ItemStack; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.item.ItemStack; import java.util.Optional; /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java index 1891bf501..cbd06d69c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -6,9 +6,10 @@ package dan200.computercraft.shared.peripheral.diskdrive; -import javax.annotation.Nonnull; import net.minecraft.util.StringRepresentable; +import javax.annotation.Nonnull; + public enum DiskDriveState implements StringRepresentable { EMPTY( "empty" ), FULL( "full" ), INVALID( "invalid" ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 529aadab2..b209601b4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -17,8 +17,6 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.util.DefaultInventory; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.RecordUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -38,6 +36,9 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java index 48bcf77c5..6e75ebd32 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -12,11 +12,12 @@ import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; class GenericPeripheral implements IDynamicPeripheral diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index a6dfbe1a2..d77203984 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -8,12 +8,13 @@ package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.asm.NamedMethod; import dan200.computercraft.core.asm.PeripheralMethod; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index ad965520c..352d37669 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -6,9 +6,10 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.common.collect.ImmutableMap; -import javax.annotation.Nonnull; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; + +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java index fd771675b..86bcd9d4f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -5,13 +5,14 @@ */ package dan200.computercraft.shared.peripheral.generic.data; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.level.block.Block; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -19,7 +20,7 @@ import java.util.Map; public final class DataHelpers { private DataHelpers() - { } + {} @Nonnull public static Map getTags( @Nonnull Collection tags ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 61cb8e68a..314a645e0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,8 +7,6 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; import dan200.computercraft.shared.util.NBTUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -21,6 +19,9 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentHelper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 30e1ef920..7be7113b5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -14,13 +14,14 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Container; import net.minecraft.world.Nameable; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -289,7 +290,7 @@ public class InventoryMethods implements GenericSource return ItemStorage.wrap( inventory ); } } - else if ( object instanceof Container ) + else if( object instanceof Container ) { return ItemStorage.wrap( (Container) object ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 3367fe068..fec0609ae 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -14,9 +14,10 @@ import dan200.computercraft.api.network.IPacketSender; import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java index ffec375cd..365abeca4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.peripheral.modem; -import javax.annotation.Nonnull; import net.minecraft.core.Direction; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import javax.annotation.Nonnull; + public final class ModemShapes { private static final VoxelShape[] BOXES = new VoxelShape[] { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 8c78bc226..f338e29b4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -14,16 +14,11 @@ import dan200.computercraft.shared.util.WorldUtil; import net.fabricmc.fabric.api.block.BlockPickInteractionAware; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.*; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.*; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SimpleWaterloggedBlock; import net.minecraft.world.level.block.entity.BlockEntity; @@ -36,6 +31,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.EnumMap; @@ -55,7 +51,7 @@ public class BlockCable extends BlockGeneric implements SimpleWaterloggedBlock, private static final BooleanProperty DOWN = BooleanProperty.create( "down" ); static final EnumMap CONNECTIONS = new EnumMap<>( new ImmutableMap.Builder().put( Direction.DOWN, - DOWN ) + DOWN ) .put( Direction.UP, UP ) .put( Direction.NORTH, @@ -94,7 +90,7 @@ public class BlockCable extends BlockGeneric implements SimpleWaterloggedBlock, @Override @Deprecated public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); // Should never happen, but handle the case where we've no modem or cable. diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 4b9d98423..2f14df974 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -17,6 +16,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BooleanProperty; +import javax.annotation.Nullable; + public class BlockWiredModemFull extends BlockGeneric { public static final BooleanProperty MODEM_ON = BooleanProperty.create( "modem" ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index be6b6e1f3..132cb0718 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.peripheral.modem.wired; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.Direction; import net.minecraft.util.StringRepresentable; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public enum CableModemVariant implements StringRepresentable { None( "none", null ), diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java index dbb270816..11e401df9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -9,12 +9,13 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; import dan200.computercraft.shared.peripheral.modem.ModemShapes; import dan200.computercraft.shared.util.DirectionUtil; -import java.util.EnumMap; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import java.util.EnumMap; + import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; public final class CableShapes @@ -25,13 +26,13 @@ public final class CableShapes private static final VoxelShape SHAPE_CABLE_CORE = Shapes.box( MIN, MIN, MIN, MAX, MAX, MAX ); private static final EnumMap SHAPE_CABLE_ARM = new EnumMap<>( new ImmutableMap.Builder().put( Direction.DOWN, - Shapes.box( - MIN, - 0, - MIN, - MAX, - MIN, - MAX ) ) + Shapes.box( + MIN, + 0, + MIN, + MAX, + MIN, + MAX ) ) .put( Direction.UP, Shapes.box( MIN, diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index ec5e4872c..4eadf5d4a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.ComputerCraftRegistry; -import javax.annotation.Nonnull; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -25,6 +24,8 @@ import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import javax.annotation.Nonnull; + import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; public abstract class ItemBlockCable extends BlockItem diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 75d14193f..fefdf28c3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -18,8 +18,6 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.TickScheduler; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -34,6 +32,9 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 62073dbff..11dd6ebfe 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -17,7 +17,6 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.TickScheduler; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -31,6 +30,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; import java.util.*; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index d670aa68b..7f52306bf 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -11,13 +11,14 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.Peripherals; import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.NBTUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 7574018cf..aae60b894 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -22,9 +22,10 @@ import dan200.computercraft.core.apis.PeripheralAPI; import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; +import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import javax.annotation.Nullable; -import net.minecraft.world.level.Level; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index 979212717..87616f005 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -10,8 +10,6 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.peripheral.modem.ModemShapes; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; @@ -31,6 +29,9 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import static dan200.computercraft.shared.util.WaterloggableHelpers.*; public class BlockWirelessModem extends BlockGeneric implements SimpleWaterloggedBlock @@ -54,7 +55,7 @@ public class BlockWirelessModem extends BlockGeneric implements SimpleWaterlogge @Override @Deprecated public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return side == state.getValue( FACING ) && !state.canSurvive( world, pos ) ? state.getFluidState() @@ -90,8 +91,8 @@ public class BlockWirelessModem extends BlockGeneric implements SimpleWaterlogge public BlockState getStateForPlacement( BlockPlaceContext placement ) { return defaultBlockState().setValue( FACING, - placement.getClickedFace() - .getOpposite() ) + placement.getClickedFace() + .getOpposite() ) .setValue( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); } @@ -103,11 +104,11 @@ public class BlockWirelessModem extends BlockGeneric implements SimpleWaterlogge public BlockEntityType getTypeByFamily( ComputerFamily family ) { - return switch ( family ) - { - case ADVANCED -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED; - default -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL; - }; + return switch( family ) + { + case ADVANCED -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED; + default -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL; + }; } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 0f44deaf5..b1a3379e8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -12,7 +12,6 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.TickScheduler; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; @@ -20,6 +19,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; + public class TileWirelessModem extends TileGeneric implements IPeripheralTile { private final boolean advanced; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 82e9b776d..b760dfce8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -9,8 +9,6 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.api.turtle.FakePlayer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.LivingEntity; @@ -26,6 +24,9 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class BlockMonitor extends BlockGeneric { public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation", Direction.UP, Direction.DOWN, Direction.NORTH ); @@ -69,14 +70,14 @@ public class BlockMonitor extends BlockGeneric } return defaultBlockState().setValue( FACING, - context.getHorizontalDirection() - .getOpposite() ) + context.getHorizontalDirection() + .getOpposite() ) .setValue( ORIENTATION, orientation ); } @Override public void setPlacedBy( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, - @Nonnull ItemStack itemStack ) + @Nonnull ItemStack itemStack ) { super.setPlacedBy( world, pos, blockState, livingEntity, itemStack ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index 9568cf1f3..d45a52a4f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -6,9 +6,10 @@ package dan200.computercraft.shared.peripheral.monitor; -import javax.annotation.Nonnull; import net.minecraft.util.StringRepresentable; +import javax.annotation.Nonnull; + import static dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState.Flags.*; public enum MonitorEdgeState implements StringRepresentable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index c6299cab3..f86791dad 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -15,7 +15,6 @@ import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.util.TickScheduler; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -27,6 +26,8 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; + +import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index ce267cc12..dffbedde4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -8,8 +8,6 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.stats.Stats; @@ -27,6 +25,9 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class BlockPrinter extends BlockGeneric { static final BooleanProperty TOP = BooleanProperty.create( "top" ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index f32db943a..0e0e04e16 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.SingleIntArray; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; @@ -19,6 +18,8 @@ import net.minecraft.world.inventory.SimpleContainerData; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class ContainerPrinter extends AbstractContainerMenu { private final Container inventory; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 505a86f7d..7f8dd4737 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -15,19 +15,13 @@ import dan200.computercraft.shared.util.ColourUtils; import dan200.computercraft.shared.util.DefaultSidedInventory; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.Nameable; +import net.minecraft.world.*; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -40,6 +34,9 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, Nameable, MenuProvider { static final int SLOTS = 13; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index 6af719802..73ac34bfc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.common.BlockGeneric; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; @@ -22,6 +21,8 @@ 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 javax.annotation.Nullable; + public class BlockSpeaker extends BlockGeneric { private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 1c990c874..88c5655d1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -24,6 +24,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; import java.util.Optional; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index e062a3e65..336d81ca2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -9,14 +9,15 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.UUID; public class TileSpeaker extends TileGeneric implements IPeripheralTile diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index 3b69c6d1b..59abef12b 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -17,8 +17,6 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.NBTUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -28,6 +26,9 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java index 47edf5f3e..8cef2a65c 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/PocketComputerMenuProvider.java @@ -19,6 +19,7 @@ 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 javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index ca845be99..b98426359 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -43,6 +43,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index e7554d664..dec881201 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -9,9 +9,10 @@ package dan200.computercraft.shared.pocket.items; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public final class PocketComputerItemFactory { private PocketComputerItemFactory() {} diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index 7735aa453..2d069d423 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -11,11 +11,12 @@ import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.peripheral.modem.ModemState; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class PocketModem extends AbstractPocketUpgrade { private final boolean advanced; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index abf9bde16..f13b41927 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -9,10 +9,11 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; +import javax.annotation.Nonnull; + public class PocketModemPeripheral extends WirelessModemPeripheral { private Level world = null; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index beaa53a36..8e775eb9d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -10,11 +10,12 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.ComputerCraftRegistry; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class PocketSpeaker extends AbstractPocketUpgrade { public PocketSpeaker() diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index a952baaa1..a5c7e78a5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -11,7 +11,6 @@ import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; @@ -20,6 +19,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class PocketComputerUpgradeRecipe extends CustomRecipe { public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( PocketComputerUpgradeRecipe::new ); @@ -39,12 +40,12 @@ public final class PocketComputerUpgradeRecipe extends CustomRecipe @Override public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { - return !craft( inventory ).isEmpty(); + return !assemble( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingContainer inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { // Scan the grid for a pocket computer ItemStack computer = ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index d617ae3aa..27de26e94 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -126,7 +126,10 @@ public final class ComputerCraftProxyCommon } ); PlayerBlockBreakEvents.BEFORE.register( ( world, player, pos, state, blockEntity ) -> { - if ( state.getBlock() instanceof BlockCable blockCable ) return blockCable.removedByPlayer( state, world, pos, player, false, null ); + if( state.getBlock() instanceof BlockCable blockCable ) + { + return blockCable.removedByPlayer( state, world, pos, player, false, null ); + } return true; } ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index fd32629bc..ab02d655a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -12,11 +12,12 @@ import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.FurnaceBlockEntity; +import javax.annotation.Nonnull; + public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler { public static final FurnaceRefuelHandler INSTANCE = new FurnaceRefuelHandler(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java index 7cfbeb8af..574274d97 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java @@ -7,12 +7,12 @@ package dan200.computercraft.shared.turtle; import com.google.common.eventbus.Subscribe; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.fabric.mixin.SignBlockEntityAccess; -import java.util.HashMap; -import java.util.Map; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import java.util.HashMap; +import java.util.Map; + public class SignInspectHandler { @Subscribe @@ -25,7 +25,7 @@ public class SignInspectHandler Map textTable = new HashMap<>(); for( int k = 0; k < 4; k++ ) { - textTable.put( k + 1, ((SignBlockEntityAccess) sbe).getTexts()[k].getContents() ); + textTable.put( k + 1, sbe.getMessage( k, true ).getString() ); } event.getData().put( "text", textTable ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index dc18b63cc..240a8d24f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -19,10 +19,11 @@ import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.turtle.core.*; +import net.minecraft.world.item.ItemStack; + import java.util.HashMap; import java.util.Map; import java.util.Optional; -import net.minecraft.world.item.ItemStack; /** * The turtle API allows you to control your turtle. diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index a30399a23..72b3f477b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -14,7 +14,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import net.minecraft.block.*; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; @@ -40,6 +39,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -72,7 +72,7 @@ public class BlockTurtle extends BlockComputerBase implements Simple @Override @Deprecated public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, - @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) + @Nonnull LevelAccessor world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return state; @@ -184,7 +184,7 @@ public class BlockTurtle extends BlockComputerBase implements Simple public BlockEntityType getTypeByFamily( ComputerFamily family ) { - if ( family == ComputerFamily.ADVANCED ) + if( family == ComputerFamily.ADVANCED ) { return ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 483aa134b..e8aa67876 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -22,8 +22,6 @@ import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.util.*; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; @@ -43,18 +41,21 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; public class TileTurtle extends TileComputerBase - implements ITurtleTile, DefaultInventory + implements ITurtleTile, DefaultInventory { public static final int INVENTORY_SIZE = 16; public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; private final NonNullList inventory = NonNullList - .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); private final NonNullList previousInventory = NonNullList - .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + .withSize( INVENTORY_SIZE, ItemStack.EMPTY ); private boolean inventoryChanged = false; private TurtleBrain brain = new TurtleBrain( this ); private MoveState moveState = MoveState.NOT_MOVED; @@ -134,7 +135,7 @@ public class TileTurtle extends TileComputerBase public ItemStack getItem( int slot ) { return slot >= 0 && slot < INVENTORY_SIZE ? inventory.get( slot ) - : ItemStack.EMPTY; + : ItemStack.EMPTY; } @Nonnull @@ -176,7 +177,7 @@ public class TileTurtle extends TileComputerBase public void setItem( int i, @Nonnull ItemStack stack ) { if( i >= 0 && i < INVENTORY_SIZE - && !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) + && !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) { inventory.set( i, stack ); onInventoryDefinitelyChanged(); @@ -227,7 +228,7 @@ public class TileTurtle extends TileComputerBase return InteractionResult.SUCCESS; } else if( currentItem.getItem() == Items.WATER_BUCKET - && brain.getColour() != -1 ) + && brain.getColour() != -1 ) { // Water to remove turtle colour if( !getLevel().isClientSide ) @@ -238,7 +239,7 @@ public class TileTurtle extends TileComputerBase if( !player.isCreative() ) { player.setItemInHand( hand, - new ItemStack( Items.BUCKET ) ); + new ItemStack( Items.BUCKET ) ); player.getInventory().setChanged(); } } @@ -270,7 +271,7 @@ public class TileTurtle extends TileComputerBase } @Override - public void serverTick( ) + public void serverTick() { super.serverTick(); brain.update(); @@ -297,7 +298,7 @@ public class TileTurtle extends TileComputerBase @Override protected void updateBlockState( ComputerState newState ) - { } + {} @Nonnull @Override @@ -367,8 +368,8 @@ public class TileTurtle extends TileComputerBase protected ServerComputer createComputer( int instanceID, int id ) { ServerComputer computer = new ServerComputer( getLevel(), id, label, instanceID, - getFamily(), ComputerCraft.turtleTermWidth, - ComputerCraft.turtleTermHeight ); + getFamily(), ComputerCraft.turtleTermWidth, + ComputerCraft.turtleTermHeight ); computer.setPosition( getBlockPos() ); computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) ); brain.setupComputer( computer ); @@ -415,7 +416,7 @@ public class TileTurtle extends TileComputerBase private boolean hasPeripheralUpgradeOnSide( ComputerSide side ) { ITurtleUpgrade upgrade; - switch ( side ) + switch( side ) { case RIGHT: upgrade = getUpgrade( TurtleSide.RIGHT ); @@ -558,7 +559,7 @@ public class TileTurtle extends TileComputerBase @Nullable @Override public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, - @Nonnull Player player ) + @Nonnull Player player ) { return new ContainerTurtle( id, inventory, brain ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 3e4df5600..d00fbdd03 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -20,8 +20,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.util.*; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.particles.ParticleTypes; @@ -40,6 +38,9 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index 1b6339af2..c18fe8b44 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -9,7 +9,6 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -17,6 +16,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nonnull; import java.util.List; public class TurtleCompareCommand implements ITurtleCommand diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index ac4ed2f75..c2f0261c3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -10,9 +10,10 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.InventoryUtil; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class TurtleCompareToCommand implements ITurtleCommand { private final int slot; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index 83fa33645..80af2ff7e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -13,8 +13,9 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.turtle.upgrades.TurtleInventoryCrafting; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nonnull; import java.util.List; public class TurtleCraftCommand implements ITurtleCommand diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index ce9a88690..b35416964 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -10,11 +10,12 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public class TurtleDetectCommand implements ITurtleCommand { private final InteractDirection direction; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 02b5a9f5f..81fc98340 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -15,13 +15,14 @@ import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public class TurtleDropCommand implements ITurtleCommand { private final InteractDirection direction; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index 865f6dae6..e2bc8f065 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -14,11 +14,12 @@ import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class TurtleEquipCommand implements ITurtleCommand { private final TurtleSide side; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index bdb4e25e0..f65811149 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -12,12 +12,13 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.peripheral.generic.data.BlockData; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; + +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index bae8eae89..4d7092230 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -15,7 +15,6 @@ import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.Entity; @@ -24,6 +23,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; + +import javax.annotation.Nonnull; import java.util.List; public class TurtleMoveCommand implements ITurtleCommand diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index f38ee775b..2d92ddd14 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -20,21 +20,13 @@ import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.item.*; import net.minecraft.network.chat.TextComponent; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.BoatItem; -import net.minecraft.world.item.BottleItem; -import net.minecraft.world.item.BucketItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.SignItem; -import net.minecraft.world.item.WaterLilyBlockItem; +import net.minecraft.world.item.*; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 73b6a6113..bb00bbedd 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -14,8 +14,6 @@ import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -31,6 +29,9 @@ import net.minecraft.world.entity.animal.horse.AbstractHorse; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.OptionalInt; import java.util.UUID; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index be8a3585c..51a71febf 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -12,9 +12,10 @@ import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class TurtleRefuelCommand implements ITurtleCommand { private final int limit; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 74897fbe6..be448c095 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -14,7 +14,6 @@ import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.Container; @@ -23,6 +22,8 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; + +import javax.annotation.Nonnull; import java.util.List; public class TurtleSuckCommand implements ITurtleCommand diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index eb98cd731..e641cfd04 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -11,9 +11,10 @@ import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.InventoryUtil; -import javax.annotation.Nonnull; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class TurtleTransferToCommand implements ITurtleCommand { private final int slot; diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 1e25ce1c7..144ceb4c8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -15,7 +15,6 @@ import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.util.SingleIntArray; -import javax.annotation.Nonnull; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; @@ -25,6 +24,8 @@ import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.inventory.SimpleContainerData; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nonnull; import java.util.function.Predicate; public class ContainerTurtle extends ContainerComputerBase diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java index 52cadb86b..92021a9e7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java @@ -10,11 +10,12 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.items.IComputerItem; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public interface ITurtleItem extends IComputerItem, IColouredItem { @Nullable diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 8843e6a56..fe08e07ed 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -13,7 +13,6 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.ItemComputerBase; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -23,6 +22,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + import static dan200.computercraft.shared.turtle.core.TurtleBrain.*; public class ItemTurtle extends ItemComputerBase implements ITurtleItem diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 908dd8709..f829b2dde 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -12,10 +12,11 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.ITurtleTile; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public final class TurtleItemFactory { private TurtleItemFactory() {} diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index f4e53bef9..7a3c94d61 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -10,13 +10,14 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; +import javax.annotation.Nonnull; + public final class TurtleRecipe extends ComputerFamilyRecipe { public static final RecipeSerializer SERIALIZER = diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index c68a539de..53d73c2f6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -12,7 +12,6 @@ import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import javax.annotation.Nonnull; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; @@ -21,6 +20,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class TurtleUpgradeRecipe extends CustomRecipe { public static final RecipeSerializer SERIALIZER = new SimpleRecipeSerializer<>( TurtleUpgradeRecipe::new ); @@ -40,12 +41,12 @@ public final class TurtleUpgradeRecipe extends CustomRecipe @Override public boolean matches( @Nonnull CraftingContainer inventory, @Nonnull Level world ) { - return !craft( inventory ).isEmpty(); + return !assemble( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack craft( @Nonnull CraftingContainer inventory ) + public ItemStack assemble( @Nonnull CraftingContainer inventory ) { // Scan the grid for a row containing a turtle and 1 or 2 items ItemStack leftItem = ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index d238dc706..f80b95859 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -17,6 +17,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Blocks; + import javax.annotation.Nonnull; public class TurtleCraftingTable extends AbstractTurtleUpgrade diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index e6e5ecf6e..c3098a2af 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -12,7 +12,6 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; @@ -22,6 +21,8 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; +import javax.annotation.Nonnull; + public class TurtleHoe extends TurtleTool { public TurtleHoe( ResourceLocation id, String adjective, Item item ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index eb264d95b..1c2d0189b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -9,8 +9,6 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.NonNullList; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; @@ -19,6 +17,9 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 4c82d30b4..97a0851c9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -21,6 +21,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; public class TurtleModem extends AbstractTurtleUpgrade diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 9255cccb2..a9684cedf 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -12,7 +12,6 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; @@ -22,6 +21,8 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; +import javax.annotation.Nonnull; + public class TurtleShovel extends TurtleTool { public TurtleShovel( ResourceLocation id, String adjective, Item item ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index e074a9237..bd35ecd90 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -20,6 +20,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; + import javax.annotation.Nonnull; public class TurtleSpeaker extends AbstractTurtleUpgrade diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index d37811c43..c25d9dbef 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -30,7 +30,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.math.*; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 26f518c22..cb288ef30 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -6,12 +6,13 @@ package dan200.computercraft.shared.util; -import javax.annotation.Nullable; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nullable; + public final class ColourUtils { @Nullable diff --git a/src/main/java/dan200/computercraft/shared/util/CommentedConfigSpec.java b/src/main/java/dan200/computercraft/shared/util/CommentedConfigSpec.java index 830eb4a5a..e41d1bcc8 100644 --- a/src/main/java/dan200/computercraft/shared/util/CommentedConfigSpec.java +++ b/src/main/java/dan200/computercraft/shared/util/CommentedConfigSpec.java @@ -32,7 +32,7 @@ public class CommentedConfigSpec extends ConfigSpec @Override public int correct( Config config ) { - return correct( config, ( action, path, incorrectValue, correctedValue ) -> { } ); + return correct( config, ( action, path, incorrectValue, correctedValue ) -> {} ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java index cb62f47f0..0fc7fc4a6 100644 --- a/src/main/java/dan200/computercraft/shared/util/Config.java +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -16,12 +16,13 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRuleConfig; -import dan200.computercraft.fabric.mixin.WorldSavePathAccess; +import dan200.computercraft.fabric.mixin.LevelResourceAccess; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import net.fabricmc.loader.FabricLoader; import net.minecraft.client.Minecraft; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.storage.LevelResource; + import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -40,7 +41,7 @@ public final class Config public static CommentedFileConfig serverConfig; public static CommentedFileConfig clientConfig; - private static final LevelResource serverDir = WorldSavePathAccess.createWorldSavePath( "serverconfig" ); + private static final LevelResource serverDir = LevelResourceAccess.create( "serverconfig" ); private static final String serverFileName = "computercraft-server.toml"; private static Path serverPath = null; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 4a6699444..6d5b07a86 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public interface DefaultInventory extends Container { @Override diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index 80c1f34c9..47f92a51d 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -6,12 +6,13 @@ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import net.minecraft.core.Direction; import net.minecraft.world.WorldlyContainer; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public interface DefaultSidedInventory extends DefaultInventory, WorldlyContainer { @Override diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index a33bc2928..7ceba6b3f 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -6,10 +6,6 @@ package dan200.computercraft.shared.util; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.item.ItemEntity; @@ -17,6 +13,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + public final class DropConsumer { private static Function dropConsumer; diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index 440665855..38a8eecd1 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -14,54 +14,11 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; import net.minecraft.network.chat.Component; -import net.minecraft.network.packet.c2s.play.*; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; -import net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket; -import net.minecraft.network.protocol.game.ServerboundBlockEntityTagQuery; -import net.minecraft.network.protocol.game.ServerboundChangeDifficultyPacket; -import net.minecraft.network.protocol.game.ServerboundChatPacket; -import net.minecraft.network.protocol.game.ServerboundClientCommandPacket; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.network.protocol.game.ServerboundCommandSuggestionPacket; -import net.minecraft.network.protocol.game.ServerboundContainerButtonClickPacket; -import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; -import net.minecraft.network.protocol.game.ServerboundContainerClosePacket; -import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; -import net.minecraft.network.protocol.game.ServerboundEditBookPacket; -import net.minecraft.network.protocol.game.ServerboundEntityTagQuery; -import net.minecraft.network.protocol.game.ServerboundInteractPacket; -import net.minecraft.network.protocol.game.ServerboundJigsawGeneratePacket; -import net.minecraft.network.protocol.game.ServerboundKeepAlivePacket; -import net.minecraft.network.protocol.game.ServerboundLockDifficultyPacket; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket; -import net.minecraft.network.protocol.game.ServerboundPaddleBoatPacket; -import net.minecraft.network.protocol.game.ServerboundPickItemPacket; -import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket; -import net.minecraft.network.protocol.game.ServerboundPlayerAbilitiesPacket; -import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; -import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; -import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; -import net.minecraft.network.protocol.game.ServerboundRecipeBookChangeSettingsPacket; -import net.minecraft.network.protocol.game.ServerboundRecipeBookSeenRecipePacket; -import net.minecraft.network.protocol.game.ServerboundRenameItemPacket; -import net.minecraft.network.protocol.game.ServerboundResourcePackPacket; -import net.minecraft.network.protocol.game.ServerboundSeenAdvancementsPacket; -import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; -import net.minecraft.network.protocol.game.ServerboundSetBeaconPacket; -import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket; -import net.minecraft.network.protocol.game.ServerboundSetCommandBlockPacket; -import net.minecraft.network.protocol.game.ServerboundSetCommandMinecartPacket; -import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket; -import net.minecraft.network.protocol.game.ServerboundSetJigsawBlockPacket; -import net.minecraft.network.protocol.game.ServerboundSetStructureBlockPacket; -import net.minecraft.network.protocol.game.ServerboundSignUpdatePacket; -import net.minecraft.network.protocol.game.ServerboundSwingPacket; -import net.minecraft.network.protocol.game.ServerboundTeleportToEntityPacket; -import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; -import net.minecraft.network.protocol.game.ServerboundUseItemPacket; +import net.minecraft.network.protocol.game.*; import net.minecraft.server.network.ServerGamePacketListenerImpl; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.crypto.Cipher; diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 0c4b14ec9..19a37cb91 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -10,10 +10,11 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.fabric.mixin.WorldSavePathAccess; +import dan200.computercraft.fabric.mixin.LevelResourceAccess; import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.storage.LevelResource; + import java.io.File; import java.io.Reader; import java.io.Writer; @@ -27,7 +28,7 @@ import java.util.Map; public final class IDAssigner { - private static final LevelResource FOLDER = WorldSavePathAccess.createWorldSavePath( ComputerCraft.MOD_ID ); + private static final LevelResource FOLDER = LevelResourceAccess.create( ComputerCraft.MOD_ID ); private static final Gson GSON = new GsonBuilder().setPrettyPrinting() .create(); private static final Type ID_TOKEN = new TypeToken>() diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index eed47d8d8..e9c39bc97 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonObject; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; @@ -19,6 +18,8 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class ImpostorRecipe extends ShapedRecipe { public static final RecipeSerializer SERIALIZER = new RecipeSerializer() @@ -50,7 +51,7 @@ public final class ImpostorRecipe extends ShapedRecipe } @Override - public void write( @Nonnull FriendlyByteBuf buf, @Nonnull ImpostorRecipe recipe ) + public void toNetwork( @Nonnull FriendlyByteBuf buf, @Nonnull ImpostorRecipe recipe ) { buf.writeVarInt( recipe.getWidth() ); buf.writeVarInt( recipe.getHeight() ); diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index c5c44a1a0..9b35f3146 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -9,7 +9,6 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import javax.annotation.Nonnull; import net.minecraft.core.NonNullList; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; @@ -22,6 +21,8 @@ import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraft.world.level.Level; +import javax.annotation.Nonnull; + public final class ImpostorShapelessRecipe extends ShapelessRecipe { public static final RecipeSerializer SERIALIZER = new RecipeSerializer() @@ -78,7 +79,7 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe } @Override - public void write( @Nonnull FriendlyByteBuf buffer, @Nonnull ImpostorShapelessRecipe recipe ) + public void toNetwork( @Nonnull FriendlyByteBuf buffer, @Nonnull ImpostorShapelessRecipe recipe ) { buffer.writeUtf( recipe.getGroup() ); buffer.writeVarInt( recipe.getIngredients() diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java index 9dbbfffd8..88c548cb1 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nonnull; import java.util.Set; /** diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 4dc196e95..c520c0646 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -6,9 +6,6 @@ package dan200.computercraft.shared.util; -import org.apache.commons.lang3.tuple.Pair; - -import javax.annotation.Nonnull; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.Container; @@ -22,6 +19,9 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nonnull; public final class InventoryUtil { diff --git a/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java b/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java index eea17b41f..cea2cb706 100644 --- a/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/InvisibleSlot.java @@ -5,12 +5,13 @@ */ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class InvisibleSlot extends Slot { public InvisibleSlot( Container container, int slot ) diff --git a/src/main/java/dan200/computercraft/shared/util/ItemStorage.java b/src/main/java/dan200/computercraft/shared/util/ItemStorage.java index b11f445d5..dcca803fe 100644 --- a/src/main/java/dan200/computercraft/shared/util/ItemStorage.java +++ b/src/main/java/dan200/computercraft/shared/util/ItemStorage.java @@ -5,12 +5,13 @@ */ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; import net.minecraft.core.Direction; import net.minecraft.world.Container; import net.minecraft.world.WorldlyContainer; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + /** * The most cutesy alternative of {@code IItemHandler} the world has ever seen. */ diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index 42d8d651c..24babefbc 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -11,19 +11,21 @@ import com.google.common.collect.Sets; import com.google.gson.*; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dan200.computercraft.shared.computer.core.ComputerFamily; -import java.util.Map; -import java.util.Set; import net.minecraft.core.NonNullList; import net.minecraft.nbt.TagParser; import net.minecraft.util.GsonHelper; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import java.util.Map; +import java.util.Set; + // TODO: Replace some things with Forge?? public final class RecipeUtil { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + private RecipeUtil() {} public static ShapedTemplate getTemplate( JsonObject json ) @@ -114,7 +116,7 @@ public final class RecipeUtil public static void setNbt( ItemStack itemStack, JsonObject result ) { JsonElement nbtElement = result.get( "nbt" ); - if ( nbtElement != null ) + if( nbtElement != null ) { try { diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 31917f7ad..3ba67807b 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -8,13 +8,14 @@ package dan200.computercraft.shared.util; import com.google.common.collect.MapMaker; import dan200.computercraft.shared.common.TileGeneric; -import java.util.Collections; -import java.util.Iterator; -import java.util.Set; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + /** * We use this when modems and other peripherals change a block in a different thread. */ diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index bd9086102..79e8c0cf1 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.util; -import javax.annotation.Nonnull; import net.minecraft.world.Container; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import javax.annotation.Nonnull; + public class ValidatingSlot extends Slot { public ValidatingSlot( Container inventoryIn, int index, int xPosition, int yPosition ) diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index a962bef3d..42bb791b3 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -10,12 +10,7 @@ import com.google.common.base.Predicate; import com.google.common.collect.MapMaker; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.entity.*; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityDimensions; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.*; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index 398e983f4..558de86ca 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -11,9 +11,10 @@ import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; -import javax.annotation.Nonnull; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; diff --git a/src/main/resources/cc.accesswidener b/src/main/resources/cc.accesswidener index cb9b4b774..7ccfdd6e0 100644 --- a/src/main/resources/cc.accesswidener +++ b/src/main/resources/cc.accesswidener @@ -1,8 +1,8 @@ accessWidener v1 named -accessible class net/minecraft/client/render/RenderLayer$MultiPhase -accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters -accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase; +accessible class net/minecraft/client/renderer/RenderType$CompositeState +accessible class net/minecraft/client/renderer/RenderType$CompositeStateBuilder +accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;Lcom/mojang/blaze3d/vertex/VertexFormat$Mode;IZZLnet/minecraft/client/renderer/RenderType$CompositeState;)Lnet/minecraft/client/renderer/RenderType$CompositeRenderType; accessible class net/minecraft/client/render/RenderPhase$Shader accessible class net/minecraft/client/render/RenderPhase$Texture diff --git a/src/main/resources/computercraft.mixins.json b/src/main/resources/computercraft.mixins.json index be224c3cc..8acb52d3e 100644 --- a/src/main/resources/computercraft.mixins.json +++ b/src/main/resources/computercraft.mixins.json @@ -3,26 +3,26 @@ "package": "dan200.computercraft.fabric.mixin", "compatibilityLevel": "JAVA_16", "mixins": [ + "LevelResourceAccess", "MinecraftServerAccess", + "MixinBlock", "MixinEntity", - "MixinServerWorld", - "MixinWorld", - "SignBlockEntityAccess", - "WorldSavePathAccess", - "MixinServerPlayerInteractionManager", - "MixinMatrix4f" + "MixinLevel", + "MixinMatrix4f", + "MixinServerLevel", + "MixinServerPlayerGameMode" ], "client": [ - "ChatHudAccess", - "HeldItemRendererAccess", - "MixinHeldItemRenderer", - "MixinItemFrameEntityRenderer", - "MixinMinecraftClient", - "MixinScreen", + "ChatComponentAccess", + "ItemInHandRendererAccess", + "MixinGameRenderer", - "MixinWorldRenderer", - "MixinHandledScreen" + "MixinItemFrameRenderer", + "MixinItemInHandRenderer", + "MixinLevelRenderer", + "MixinMinecraft", + "MixinScreen" ], "server": [ "MixinLanguage" From 70a24d371d98b23aed6cd37a410842a612619caf Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 27 Nov 2021 09:32:25 +0000 Subject: [PATCH 3/5] Update build.gradle to more closely match CC:T's - Adds cct-javadoc fun and renables checkstyle (yay?) - Fixes a few javadoc and formatting issues - Cherry pick the docs so illuaminate doesn't complain --- .github/workflows/main-ci.yml | 4 +- build.gradle | 168 ++++++++++++---- config/checkstyle/checkstyle.xml | 18 +- config/pre-commit/config.yml | 11 +- doc/events/alarm.md | 21 ++ doc/events/char.md | 24 +++ doc/events/computer_command.md | 18 ++ doc/events/disk.md | 19 ++ doc/events/disk_eject.md | 19 ++ doc/events/http_check.md | 14 ++ doc/events/http_failure.md | 39 ++++ doc/events/http_success.md | 27 +++ doc/events/key.md | 26 +++ doc/events/key_up.md | 24 +++ doc/events/modem_message.md | 22 +++ doc/events/monitor_resize.md | 18 ++ doc/events/monitor_touch.md | 20 ++ doc/events/mouse_click.md | 34 ++++ doc/events/mouse_drag.md | 22 +++ doc/events/mouse_scroll.md | 21 ++ doc/events/mouse_up.md | 21 ++ doc/events/paste.md | 18 ++ doc/events/peripheral.md | 19 ++ doc/events/peripheral_detach.md | 19 ++ doc/events/rednet_message.md | 30 +++ doc/events/redstone.md | 14 ++ doc/events/task_complete.md | 28 +++ doc/events/term_resize.md | 15 ++ doc/events/terminate.md | 25 +++ doc/events/timer.md | 21 ++ doc/events/turtle_inventory.md | 14 ++ doc/events/websocket_closed.md | 21 ++ doc/events/websocket_failure.md | 25 +++ doc/events/websocket_message.md | 27 +++ doc/events/websocket_success.md | 28 +++ doc/head.html | 1 + doc/images/basic-terminal.png | Bin 0 -> 54177 bytes doc/images/peripherals.png | Bin 0 -> 198811 bytes doc/images/turtle.png | Bin 0 -> 166845 bytes doc/index.md | 55 ++++++ doc/logo.png | Bin 0 -> 1563 bytes doc/stub/fs.lua | 36 ++++ doc/stub/global.lua | 130 +++++++++++++ doc/stub/http.lua | 181 ++++++++++++++++++ doc/stub/os.lua | 128 +++++++++++++ doc/stub/turtle.lua | 14 ++ gradle.properties | 10 +- illuaminate.sexp | 115 +++++++++++ .../computercraft/api/IUpgradeBase.java | 2 - .../computercraft/api/lua/GenericSource.java | 10 +- .../shared/computer/blocks/BlockComputer.java | 10 +- .../integration/ModMenuIntegration.java | 2 +- .../modem/wireless/BlockWirelessModem.java | 8 +- .../shared/turtle/apis/TurtleAPI.java | 1 + src/main/resources/cc.accesswidener | 4 - 55 files changed, 1530 insertions(+), 71 deletions(-) create mode 100644 doc/events/alarm.md create mode 100644 doc/events/char.md create mode 100644 doc/events/computer_command.md create mode 100644 doc/events/disk.md create mode 100644 doc/events/disk_eject.md create mode 100644 doc/events/http_check.md create mode 100644 doc/events/http_failure.md create mode 100644 doc/events/http_success.md create mode 100644 doc/events/key.md create mode 100644 doc/events/key_up.md create mode 100644 doc/events/modem_message.md create mode 100644 doc/events/monitor_resize.md create mode 100644 doc/events/monitor_touch.md create mode 100644 doc/events/mouse_click.md create mode 100644 doc/events/mouse_drag.md create mode 100644 doc/events/mouse_scroll.md create mode 100644 doc/events/mouse_up.md create mode 100644 doc/events/paste.md create mode 100644 doc/events/peripheral.md create mode 100644 doc/events/peripheral_detach.md create mode 100644 doc/events/rednet_message.md create mode 100644 doc/events/redstone.md create mode 100644 doc/events/task_complete.md create mode 100644 doc/events/term_resize.md create mode 100644 doc/events/terminate.md create mode 100644 doc/events/timer.md create mode 100644 doc/events/turtle_inventory.md create mode 100644 doc/events/websocket_closed.md create mode 100644 doc/events/websocket_failure.md create mode 100644 doc/events/websocket_message.md create mode 100644 doc/events/websocket_success.md create mode 100644 doc/head.html create mode 100644 doc/images/basic-terminal.png create mode 100644 doc/images/peripherals.png create mode 100644 doc/images/turtle.png create mode 100644 doc/index.md create mode 100644 doc/logo.png create mode 100644 doc/stub/fs.lua create mode 100644 doc/stub/global.lua create mode 100644 doc/stub/http.lua create mode 100644 doc/stub/os.lua create mode 100644 doc/stub/turtle.lua create mode 100644 illuaminate.sexp diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index b69180785..014abc079 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -9,8 +9,8 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Checkout submodules - run: git submodule update --init --recursive + with: + submodules: true - name: Set up Java 16 uses: actions/setup-java@v1 diff --git a/build.gradle b/build.gradle index 77c713e26..dfc18de3a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,47 +1,68 @@ plugins { - id 'fabric-loom' version '0.9-SNAPSHOT' - id 'maven-publish' - //id "checkstyle" + id "checkstyle" + id "jacoco" + id "maven-publish" id "com.github.hierynomus.license" version "0.16.1" + id "org.jetbrains.kotlin.jvm" version "1.5.21" + id 'fabric-loom' version '0.10-SNAPSHOT' } +def javaVersion = JavaLanguageVersion.of(16) java { toolchain { - languageVersion = JavaLanguageVersion.of(16) + languageVersion = javaVersion + } + + withSourcesJar() + withJavadocJar() +} + +tasks.withType(JavaExec).configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = javaVersion } } version = mod_version group = "dan200.computercraft" -archivesBaseName = "cc-restiched" +archivesBaseName = "cc-restitched" -repositories { - mavenCentral() - maven { url 'https://jitpack.io' } - maven { url 'https://api.modrinth.com/maven'} - maven { url "https://maven.shedaniel.me/" } - maven { url "https://maven.terraformersmc.com/" } - maven { - name "SquidDev" - url "https://squiddev.cc/maven" +sourceSets { + main.resources { + srcDir 'src/generated/resources' } + + testMod {} } loom { accessWidenerPath = file("src/main/resources/cc.accesswidener") } +repositories { + mavenCentral() + maven { + name "SquidDev" + url "https://squiddev.cc/maven" + } + + // TODO: Limit these to a set of groups. + maven { url "https://maven.shedaniel.me/" } + maven { url "https://maven.terraformersmc.com/" } +} + configurations { + shade implementation.extendsFrom shade + cctJavadoc } dependencies { - //checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1' + checkstyle "com.puppycrawl.tools:checkstyle:8.45" minecraft "com.mojang:minecraft:${mc_version}" - //mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2" - mappings(minecraft.officialMojangMappings()) + mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}" @@ -52,7 +73,8 @@ dependencies { modImplementation "me.shedaniel.cloth.api:cloth-utils-v1:${cloth_api_version}" implementation 'com.electronwill.night-config:toml:3.6.3' - implementation 'com.google.code.findbugs:jsr305:3.0.2' + + compileOnly 'com.google.code.findbugs:jsr305:3.0.2' shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT' @@ -61,39 +83,114 @@ dependencies { include 'com.electronwill.night-config:toml:3.6.3' include "me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}" - modRuntime "me.shedaniel:RoughlyEnoughItems-api-fabric:6.0.254-alpha" - modRuntime "me.shedaniel:RoughlyEnoughItems-fabric:6.0.254-alpha" + modRuntimeOnly "me.shedaniel:RoughlyEnoughItems-api-fabric:6.0.254-alpha" + modRuntimeOnly "me.shedaniel:RoughlyEnoughItems-fabric:6.0.254-alpha" + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' + testImplementation 'org.hamcrest:hamcrest:2.2' + testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1' + + cctJavadoc 'cc.tweaked:cct-javadoc:1.4.1' } processResources { inputs.property "version", project.version - filesMatching("fabric.mod.json") { - expand "version": project.version - } + def hash = 'none' + Set contributors = [] + try { + hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim() + + def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe'] + ["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each { + if (!blacklist.contains(it)) contributors.add(it) + } + } catch (Exception e) { + e.printStackTrace() + } + inputs.property "commithash", hash + duplicatesStrategy = DuplicatesStrategy.INCLUDE + + filesMatching(["fabric.mod.json", "data/computercraft/lua/rom/help/credits.txt"]) { + expand( + 'version': mod_version, + 'mcversion': mc_version, + 'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n') + ) + } } -// ensure that the encoding is set to UTF-8, no matter what the system default is -// this fixes some edge cases with special characters not displaying correctly -// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html tasks.withType(JavaCompile) { options.encoding = "UTF-8" } -// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task -// if it is present. -// If you remove this task, sources will not be generated. -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = "sources" - from sourceSets.main.allSource +javadoc { + include "dan200/computercraft/api/**/*.java" +} + +task luaJavadoc(type: Javadoc) { + description "Generates documentation for Java-side Lua functions." + group "documentation" + + source = sourceSets.main.allJava + destinationDir = file("${project.docsDir}/luaJavadoc") + classpath = sourceSets.main.compileClasspath + + options.docletpath = configurations.cctJavadoc.files as List + options.doclet = "cc.tweaked.javadoc.LuaDoclet" + options.noTimestamp = false + + javadocTool = javaToolchains.javadocToolFor { + languageVersion = javaVersion + } } jar { from "LICENSE" + manifest { + attributes([ + "Specification-Title" : "computercraft", + "Specification-Version" : "1", + "Implementation-Title" : "CC: Restitched", + "Implementation-Version" : "${mod_version}", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) } } +[compileJava, compileTestJava].forEach { + it.configure { + options.compilerArgs << "-Xlint" << "-Xlint:-processing" + } +} + +sourcesJar { + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + +// Check tasks + +test { + useJUnitPlatform() + testLogging { + events "skipped", "failed" + } +} + +jacocoTestReport { + dependsOn('test') + reports { + xml.required = true + html.required = true + } +} + +check.dependsOn jacocoTestReport import com.hierynomus.gradle.license.tasks.LicenseCheck import com.hierynomus.gradle.license.tasks.LicenseFormat @@ -113,7 +210,7 @@ license { } } -[licenseTest, licenseFormatTest].forEach { +[licenseTest, licenseFormatTest, licenseTestMod, licenseFormatTestMod].forEach { it.configure { include("**/*.java") header file('config/license/main.txt') @@ -126,9 +223,8 @@ gradle.projectsEvaluated { } } - -task licenseAPI(type: LicenseCheck); -task licenseFormatAPI(type: LicenseFormat); +task licenseAPI(type: LicenseCheck) +task licenseFormatAPI(type: LicenseFormat) [licenseAPI, licenseFormatAPI].forEach { it.configure { source = sourceSets.main.java diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index ebc62360c..580780514 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -58,13 +58,20 @@ - + + + + - + + + @@ -149,8 +156,13 @@ - + + + + + + diff --git a/config/pre-commit/config.yml b/config/pre-commit/config.yml index 6d16e1978..9fcbee67a 100644 --- a/config/pre-commit/config.yml +++ b/config/pre-commit/config.yml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.0.1 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -16,7 +16,7 @@ repos: exclude: "tsconfig\\.json$" - repo: https://github.com/editorconfig-checker/editorconfig-checker.python - rev: 2.3.5 + rev: 2.3.54 hooks: - id: editorconfig-checker args: ['-disable-indentation'] @@ -38,6 +38,13 @@ repos: entry: ./gradlew licenseFormat pass_filenames: false require_serial: true + - id: illuaminate + name: Check Lua code + files: ".*\\.(lua|java|md)" + language: script + entry: config/pre-commit/illuaminate-lint.sh + pass_filenames: false + require_serial: true exclude: | (?x)^( diff --git a/doc/events/alarm.md b/doc/events/alarm.md new file mode 100644 index 000000000..db7f04845 --- /dev/null +++ b/doc/events/alarm.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] alarm +see: os.setAlarm To start an alarm. +--- + +The @{timer} event is fired when an alarm started with @{os.setAlarm} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the alarm that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local alarmID = os.setAlarm(os.time() + 0.05) +local event, id +repeat + event, id = os.pullEvent("alarm") +until id == alarmID +print("Alarm with ID " .. id .. " was fired") +``` diff --git a/doc/events/char.md b/doc/events/char.md new file mode 100644 index 000000000..473313702 --- /dev/null +++ b/doc/events/char.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] char +see: key To listen to any key press. +--- + +The @{char} event is fired when a character is _typed_ on the keyboard. + +The @{char} event is different to a key press. Sometimes multiple key presses may result in one character being +typed (for instance, on some European keyboards). Similarly, some keys (e.g. Ctrl) do not have any +corresponding character. The @{key} should be used if you want to listen to key presses themselves. + +## Return values +1. @{string}: The event name. +2. @{string}: The string representing the character that was pressed. + + +## Example +Prints each character the user presses: +```lua +while true do + local event, character = os.pullEvent("char") + print(character .. " was pressed.") +end +``` diff --git a/doc/events/computer_command.md b/doc/events/computer_command.md new file mode 100644 index 000000000..245252399 --- /dev/null +++ b/doc/events/computer_command.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] computer_command +--- + +The @{computer_command} event is fired when the `/computercraft queue` command is run for the current computer. + +## Return Values +1. @{string}: The event name. +... @{string}: The arguments passed to the command. + +## Example +Prints the contents of messages sent: +```lua +while true do + local event = {os.pullEvent("computer_command")} + print("Received message:", table.unpack(event, 2)) +end +``` diff --git a/doc/events/disk.md b/doc/events/disk.md new file mode 100644 index 000000000..2946d70c4 --- /dev/null +++ b/doc/events/disk.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk +see: disk_eject For the event sent when a disk is removed. +--- + +The @{disk} event is fired when a disk is inserted into an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk inserted. + +## Example +Prints a message when a disk is inserted: +```lua +while true do + local event, side = os.pullEvent("disk") + print("Inserted a disk on side " .. side) +end +``` diff --git a/doc/events/disk_eject.md b/doc/events/disk_eject.md new file mode 100644 index 000000000..71c3ede0a --- /dev/null +++ b/doc/events/disk_eject.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk_eject +see: disk For the event sent when a disk is inserted. +--- + +The @{disk_eject} event is fired when a disk is removed from an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk removed. + +## Example +Prints a message when a disk is removed: +```lua +while true do + local event, side = os.pullEvent("disk_eject") + print("Removed a disk on side " .. side) +end +``` diff --git a/doc/events/http_check.md b/doc/events/http_check.md new file mode 100644 index 000000000..9af5ea7ca --- /dev/null +++ b/doc/events/http_check.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] http_check +see: http.checkURLAsync To check a URL asynchronously. +--- + +The @{http_check} event is fired when a URL check finishes. + +This event is normally handled inside @{http.checkURL}, but it can still be seen when using @{http.checkURLAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL requested to be checked. +3. @{boolean}: Whether the check succeeded. +4. @{string|nil}: If the check failed, a reason explaining why the check failed. diff --git a/doc/events/http_failure.md b/doc/events/http_failure.md new file mode 100644 index 000000000..dc10b40d7 --- /dev/null +++ b/doc/events/http_failure.md @@ -0,0 +1,39 @@ +--- +module: [kind=event] http_failure +see: http.request To send an HTTP request. +--- + +The @{http_failure} event is fired when an HTTP request fails. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. +4. @{http.Response|nil}: A response handle if the connection succeeded, but the server's response indicated failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "https://does.not.exist.tweaked.cc" +http.request(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` + +Prints the contents of a webpage that does not exist: +```lua +local myURL = "https://tweaked.cc/this/does/not/exist" +http.request(myURL) +local event, url, err, handle +repeat + event, url, err, handle = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +print(handle.getResponseCode()) +handle.close() +``` diff --git a/doc/events/http_success.md b/doc/events/http_success.md new file mode 100644 index 000000000..3700b9211 --- /dev/null +++ b/doc/events/http_success.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] http_success +see: http.request To make an HTTP request. +--- + +The @{http_success} event is fired when an HTTP request returns successfully. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{http.Response}: The handle for the response text. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "https://tweaked.cc/" +http.request(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("http_success") +until url == myURL +print("Contents of " .. url .. ":") +print(handle.readAll()) +handle.close() +``` diff --git a/doc/events/key.md b/doc/events/key.md new file mode 100644 index 000000000..1f11e443b --- /dev/null +++ b/doc/events/key.md @@ -0,0 +1,26 @@ +--- +module: [kind=event] key +--- + +This event is fired when any key is pressed while the terminal is focused. + +This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and +so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values. + +If the button pressed represented a printable character, then the @{key} event will be followed immediately by a @{char} +event. If you are consuming text input, use a @{char} event instead! + +## Return values +1. @{string}: The event name. +2. @{number}: The numerical key value of the key pressed. +3. @{boolean}: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}). + +## Example +Prints each key when the user presses it, and if the key is being held. + +```lua +while true do + local event, key, is_held = os.pullEvent("key") + print(("%s held=%s"):format(keys.getName(key), is_held)) +end +``` diff --git a/doc/events/key_up.md b/doc/events/key_up.md new file mode 100644 index 000000000..e957cae6b --- /dev/null +++ b/doc/events/key_up.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] key_up +see: keys For a lookup table of the given keys. +--- + +Fired whenever a key is released (or the terminal is closed while a key was being pressed). + +This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and +so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values. + +## Return values +1. @{string}: The event name. +2. @{number}: The numerical key value of the key pressed. + +## Example +Prints each key released on the keyboard whenever a @{key_up} event is fired. + +```lua +while true do + local event, key = os.pullEvent("key_up") + local name = keys.getName(key) or "unknown key" + print(name .. " was released.") +end +``` diff --git a/doc/events/modem_message.md b/doc/events/modem_message.md new file mode 100644 index 000000000..ec619f3d4 --- /dev/null +++ b/doc/events/modem_message.md @@ -0,0 +1,22 @@ +--- +module: [kind=event] modem_message +--- + +The @{modem_message} event is fired when a message is received on an open channel on any modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the modem that received the message. +3. @{number}: The channel that the message was sent on. +4. @{number}: The reply channel set by the sender. +5. @{any}: The message as sent by the sender. +6. @{number}: The distance between the sender and the receiver, in blocks (decimal). + +## Example +Prints a message when one is sent: +```lua +while true do + local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message") + print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message))) +end +``` diff --git a/doc/events/monitor_resize.md b/doc/events/monitor_resize.md new file mode 100644 index 000000000..03de804e7 --- /dev/null +++ b/doc/events/monitor_resize.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] monitor_resize +--- + +The @{monitor_resize} event is fired when an adjacent or networked monitor's size is changed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that resized. + +## Example +Prints a message when a monitor is resized: +```lua +while true do + local event, side = os.pullEvent("monitor_resize") + print("The monitor on side " .. side .. " was resized.") +end +``` diff --git a/doc/events/monitor_touch.md b/doc/events/monitor_touch.md new file mode 100644 index 000000000..0f27a9cc1 --- /dev/null +++ b/doc/events/monitor_touch.md @@ -0,0 +1,20 @@ +--- +module: [kind=event] monitor_touch +--- + +The @{monitor_touch} event is fired when an adjacent or networked Advanced Monitor is right-clicked. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that was touched. +3. @{number}: The X coordinate of the touch, in characters. +4. @{number}: The Y coordinate of the touch, in characters. + +## Example +Prints a message when a monitor is touched: +```lua +while true do + local event, side, x, y = os.pullEvent("monitor_touch") + print("The monitor on side " .. side .. " was touched at (" .. x .. ", " .. y .. ")") +end +``` diff --git a/doc/events/mouse_click.md b/doc/events/mouse_click.md new file mode 100644 index 000000000..83d371260 --- /dev/null +++ b/doc/events/mouse_click.md @@ -0,0 +1,34 @@ +--- +module: [kind=event] mouse_click +--- + +This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including +advanced turtles and pocket computers). + +## Return values +1. @{string}: The event name. +2. @{number}: The mouse button that was clicked. +3. @{number}: The X-coordinate of the click. +4. @{number}: The Y-coordinate of the click. + +## Mouse buttons +Several mouse events (@{mouse_click}, @{mouse_up}, @{mouse_scroll}) contain a "mouse button" code. This takes a +numerical value depending on which button on your mouse was last pressed when this event occurred. + + + + + + + +
Button codeMouse button
1Left button
2Middle button
3Right button
+ +## Example +Print the button and the coordinates whenever the mouse is clicked. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_click") + print(("The mouse button %s was pressed at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/mouse_drag.md b/doc/events/mouse_drag.md new file mode 100644 index 000000000..15451c9f8 --- /dev/null +++ b/doc/events/mouse_drag.md @@ -0,0 +1,22 @@ +--- +module: [kind=event] mouse_drag +see: mouse_click For when a mouse button is initially pressed. +--- + +This event is fired every time the mouse is moved while a mouse button is being held. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that is being pressed. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Print the button and the coordinates whenever the mouse is dragged. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_drag") + print(("The mouse button %s was dragged at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/mouse_scroll.md b/doc/events/mouse_scroll.md new file mode 100644 index 000000000..6248220a5 --- /dev/null +++ b/doc/events/mouse_scroll.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] mouse_scroll +--- + +This event is fired when a mouse wheel is scrolled in the terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The direction of the scroll. (-1 = up, 1 = down) +3. @{number}: The X-coordinate of the mouse when scrolling. +4. @{number}: The Y-coordinate of the mouse when scrolling. + +## Example +Prints the direction of each scroll, and the position of the mouse at the time. + +```lua +while true do + local event, dir, x, y = os.pullEvent("mouse_scroll") + print(("The mouse was scrolled in direction %s at %d, %d"):format(dir, x, y)) +end +``` diff --git a/doc/events/mouse_up.md b/doc/events/mouse_up.md new file mode 100644 index 000000000..886330a6d --- /dev/null +++ b/doc/events/mouse_up.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] mouse_up +--- + +This event is fired when a mouse button is released or a held mouse leaves the computer's terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that was released. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Prints the coordinates and button number whenever the mouse is released. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_up") + print(("The mouse button %s was released at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/paste.md b/doc/events/paste.md new file mode 100644 index 000000000..b4f8713c5 --- /dev/null +++ b/doc/events/paste.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] paste +--- + +The @{paste} event is fired when text is pasted into the computer through Ctrl-V (or ⌘V on Mac). + +## Return values +1. @{string}: The event name. +2. @{string} The text that was pasted. + +## Example +Prints pasted text: +```lua +while true do + local event, text = os.pullEvent("paste") + print('"' .. text .. '" was pasted') +end +``` diff --git a/doc/events/peripheral.md b/doc/events/peripheral.md new file mode 100644 index 000000000..5769f3942 --- /dev/null +++ b/doc/events/peripheral.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral +see: peripheral_detach For the event fired when a peripheral is detached. +--- + +The @{peripheral} event is fired when a peripheral is attached on a side or to a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was attached to. + +## Example +Prints a message when a peripheral is attached: +```lua +while true do + local event, side = os.pullEvent("peripheral") + print("A peripheral was attached on side " .. side) +end +``` diff --git a/doc/events/peripheral_detach.md b/doc/events/peripheral_detach.md new file mode 100644 index 000000000..c8a462cf0 --- /dev/null +++ b/doc/events/peripheral_detach.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral_detach +see: peripheral For the event fired when a peripheral is attached. +--- + +The @{peripheral_detach} event is fired when a peripheral is detached from a side or from a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was detached from. + +## Example +Prints a message when a peripheral is detached: +```lua +while true do + local event, side = os.pullEvent("peripheral_detach") + print("A peripheral was detached on side " .. side) +end +``` diff --git a/doc/events/rednet_message.md b/doc/events/rednet_message.md new file mode 100644 index 000000000..8d0bdf697 --- /dev/null +++ b/doc/events/rednet_message.md @@ -0,0 +1,30 @@ +--- +module: [kind=event] rednet_message +see: modem_message For raw modem messages sent outside of Rednet. +see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter. +--- + +The @{rednet_message} event is fired when a message is sent over Rednet. + +This event is usually handled by @{rednet.receive}, but it can also be pulled manually. + +@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the sending computer. +3. @{any}: The message sent. +4. @{string|nil}: The protocol of the message, if provided. + +## Example +Prints a message when one is sent: +```lua +while true do + local event, sender, message, protocol = os.pullEvent("rednet_message") + if protocol ~= nil then + print("Received message from " .. sender .. " with protocol " .. protocol .. " and message " .. tostring(message)) + else + print("Received message from " .. sender .. " with message " .. tostring(message)) + end +end +``` diff --git a/doc/events/redstone.md b/doc/events/redstone.md new file mode 100644 index 000000000..44eda304a --- /dev/null +++ b/doc/events/redstone.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] redstone +--- + +The @{redstone} event is fired whenever any redstone inputs on the computer change. + +## Example +Prints a message when a redstone input changes: +```lua +while true do + os.pullEvent("redstone") + print("A redstone input has changed!") +end +``` diff --git a/doc/events/task_complete.md b/doc/events/task_complete.md new file mode 100644 index 000000000..eddec51d2 --- /dev/null +++ b/doc/events/task_complete.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] task_complete +see: commands.execAsync To run a command which fires a task_complete event. +--- + +The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the task that completed. +3. @{boolean}: Whether the command succeeded. +4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.) +...: Any parameters returned from the command. + +## Example +Prints the results of an asynchronous command: +```lua +local taskID = commands.execAsync("say Hello") +local event +repeat + event = {os.pullEvent("task_complete")} +until event[2] == taskID +if event[3] == true then + print("Task " .. event[2] .. " succeeded:", table.unpack(event, 4)) +else + print("Task " .. event[2] .. " failed: " .. event[4]) +end +``` diff --git a/doc/events/term_resize.md b/doc/events/term_resize.md new file mode 100644 index 000000000..0eb503bad --- /dev/null +++ b/doc/events/term_resize.md @@ -0,0 +1,15 @@ +--- +module: [kind=event] term_resize +--- + +The @{term_resize} event is fired when the main terminal is resized, mainly when a new tab is opened or closed in @{multishell}. + +## Example +Prints : +```lua +while true do + os.pullEvent("term_resize") + local w, h = term.getSize() + print("The term was resized to (" .. w .. ", " .. h .. ")") +end +``` diff --git a/doc/events/terminate.md b/doc/events/terminate.md new file mode 100644 index 000000000..0760b8c3b --- /dev/null +++ b/doc/events/terminate.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] terminate +--- + +The @{terminate} event is fired when Ctrl-T is held down. + +This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired. + +@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}. + +## Example +Prints a message when Ctrl-T is held: +```lua +while true do + local event = os.pullEventRaw("terminate") + if event == "terminate" then print("Terminate requested!") end +end +``` + +Exits when Ctrl-T is held: +```lua +while true do + os.pullEvent() +end +``` diff --git a/doc/events/timer.md b/doc/events/timer.md new file mode 100644 index 000000000..c359c37b4 --- /dev/null +++ b/doc/events/timer.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] timer +see: os.startTimer To start a timer. +--- + +The @{timer} event is fired when a timer started with @{os.startTimer} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the timer that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local timerID = os.startTimer(2) +local event, id +repeat + event, id = os.pullEvent("timer") +until id == timerID +print("Timer with ID " .. id .. " was fired") +``` diff --git a/doc/events/turtle_inventory.md b/doc/events/turtle_inventory.md new file mode 100644 index 000000000..bc9392b6b --- /dev/null +++ b/doc/events/turtle_inventory.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] turtle_inventory +--- + +The @{turtle_inventory} event is fired when a turtle's inventory is changed. + +## Example +Prints a message when the inventory is changed: +```lua +while true do + os.pullEvent("turtle_inventory") + print("The inventory was changed.") +end +``` diff --git a/doc/events/websocket_closed.md b/doc/events/websocket_closed.md new file mode 100644 index 000000000..9e3783d19 --- /dev/null +++ b/doc/events/websocket_closed.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] websocket_closed +--- + +The @{websocket_closed} event is fired when an open WebSocket connection is closed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket that was closed. + +## Example +Prints a message when a WebSocket is closed (this may take a minute): +```lua +local myURL = "wss://example.tweaked.cc/echo" +local ws = http.websocket(myURL) +local event, url +repeat + event, url = os.pullEvent("websocket_closed") +until url == myURL +print("The WebSocket at " .. url .. " was closed.") +``` diff --git a/doc/events/websocket_failure.md b/doc/events/websocket_failure.md new file mode 100644 index 000000000..eef34e777 --- /dev/null +++ b/doc/events/websocket_failure.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] websocket_failure +see: http.websocketAsync To send an HTTP request. +--- + +The @{websocket_failure} event is fired when a WebSocket connection request fails. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "wss://example.tweaked.cc/not-a-websocket" +http.websocketAsync(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("websocket_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` diff --git a/doc/events/websocket_message.md b/doc/events/websocket_message.md new file mode 100644 index 000000000..839e214cc --- /dev/null +++ b/doc/events/websocket_message.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] websocket_message +--- + +The @{websocket_message} event is fired when a message is received on an open WebSocket connection. + +This event is normally handled by @{http.Websocket.receive}, but it can also be pulled manually. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket. +3. @{string}: The contents of the message. +4. @{boolean}: Whether this is a binary message. + +## Example +Prints a message sent by a WebSocket: +```lua +local myURL = "wss://example.tweaked.cc/echo" +local ws = http.websocket(myURL) +ws.send("Hello!") +local event, url, message +repeat + event, url, message = os.pullEvent("websocket_message") +until url == myURL +print("Received message from " .. url .. " with contents " .. message) +ws.close() +``` diff --git a/doc/events/websocket_success.md b/doc/events/websocket_success.md new file mode 100644 index 000000000..dcde934b3 --- /dev/null +++ b/doc/events/websocket_success.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] websocket_success +see: http.websocketAsync To open a WebSocket asynchronously. +--- + +The @{websocket_success} event is fired when a WebSocket connection request returns successfully. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site. +3. @{http.Websocket}: The handle for the WebSocket. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "wss://example.tweaked.cc/echo" +http.websocketAsync(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("websocket_success") +until url == myURL +print("Connected to " .. url) +handle.send("Hello!") +print(handle.receive()) +handle.close() +``` diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 000000000..efd18a401 --- /dev/null +++ b/doc/head.html @@ -0,0 +1 @@ + diff --git a/doc/images/basic-terminal.png b/doc/images/basic-terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..782b850cdc946cf37e3a52ea8e495f3a4d2756ac GIT binary patch literal 54177 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�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≪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 literal 0 HcmV?d00001 diff --git a/doc/images/peripherals.png b/doc/images/peripherals.png new file mode 100644 index 0000000000000000000000000000000000000000..16c2e807d8b6ea8a0027bfb1750a543cea217814 GIT binary patch literal 198811 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Ø^;iG5IKi_1bSbeuZ*ghiCW%pLzALm!afF4@b(8 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

c|`~KgH*~eMR)Fa=T9Su}| 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%0Ag_%T_hs=lt(&xN;J1K3(j7 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
bU54;7DVos|Fuk`>ER8gi8^k7g>|k( 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 K&t;ucLK6VgkwKpT literal 0 HcmV?d00001 diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua new file mode 100644 index 000000000..aa40a30f3 --- /dev/null +++ b/doc/stub/fs.lua @@ -0,0 +1,36 @@ +--- The FS API allows you to manipulate files and the filesystem. +-- +-- @module fs + +--- Returns true if a path is mounted to the parent filesystem. +-- +-- The root filesystem "/" is considered a mount, along with disk folders and +-- the rom folder. Other programs (such as network shares) can exstend this to +-- make other mount types by correctly assigning their return value for getDrive. +-- +-- @tparam string path The path to check. +-- @treturn boolean If the path is mounted, rather than a normal file/folder. +-- @throws If the path does not exist. +-- @see getDrive +-- @since 1.87.0 +function isDriveRoot(path) end + +--[[- Provides completion for a file or directory name, suitable for use with +@{_G.read}. + +When a directory is a possible candidate for completion, two entries are +included - one with a trailing slash (indicating that entries within this +directory exist) and one without it (meaning this entry is an immediate +completion candidate). `include_dirs` can be set to @{false} to only include +those with a trailing slash. + +@tparam string path The path to complete. +@tparam string location The location where paths are resolved from. +@tparam[opt] boolean include_files When @{false}, only directories will be +included in the returned list. +@tparam[opt] boolean include_dirs When @{false}, "raw" directories will not be +included in the returned list. +@treturn { string... } A list of possible completion candidates. +@since 1.74 +]] +function complete(path, location, include_files, include_dirs) end diff --git a/doc/stub/global.lua b/doc/stub/global.lua new file mode 100644 index 000000000..a2d54fa12 --- /dev/null +++ b/doc/stub/global.lua @@ -0,0 +1,130 @@ +--[[- +Functions in the global environment, defined in `bios.lua`. This does not +include standard Lua functions. + +@module _G +]] + +--[[- Pauses execution for the specified number of seconds. + +As it waits for a fixed amount of world ticks, `time` will automatically be +rounded up to the nearest multiple of 0.05 seconds. If you are using coroutines +or the @{parallel|parallel API}, it will only pause execution of the current +thread, not the whole program. + +**Note** Because sleep internally uses timers, it is a function that yields. +This means that you can use it to prevent "Too long without yielding" errors, +however, as the minimum sleep time is 0.05 seconds, it will slow your program +down. + +**Warning** Internally, this function queues and waits for a timer event (using +@{os.startTimer}), however it does not listen for any other events. This means +that any event that occurs while sleeping will be entirely discarded. If you +need to receive events while sleeping, consider using @{os.startTimer|timers}, +or the @{parallel|parallel API}. + +@tparam number time The number of seconds to sleep for, rounded up to the +nearest multiple of 0.05. + +@see os.startTimer +@usage Sleep for three seconds. + + print("Sleeping for three seconds") + sleep(3) + print("Done!") +]] +function sleep(time) end + +--- Writes a line of text to the screen without a newline at the end, wrapping +-- text if necessary. +-- +-- @tparam string text The text to write to the string +-- @treturn number The number of lines written +-- @see print A wrapper around write that adds a newline and accepts multiple arguments +-- @usage write("Hello, world") +function write(text) end + +--- Prints the specified values to the screen separated by spaces, wrapping if +-- necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @treturn number The number of lines written +-- @usage print("Hello, world!") +function print(...) end + +--- Prints the specified values to the screen in red, separated by spaces, +-- wrapping if necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @usage printError("Something went wrong!") +function printError(...) end + +--[[- Reads user input from the terminal, automatically handling arrow keys, +pasting, character replacement, history scrollback, auto-completion, and +default values. + +@tparam[opt] string replaceChar A character to replace each typed character with. +This can be used for hiding passwords, for example. +@tparam[opt] table history A table holding history items that can be scrolled +back to with the up/down arrow keys. The oldest item is at index 1, while the +newest item is at the highest index. +@tparam[opt] function(partial: string):({ string... }|nil) completeFn A function +to be used for completion. This function should take the partial text typed so +far, and returns a list of possible completion options. +@tparam[opt] string default Default text which should already be entered into +the prompt. + +@treturn string The text typed in. + +@see cc.completion For functions to help with completion. +@usage Read a string and echo it back to the user + + write("> ") + local msg = read() + print(msg) + +@usage Prompt a user for a password. + + while true do + write("Password> ") + local pwd = read("*") + if pwd == "let me in" then break end + print("Incorrect password, try again.") + end + print("Logged in!") + +@usage A complete example with completion, history and a default value. + + local completion = require "cc.completion" + local history = { "potato", "orange", "apple" } + local choices = { "apple", "orange", "banana", "strawberry" } + write("> ") + local msg = read(nil, history, function(text) return completion.choice(text, choices) end, "app") + print(msg) + +@changed 1.74 Added `completeFn` parameter. +@changed 1.80pr1 Added `default` parameter. +]] +function read(replaceChar, history, completeFn, default) end + +--- The ComputerCraft and Minecraft version of the current computer environment. +-- +-- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`. +-- @usage _HOST +-- @since 1.76 +_HOST = _HOST + +--[[- The default computer settings as defined in the ComputerCraft +configuration. + +This is a comma-separated list of settings pairs defined by the mod +configuration or server owner. By default, it is empty. + +An example value to disable autocompletion: + + shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false + +@usage _CC_DEFAULT_SETTINGS +@since 1.77 +]] +_CC_DEFAULT_SETTINGS = _CC_DEFAULT_SETTINGS diff --git a/doc/stub/http.lua b/doc/stub/http.lua new file mode 100644 index 000000000..81ba63753 --- /dev/null +++ b/doc/stub/http.lua @@ -0,0 +1,181 @@ +--- The http library allows communicating with web servers, sending and +-- receiving data from them. +-- +-- @module http +-- @since 1.1 + +--- Asynchronously make a HTTP request to the given url. +-- +-- This returns immediately, a [`http_success`](#http-success-event) or +-- [`http_failure`](#http-failure-event) will be queued once the request has +-- completed. +-- +-- @tparam string url The url to request +-- @tparam[opt] string body An optional string containing the body of the +-- request. If specified, a `POST` request will be made instead. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. +-- +-- This table form is an expanded version of the previous syntax. All arguments +-- from above are passed in as fields instead (for instance, +-- `http.request("https://example.com")` becomes `http.request { url = +-- "https://example.com" }`). +-- +-- This table also accepts several additional options: +-- +-- - `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`. +-- - `redirect`: Whether to follow HTTP redirects. Defaults to true. +-- +-- @see http.get For a synchronous way to make GET requests. +-- @see http.post For a synchronous way to make POST requests. +-- +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +function request(...) end + +--- Make a HTTP GET request to the given url. +-- +-- @tparam string url The url to request +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Response handles are now returned on error if available. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +-- +-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), +-- and print the returned page. +-- ```lua +-- local request = http.get("https://example.tweaked.cc") +-- print(request.readAll()) +-- -- => HTTP is working! +-- request.close() +-- ``` +function get(...) end + +--- Make a HTTP POST request to the given url. +-- +-- @tparam string url The url to request +-- @tparam string body The body of the POST request. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @since 1.31 +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Response handles are now returned on error if available. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +function post(...) end + +--- Asynchronously determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is not invalid. This does not imply that it is +-- allowed - see the comment above. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURL For a synchronous version. +function checkURLAsync(url) end + +--- Determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is valid and can be requested via @{http.request}. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURLAsync For an asynchronous version. +-- +-- @usage +-- ```lua +-- print(http.checkURL("https://example.tweaked.cc/")) +-- -- => true +-- print(http.checkURL("http://localhost/")) +-- -- => false Domain not permitted +-- print(http.checkURL("not a url")) +-- -- => false URL malformed +-- ``` +function checkURL(url) end + +--- Open a websocket. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- +-- @treturn Websocket The websocket connection. +-- @treturn[2] false If the websocket connection failed. +-- @treturn string An error message describing why the connection failed. +-- @since 1.80pr1.1 +-- @changed 1.80pr1.3 No longer asynchronous. +-- @changed 1.95.3 Added User-Agent to default headers. +function websocket(url, headers) end + +--- Asynchronously open a websocket. +-- +-- This returns immediately, a [`websocket_success`](#websocket-success-event) +-- or [`websocket_failure`](#websocket-failure-event) will be queued once the +-- request has completed. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- @since 1.80pr1.3 +-- @changed 1.95.3 Added User-Agent to default headers. +function websocketAsync(url, headers) end diff --git a/doc/stub/os.lua b/doc/stub/os.lua new file mode 100644 index 000000000..39c051ceb --- /dev/null +++ b/doc/stub/os.lua @@ -0,0 +1,128 @@ +-- Defined in bios.lua + +--[[- Loads the given API into the global environment. + +This function loads and executes the file at the given path, and all global +variables and functions exported by it will by available through the use of +`myAPI.`, where `myAPI` is the base name of the API file. + +@tparam string path The path of the API to load. +@treturn boolean Whether or not the API was successfully loaded. +@since 1.2 + +@deprecated When possible it's best to avoid using this function. It pollutes +the global table and can mask errors. + +@{require} should be used to load libraries instead. +]] +function loadAPI(path) end + +--- Unloads an API which was loaded by @{os.loadAPI}. +-- +-- This effectively removes the specified table from `_G`. +-- +-- @tparam string name The name of the API to unload. +-- @since 1.2 +-- @deprecated See @{os.loadAPI} for why. +function unloadAPI(name) end + +--[[- Pause execution of the current thread and waits for any events matching +`filter`. + +This function @{coroutine.yield|yields} the current process and waits for it +to be resumed with a vararg list where the first element matches `filter`. +If no `filter` is supplied, this will match all events. + +Unlike @{os.pullEventRaw}, it will stop the application upon a "terminate" +event, printing the error "Terminated". + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `mouse_click` events. + + while true do + local event, button, x, y = os.pullEvent("mouse_click") + print("Button", button, "was clicked at", x, ",", y) + end + +@usage Listen for multiple events. + + while true do + local eventData = {os.pullEvent()} + local event = eventData[1] + + if event == "mouse_click" then + print("Button", eventData[2], "was clicked at", eventData[3], ",", eventData[4]) + elseif event == "key" then + print("Key code", eventData[2], "was pressed") + end + end + +@see os.pullEventRaw To pull the terminate event. +@changed 1.3 Added filter argument. +]] +function pullEvent(filter) end + +--[[- Pause execution of the current thread and waits for events, including the +`terminate` event. + +This behaves almost the same as @{os.pullEvent}, except it allows you to handle +the `terminate` event yourself - the program will not stop execution when +Ctrl+T is pressed. + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `terminate` events. + + while true do + local event = os.pullEventRaw() + if event == "terminate" then + print("Caught terminate event!") + end + end + +@see os.pullEvent To pull events normally. +]] +function pullEventRaw(filter) end + +--- Pauses execution for the specified number of seconds, alias of @{_G.sleep}. +-- +-- @tparam number time The number of seconds to sleep for, rounded up to the +-- nearest multiple of 0.05. +function sleep(time) end + +--- Get the current CraftOS version (for example, `CraftOS 1.8`). +-- +-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this +-- should return `CraftOS 1.8`. +-- +-- @treturn string The current CraftOS version. +-- @usage os.version() +function version() end + +--[[- Run the program at the given path with the specified environment and +arguments. + +This function does not resolve program names like the shell does. This means +that, for example, `os.run("edit")` will not work. As well as this, it does not +provide access to the @{shell} API in the environment. For this behaviour, use +@{shell.run} instead. + +If the program cannot be found, or failed to run, it will print the error and +return `false`. If you want to handle this more gracefully, use an alternative +such as @{loadfile}. + +@tparam table env The environment to run the program with. +@tparam string path The exact path of the program to run. +@param ... The arguments to pass to the program. +@treturn boolean Whether or not the program ran successfully. +@usage Run the default shell from within your program: + + os.run({}, "/rom/programs/shell.lua") + +@see shell.run +@see loadfile +]] +function run(env, path, ...) end diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua new file mode 100644 index 000000000..10ae68df7 --- /dev/null +++ b/doc/stub/turtle.lua @@ -0,0 +1,14 @@ +--[[- Craft a recipe based on the turtle's inventory. + +The turtle's inventory should set up like a crafting grid. For instance, to +craft sticks, slots 1 and 5 should contain planks. _All_ other slots should be +empty, including those outside the crafting "grid". + +@tparam[opt=64] number limit The maximum number of crafting steps to run. +@throws When limit is less than 1 or greater than 64. +@treturn[1] true If crafting succeeds. +@treturn[2] false If crafting fails. +@treturn string A string describing why crafting failed. +@since 1.4 +]] +function craft(limit) end diff --git a/gradle.properties b/gradle.properties index 92c1f2c1f..149a41402 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,12 +6,10 @@ mod_version=1.97.2 # Minecraft properties mc_version=1.17.1 -#mappings_version=61 - -# Dependencies -cloth_config_version=5.0.34 -fabric_loader_version=0.11.7 fabric_api_version=0.40.1+1.17 +fabric_loader_version=0.12.0 + +cloth_api_version=2.0.54 +cloth_config_version=5.0.34 jankson_version=1.2.0 modmenu_version=2.0.2 -cloth_api_version=2.0.54 diff --git a/illuaminate.sexp b/illuaminate.sexp new file mode 100644 index 000000000..ac3ae44e4 --- /dev/null +++ b/illuaminate.sexp @@ -0,0 +1,115 @@ +; -*- mode: Lisp;-*- + +(sources + /doc/stub/ + /doc/events/ + /build/docs/luaJavadoc/ + /src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/ + /src/test/resources/test-rom + /src/web/mount) + + +(doc + (destination build/docs/lua) + (index doc/index.md) + + (site + (title "CC: Tweaked") + (logo src/main/resources/pack.png) + (url https://tweaked.cc/) + (source-link https://github.com/cc-tweaked/CC-Tweaked/blob/${commit}/${path}#L${line}) + + (styles src/web/styles.css) + (scripts build/rollup/index.js) + (head doc/head.html)) + + (module-kinds + (peripheral Peripherals) + (generic_peripheral "Generic Peripherals") + (event Events)) + + (library-path + /doc/stub/ + /build/docs/luaJavadoc/ + + /src/main/resources/*/computercraft/lua/rom/apis/ + /src/main/resources/*/computercraft/lua/rom/apis/command/ + /src/main/resources/*/computercraft/lua/rom/apis/turtle/ + + /src/main/resources/*/computercraft/lua/rom/modules/main/ + /src/main/resources/*/computercraft/lua/rom/modules/command/ + /src/main/resources/*/computercraft/lua/rom/modules/turtle/)) + +(at / + (linters + syntax:string-index + + ;; It'd be nice to avoid this, but right now there's a lot of instances of + ;; it. + -var:set-loop + + ;; It's useful to name arguments for documentation, so we allow this. It'd + ;; be good to find a compromise in the future, but this works for now. + -var:unused-arg) + + (lint + (bracket-spaces + (call no-space) + (function-args no-space) + (parens no-space) + (table space) + (index no-space)) + + (allow-clarifying-parens true) + + ;; colours imports from colors, and we don't handle that right now. + ;; keys is entirely dynamic, so we skip it. + (dynamic-modules colours keys _G) + + (globals + :max + _CC_DEFAULT_SETTINGS + _CC_DISABLE_LUA51_FEATURES + _HOST + ;; Ideally we'd pick these up from bios.lua, but illuaminate currently + ;; isn't smart enough. + sleep write printError read rs))) + +;; We disable the unused global linter in bios.lua and the APIs. In the future +;; hopefully we'll get illuaminate to handle this. +(at + (/src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/apis/) + (linters -var:unused-global) + (lint (allow-toplevel-global true))) + +;; Silence some variable warnings in documentation stubs. +(at (/doc/stub/ /build/docs/luaJavadoc/) + (linters -var:unused-global) + (lint (allow-toplevel-global true))) + +;; Suppress warnings for currently undocumented modules. +(at + (; Lua APIs + /src/main/resources/*/computercraft/lua/rom/apis/io.lua + /src/main/resources/*/computercraft/lua/rom/apis/window.lua) + + (linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return)) + +;; Suppress warnings for various APIs using its own deprecated members. +(at + (/src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/apis/turtle/turtle.lua) + (linters -var:deprecated)) + +(at /src/test/resources/test-rom + ; We should still be able to test deprecated members. + (linters -var:deprecated) + + (lint + (globals + :max sleep write + cct_test describe expect howlci fail it pending stub))) + +(at /src/web/mount/expr_template.lua (lint (globals :max __expr__))) diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java index 6924160a0..d87c404bb 100644 --- a/src/main/java/dan200/computercraft/api/IUpgradeBase.java +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -67,8 +67,6 @@ public interface IUpgradeBase * @param stack The stack to check. This is guaranteed to be non-empty and have the same item as * {@link #getCraftingItem()}. * @return If this stack may be used to equip this upgrade. - * @see net.minecraftforge.common.crafting.NBTIngredient#test(ItemStack) For the implementation of the default - * check. */ default boolean isItemSuitable( @Nonnull ItemStack stack ) { diff --git a/src/main/java/dan200/computercraft/api/lua/GenericSource.java b/src/main/java/dan200/computercraft/api/lua/GenericSource.java index 1828ffb6b..c29cf4991 100644 --- a/src/main/java/dan200/computercraft/api/lua/GenericSource.java +++ b/src/main/java/dan200/computercraft/api/lua/GenericSource.java @@ -10,6 +10,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.core.asm.LuaMethod; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; import javax.annotation.Nonnull; @@ -18,20 +19,19 @@ import javax.annotation.Nonnull; * * Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but * instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject - * methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a - * {@link Capability}). + * methods onto objects you do not own, as well as declaring methods for a specific "trait" (well, interface). * * Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider} * or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name * determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable * design has been established. * - * For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s: + * For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link Container}s: * *

{@code
  * public class InventoryMethods implements GenericSource {
  *     \@LuaFunction( mainThread = true )
- *     public static int size(IItemHandler inventory) {
+ *     public static int size(Container inventory) {
  *         return inventory.getSlots();
  *     }
  *
@@ -40,8 +40,6 @@ import javax.annotation.Nonnull;
  * }
* * @see ComputerCraftAPI#registerGenericSource(GenericSource) - * @see ComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be - * explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities. */ public interface GenericSource { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index af607e6bb..5e5f2ceda 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -63,11 +63,11 @@ public class BlockComputer extends BlockComputerBase public BlockEntityType getTypeByFamily( ComputerFamily family ) { return switch( family ) - { - case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND; - case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED; - default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL; - }; + { + case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND; + case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED; + default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL; + }; } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java index 08c311416..081f43de4 100644 --- a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java @@ -42,7 +42,7 @@ public class ModMenuIntegration implements ModMenuApi client.addEntry( entryBuilder.startEnumSelector( new TextComponent( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) .setDefaultValue( MonitorRenderer.BEST ) - .setSaveConsumer( renderer -> {Config.clientConfig.set( "monitor_renderer", renderer );} ) + .setSaveConsumer( renderer -> Config.clientConfig.set( "monitor_renderer", renderer ) ) .setTooltip( Component.nullToEmpty( Config.clientConfig.getComment( "monitor_renderer" ) ) ) .build() ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index 87616f005..b3a03e8a6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -105,10 +105,10 @@ public class BlockWirelessModem extends BlockGeneric implements SimpleWaterlogge public BlockEntityType getTypeByFamily( ComputerFamily family ) { return switch( family ) - { - case ADVANCED -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED; - default -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL; - }; + { + case ADVANCED -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED; + default -> ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL; + }; } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 240a8d24f..79438be47 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -18,6 +18,7 @@ import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.peripheral.generic.data.ItemData; +import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import dan200.computercraft.shared.turtle.core.*; import net.minecraft.world.item.ItemStack; diff --git a/src/main/resources/cc.accesswidener b/src/main/resources/cc.accesswidener index 7ccfdd6e0..c7e7cccab 100644 --- a/src/main/resources/cc.accesswidener +++ b/src/main/resources/cc.accesswidener @@ -1,8 +1,4 @@ accessWidener v1 named accessible class net/minecraft/client/renderer/RenderType$CompositeState -accessible class net/minecraft/client/renderer/RenderType$CompositeStateBuilder accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;Lcom/mojang/blaze3d/vertex/VertexFormat$Mode;IZZLnet/minecraft/client/renderer/RenderType$CompositeState;)Lnet/minecraft/client/renderer/RenderType$CompositeRenderType; - -accessible class net/minecraft/client/render/RenderPhase$Shader -accessible class net/minecraft/client/render/RenderPhase$Texture From 58e747506e961732c2dbedecfca7d6f8e5318c23 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 27 Nov 2021 10:12:27 +0000 Subject: [PATCH 4/5] Update core, api and ROM to match latest CC:T Mostly fine, but breaking change in that getWorld -> getLevel. Possibly worth deferring to 1.18 --- .../dan200/computercraft/ComputerCraft.java | 3 - .../computercraft/api/ComputerCraftAPI.java | 80 +- .../api/client/TransformedModel.java | 8 +- .../api/filesystem/FileAttributes.java | 1 - .../filesystem/FileOperationException.java | 1 - .../api/filesystem/IFileSystem.java | 1 - .../computercraft/api/filesystem/IMount.java | 81 +- .../api/filesystem/IWritableMount.java | 24 +- .../computercraft/api/lua/IArguments.java | 388 ++++----- .../api/lua/IComputerSystem.java | 4 +- .../api/lua/IDynamicLuaObject.java | 18 +- .../dan200/computercraft/api/lua/ILuaAPI.java | 9 +- .../computercraft/api/lua/ILuaAPIFactory.java | 1 - .../computercraft/api/lua/ILuaCallback.java | 4 +- .../computercraft/api/lua/ILuaContext.java | 6 +- .../computercraft/api/lua/ILuaFunction.java | 9 +- .../computercraft/api/lua/ILuaTask.java | 11 +- .../computercraft/api/lua/LuaException.java | 4 +- .../computercraft/api/lua/LuaFunction.java | 8 +- .../computercraft/api/lua/LuaValues.java | 106 +-- .../computercraft/api/lua/MethodResult.java | 45 +- .../api/lua/ObjectArguments.java | 42 +- .../computercraft/api/lua/TaskCallback.java | 53 ++ .../computercraft/api/media/IMedia.java | 15 +- .../api/media/IMediaProvider.java | 1 - .../api/network/IPacketNetwork.java | 9 +- .../api/network/IPacketReceiver.java | 16 +- .../api/network/IPacketSender.java | 7 +- .../computercraft/api/network/Packet.java | 124 +-- .../api/network/wired/IWiredElement.java | 13 +- .../api/network/wired/IWiredNetwork.java | 24 +- .../network/wired/IWiredNetworkChange.java | 9 +- .../api/network/wired/IWiredNode.java | 44 +- .../api/network/wired/IWiredSender.java | 7 +- .../api/peripheral/GenericPeripheral.java | 45 ++ .../api/peripheral/IComputerAccess.java | 96 ++- .../api/peripheral/IDynamicPeripheral.java | 32 +- .../api/peripheral/IPeripheral.java | 44 +- .../api/peripheral/IPeripheralProvider.java | 10 +- .../api/peripheral/IWorkMonitor.java | 53 +- .../api/peripheral/NotAttachedException.java | 4 +- .../api/peripheral/PeripheralType.java | 62 ++ .../api/pocket/AbstractPocketUpgrade.java | 1 - .../api/pocket/IPocketAccess.java | 15 +- .../api/pocket/IPocketUpgrade.java | 11 +- .../redstone/IBundledRedstoneProvider.java | 4 +- .../api/turtle/ITurtleAccess.java | 114 +-- .../api/turtle/ITurtleCommand.java | 5 +- .../api/turtle/ITurtleUpgrade.java | 31 +- .../api/turtle/TurtleAnimation.java | 21 +- .../api/turtle/TurtleCommandResult.java | 34 +- .../computercraft/api/turtle/TurtleSide.java | 1 - .../api/turtle/TurtleUpgradeType.java | 14 +- .../computercraft/api/turtle/TurtleVerb.java | 6 +- .../api/turtle/event/TurtleAction.java | 84 -- .../api/turtle/event/TurtleActionEvent.java | 85 -- .../api/turtle/event/TurtleAttackEvent.java | 73 -- .../api/turtle/event/TurtleBlockEvent.java | 224 ----- .../api/turtle/event/TurtleEvent.java | 14 +- .../turtle/event/TurtleInspectItemEvent.java | 90 --- .../turtle/event/TurtleInventoryEvent.java | 87 -- .../api/turtle/event/TurtlePlayerEvent.java | 44 - .../api/turtle/event/TurtleRefuelEvent.java | 14 +- .../core/apis/ComputerAccess.java | 1 + .../dan200/computercraft/core/apis/FSAPI.java | 88 +- .../dan200/computercraft/core/apis/OSAPI.java | 63 +- .../computercraft/core/apis/RedstoneAPI.java | 16 +- .../computercraft/core/apis/TermAPI.java | 1 + .../computercraft/core/apis/TermMethods.java | 12 + .../apis/handles/BinaryReadableHandle.java | 5 + .../apis/handles/BinaryWritableHandle.java | 2 + .../apis/handles/EncodedReadableHandle.java | 2 + .../core/apis/http/NetworkUtils.java | 2 +- .../core/apis/http/options/AddressRule.java | 2 +- .../apis/http/request/HttpResponseHandle.java | 1 + .../apis/http/websocket/WebsocketHandle.java | 3 + .../computercraft/core/asm/Generator.java | 11 +- .../computercraft/core/asm/GenericMethod.java | 51 +- .../computercraft/core/asm/LuaMethod.java | 2 +- .../computercraft/core/asm/NamedMethod.java | 14 +- .../core/asm/PeripheralMethod.java | 2 +- .../computercraft/core/asm/ResultHelpers.java | 27 + .../core/computer/Environment.java | 6 +- .../core/computer/MainThread.java | 2 +- .../core/filesystem/ResourceMount.java | 80 +- .../computercraft/core/lua/LuaContext.java | 9 - .../core/lua/ResultInterpreterFunction.java | 2 +- .../core/tracking/ComputerMBean.java | 155 ++++ .../peripheral/modem/ModemPeripheral.java | 144 ++-- .../peripheral/modem/wired/TileCable.java | 2 +- .../modem/wired/TileWiredModemFull.java | 2 +- .../modem/wired/WiredModemPeripheral.java | 4 +- .../modem/wireless/TileWirelessModem.java | 2 +- .../wireless/WirelessModemPeripheral.java | 2 +- .../modem/wireless/WirelessNetwork.java | 38 +- .../peripherals/PocketModemPeripheral.java | 2 +- .../proxy/ComputerCraftProxyCommon.java | 2 - .../shared/turtle/FurnaceRefuelHandler.java | 2 +- .../shared/turtle/SignInspectHandler.java | 33 - .../shared/turtle/apis/TurtleAPI.java | 9 - .../shared/turtle/core/TurtleBrain.java | 20 +- .../turtle/core/TurtleCompareCommand.java | 2 +- .../turtle/core/TurtleCraftCommand.java | 4 +- .../turtle/core/TurtleDetectCommand.java | 2 +- .../shared/turtle/core/TurtleDropCommand.java | 13 +- .../turtle/core/TurtleEquipCommand.java | 11 +- .../turtle/core/TurtleInspectCommand.java | 12 +- .../shared/turtle/core/TurtleMoveCommand.java | 10 +- .../turtle/core/TurtlePlaceCommand.java | 18 +- .../shared/turtle/core/TurtlePlayer.java | 6 +- .../turtle/core/TurtleRefuelCommand.java | 22 +- .../shared/turtle/core/TurtleSuckCommand.java | 12 +- .../shared/turtle/core/TurtleTurnCommand.java | 9 - .../upgrades/TurtleInventoryCrafting.java | 108 +-- .../shared/turtle/upgrades/TurtleModem.java | 6 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 2 +- .../shared/turtle/upgrades/TurtleTool.java | 22 +- .../computercraft/shared/util/Config.java | 28 +- .../shared/wired/WiredNetwork.java | 763 ++++++++---------- .../computercraft/shared/wired/WiredNode.java | 114 ++- .../computercraft/lua/rom/apis/rednet.lua | 52 +- .../computercraft/lua/rom/apis/window.lua | 2 + .../rom/help/{changelog.txt => changelog.md} | 0 .../rom/help/{whatsnew.txt => whatsnew.md} | 0 .../computercraft/lua/rom/programs/about.lua | 4 + .../computercraft/lua/rom/programs/motd.lua | 2 + .../lua/rom/programs/rednet/repeat.lua | 6 +- 127 files changed, 1923 insertions(+), 2622 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/lua/TaskCallback.java create mode 100644 src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java create mode 100644 src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java create mode 100644 src/main/java/dan200/computercraft/core/asm/ResultHelpers.java create mode 100644 src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java delete mode 100644 src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java rename src/main/resources/data/computercraft/lua/rom/help/{changelog.txt => changelog.md} (100%) rename src/main/resources/data/computercraft/lua/rom/help/{whatsnew.txt => whatsnew.md} (100%) create mode 100644 src/main/resources/data/computercraft/lua/rom/programs/about.lua diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 317bfd0ef..00f116d64 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -6,7 +6,6 @@ package dan200.computercraft; -import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.shared.ComputerCraftRegistry.ModBlocks; @@ -40,7 +39,6 @@ import org.apache.logging.log4j.Logger; import java.util.Arrays; import java.util.Collections; -import java.util.EnumSet; import java.util.List; import java.util.concurrent.TimeUnit; @@ -91,7 +89,6 @@ public final class ComputerCraft implements ModInitializer public static int advancedTurtleFuelLimit = 100000; public static boolean turtlesObeyBlockProtection = true; public static boolean turtlesCanPush = true; - public static EnumSet turtleDisabledActions = EnumSet.noneOf( TurtleAction.class ); public static int computerTermWidth = 51; public static int computerTermHeight = 19; diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 7e7ae52ee..bef9f90d7 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api; import dan200.computercraft.api.filesystem.IMount; @@ -32,19 +31,11 @@ import javax.annotation.Nullable; /** * The static entry point to the ComputerCraft API. * - * Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is fully loaded. + * Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is + * fully loaded. */ public final class ComputerCraftAPI { - private static IComputerCraftAPI instance; - - @Nonnull - @Deprecated - public static String getAPIVersion() - { - return getInstalledVersion(); - } - @Nonnull public static String getInstalledVersion() { @@ -52,23 +43,10 @@ public final class ComputerCraftAPI } @Nonnull - private static IComputerCraftAPI getInstance() + @Deprecated + public static String getAPIVersion() { - if( instance != null ) - { - return instance; - } - - try - { - return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) - .getField( "INSTANCE" ) - .get( null ); - } - catch( ReflectiveOperationException e ) - { - throw new IllegalStateException( "Cannot find ComputerCraft API", e ); - } + return getInstalledVersion(); } /** @@ -80,7 +58,8 @@ public final class ComputerCraftAPI * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk" * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason. * - * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. + * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now + * available for writing. * @see #createSaveDirMount(Level, String, long) */ public static int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath ) @@ -91,15 +70,15 @@ public final class ComputerCraftAPI /** * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it. * - * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the users save directory onto a computers - * file system. + * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the + * users save directory onto a computers file system. * * @param world The world for which the save dir can be found. This should be the server side world object. - * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42". Use createUniqueNumberedSaveDir() - * to create a new numbered folder to use. + * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42". + * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. * @param capacity The amount of data that can be stored in the directory before it fills up, in bytes. - * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() to mount this on a - * Computers' file system. + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. * @see #createUniqueNumberedSaveDir(Level, String) * @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mountWritable(String, IWritableMount) @@ -115,8 +94,8 @@ public final class ComputerCraftAPI /** * Creates a file system mount to a resource folder, and returns it. * - * Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a resource folder onto a computer's file - * system. + * Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a + * resource folder onto a computer's file system. * * The files in this mount will be a combination of files in all mod jar, and data packs that contain * resources with the same domain and path. For instance, ComputerCraft's resources are stored in @@ -137,7 +116,7 @@ public final class ComputerCraftAPI } /** - * Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations. + * rers a peripheral provider to convert blocks into {@link IPeripheral} implementations. * * @param provider The peripheral provider to register. * @see IPeripheral @@ -160,8 +139,9 @@ public final class ComputerCraftAPI } /** - * Registers a new turtle turtle for use in ComputerCraft. After calling this, users should be able to craft Turtles with your new turtle. It is - * recommended to call this during the load() method of your mod. + * Registers a new turtle turtle for use in ComputerCraft. After calling this, + * users should be able to craft Turtles with your new turtle. It is recommended to call + * this during the load() method of your mod. * * @param upgrade The turtle upgrade to register. * @see ITurtleUpgrade @@ -188,8 +168,8 @@ public final class ComputerCraftAPI * @param world The world this block is in. * @param pos The position this block is at. * @param side The side to extract the bundled redstone output from. - * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. If there is no block - * capable of emitting bundled redstone at the location, -1 will be returned. + * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. + * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. * @see IBundledRedstoneProvider */ public static int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) @@ -256,6 +236,24 @@ public final class ComputerCraftAPI return getInstance().getWiredElementAt( world, pos, side ); } + private static IComputerCraftAPI instance; + + @Nonnull + private static IComputerCraftAPI getInstance() + { + if( instance != null ) return instance; + + try + { + return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) + .getField( "INSTANCE" ).get( null ); + } + catch( ReflectiveOperationException e ) + { + throw new IllegalStateException( "Cannot find ComputerCraft API", e ); + } + } + public interface IComputerCraftAPI { @Nonnull diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index f0c3658ff..5a439da61 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -43,17 +43,13 @@ public final class TransformedModel public static TransformedModel of( @Nonnull ModelResourceLocation location ) { - ModelManager modelManager = Minecraft.getInstance() - .getModelManager(); + ModelManager modelManager = Minecraft.getInstance().getModelManager(); return new TransformedModel( modelManager.getModel( location ) ); } public static TransformedModel of( @Nonnull ItemStack item, @Nonnull Transformation transform ) { - BakedModel model = Minecraft.getInstance() - .getItemRenderer() - .getItemModelShaper() - .getItemModel( item ); + BakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel( item ); return new TransformedModel( model, transform ); } diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java index 20db37caa..82aa83686 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import java.nio.file.attribute.BasicFileAttributes; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index dc08e0268..638c61486 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java index 8c74731e3..7ce152db7 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import java.io.IOException; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 0e23748be..680f6fac3 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; @@ -17,10 +16,12 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.List; /** - * Represents a read only part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}. + * Represents a read only part of a virtual filesystem that can be mounted onto a computer using + * {@link IComputerAccess#mount(String, IMount)}. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or {@link - * ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! + * Ready made implementations of this interface can be created using + * {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or + * {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! * * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -29,43 +30,6 @@ import java.util.List; */ public interface IMount { - /** - * Returns the file names of all the files in a directory. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms". - * @param contents A list of strings. Add all the file names to this list. - * @throws IOException If the file was not a directory, or could not be listed. - */ - void list( @Nonnull String path, @Nonnull List contents ) throws IOException; - - /** - * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A channel representing the contents of the file. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to - * seek to arbitrary positions when using binary mode. - * @throws IOException If the file does not exist, or could not be opened. - */ - @Nonnull - ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; - - /** - * Get attributes about the given file. - * - * @param path The path to query. - * @return File attributes for the given file. - * @throws IOException If the file does not exist, or attributes could not be fetched. - */ - @Nonnull - default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException - { - if( !exists( path ) ) - { - throw new FileOperationException( path, "No such file" ); - } - return new FileAttributes( isDirectory( path ), getSize( path ) ); - } - /** * Returns whether a file with a given path exists or not. * @@ -84,6 +48,15 @@ public interface IMount */ boolean isDirectory( @Nonnull String path ) throws IOException; + /** + * Returns the file names of all the files in a directory. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms". + * @param contents A list of strings. Add all the file names to this list. + * @throws IOException If the file was not a directory, or could not be listed. + */ + void list( @Nonnull String path, @Nonnull List contents ) throws IOException; + /** * Returns the size of a file with a given path, in bytes. * @@ -92,4 +65,30 @@ public interface IMount * @throws IOException If the file does not exist, or its size could not be determined. */ long getSize( @Nonnull String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". + * @return A channel representing the contents of the file. If the channel implements + * {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary positions when using binary + * mode. + * @throws IOException If the file does not exist, or could not be opened. + */ + @Nonnull + ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; + + /** + * Get attributes about the given file. + * + * @param path The path to query. + * @return File attributes for the given file. + * @throws IOException If the file does not exist, or attributes could not be fetched. + */ + @Nonnull + default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + if( !exists( path ) ) throw new FileOperationException( path, "No such file" ); + return new FileAttributes( isDirectory( path ), getSize( path ) ); + } } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index 713e290fa..b1d7ca8ee 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; @@ -17,11 +16,11 @@ import java.nio.channels.WritableByteChannel; import java.util.OptionalLong; /** - * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} or {@link - * IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. + * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} + * or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to - * implement it yourselves! + * Ready made implementations of this interface can be created using + * {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to implement it yourselves! * * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see IComputerAccess#mount(String, IMount) @@ -50,8 +49,8 @@ public interface IWritableMount extends IMount * Opens a file with a given path, and returns an {@link OutputStream} for writing to it. * * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary - * positions when using binary mode. + * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one + * will be able to seek to arbitrary positions when using binary mode. * @throws IOException If the file could not be opened for writing. */ @Nonnull @@ -61,16 +60,16 @@ public interface IWritableMount extends IMount * Opens a file with a given path, and returns an {@link OutputStream} for appending to it. * * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary - * positions when using binary mode. + * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one + * will be able to seek to arbitrary positions when using binary mode. * @throws IOException If the file could not be opened for writing. */ @Nonnull WritableByteChannel openForAppend( @Nonnull String path ) throws IOException; /** - * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail - * once it reaches zero. + * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the + * mount, and write operations should fail once it reaches zero. * * @return The amount of free space, in bytes. * @throws IOException If the remaining space could not be computed. @@ -78,7 +77,8 @@ public interface IWritableMount extends IMount long getRemainingSpace() throws IOException; /** - * Get the capacity of this mount. This should be equal to the size of all files/directories on this mount, minus the {@link #getRemainingSpace()}. + * Get the capacity of this mount. This should be equal to the size of all files/directories on this mount, minus + * the {@link #getRemainingSpace()}. * * @return The capacity of this mount, in bytes. */ diff --git a/src/main/java/dan200/computercraft/api/lua/IArguments.java b/src/main/java/dan200/computercraft/api/lua/IArguments.java index 5546176ca..02e8b659d 100644 --- a/src/main/java/dan200/computercraft/api/lua/IArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/IArguments.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; @@ -19,25 +18,6 @@ import static dan200.computercraft.api.lua.LuaValues.checkFinite; */ public interface IArguments { - /** - * Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count}, rather than {@code i}. However, - * errors will still use the given argument index. - * - * @param count The number of arguments to drop. - * @return The new {@link IArguments} instance. - */ - IArguments drop( int count ); - - default Object[] getAll() - { - Object[] result = new Object[count()]; - for( int i = 0; i < result.length; i++ ) - { - result[i] = get( i ); - } - return result; - } - /** * Get the number of arguments passed to this function. * @@ -62,6 +42,37 @@ public interface IArguments @Nullable Object get( int index ); + /** + * Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count}, + * rather than {@code i}. However, errors will still use the given argument index. + * + * @param count The number of arguments to drop. + * @return The new {@link IArguments} instance. + */ + IArguments drop( int count ); + + default Object[] getAll() + { + Object[] result = new Object[count()]; + for( int i = 0; i < result.length; i++ ) result[i] = get( i ); + return result; + } + + /** + * Get an argument as a double. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a number. + * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN). + */ + default double getDouble( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return ((Number) value).doubleValue(); + } + /** * Get an argument as an integer. * @@ -84,12 +95,8 @@ public interface IArguments default long getLong( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof Number) ) - { - throw LuaValues.badArgumentOf( index, "number", value ); - } - return LuaValues.checkFiniteNum( index, (Number) value ) - .longValue(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return LuaValues.checkFiniteNum( index, (Number) value ).longValue(); } /** @@ -104,24 +111,6 @@ public interface IArguments return checkFinite( index, getDouble( index ) ); } - /** - * Get an argument as a double. - * - * @param index The argument number. - * @return The argument's value. - * @throws LuaException If the value is not a number. - * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN). - */ - default double getDouble( int index ) throws LuaException - { - Object value = get( index ); - if( !(value instanceof Number) ) - { - throw LuaValues.badArgumentOf( index, "number", value ); - } - return ((Number) value).doubleValue(); - } - /** * Get an argument as a boolean. * @@ -132,26 +121,10 @@ public interface IArguments default boolean getBoolean( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof Boolean) ) - { - throw LuaValues.badArgumentOf( index, "boolean", value ); - } + if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value ); return (Boolean) value; } - /** - * Get a string argument as a byte array. - * - * @param index The argument number. - * @return The argument's value. This is a read only buffer. - * @throws LuaException If the value is not a string. - */ - @Nonnull - default ByteBuffer getBytes( int index ) throws LuaException - { - return LuaValues.encode( getString( index ) ); - } - /** * Get an argument as a string. * @@ -163,13 +136,23 @@ public interface IArguments default String getString( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof String) ) - { - throw LuaValues.badArgumentOf( index, "string", value ); - } + if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value ); return (String) value; } + /** + * Get a string argument as a byte array. + * + * @param index The argument number. + * @return The argument's value. This is a read only buffer. + * @throws LuaException If the value is not a string. + */ + @Nonnull + default ByteBuffer getBytes( int index ) throws LuaException + { + return LuaValues.encode( getString( index ) ); + } + /** * Get a string argument as an enum value. * @@ -196,75 +179,10 @@ public interface IArguments default Map getTable( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof Map) ) - { - throw LuaValues.badArgumentOf( index, "table", value ); - } + if( !(value instanceof Map) ) throw LuaValues.badArgumentOf( index, "table", value ); return (Map) value; } - /** - * Get a string argument as a byte array. - * - * @param index The argument number. - * @return The argument's value, or {@link Optional#empty()} if not present. This is a read only buffer. - * @throws LuaException If the value is not a string. - */ - default Optional optBytes( int index ) throws LuaException - { - return optString( index ).map( LuaValues::encode ); - } - - /** - * Get an argument as a string. - * - * @param index The argument number. - * @return The argument's value, or {@link Optional#empty()} if not present. - * @throws LuaException If the value is not a string. - */ - default Optional optString( int index ) throws LuaException - { - Object value = get( index ); - if( value == null ) - { - return Optional.empty(); - } - if( !(value instanceof String) ) - { - throw LuaValues.badArgumentOf( index, "string", value ); - } - return Optional.of( (String) value ); - } - - /** - * Get a string argument as an enum value. - * - * @param index The argument number. - * @param klass The type of enum to parse. - * @param The type of enum to parse. - * @return The argument's value. - * @throws LuaException If the value is not a string or not a valid option for this enum. - */ - @Nonnull - default > Optional optEnum( int index, Class klass ) throws LuaException - { - Optional str = optString( index ); - return str.isPresent() ? Optional.of( LuaValues.checkEnum( index, klass, str.get() ) ) : Optional.empty(); - } - - /** - * Get an argument as a double. - * - * @param index The argument number. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a number. - */ - default double optDouble( int index, double def ) throws LuaException - { - return optDouble( index ).orElse( def ); - } - /** * Get an argument as a double. * @@ -276,30 +194,11 @@ public interface IArguments default Optional optDouble( int index ) throws LuaException { Object value = get( index ); - if( value == null ) - { - return Optional.empty(); - } - if( !(value instanceof Number) ) - { - throw LuaValues.badArgumentOf( index, "number", value ); - } + if( value == null ) return Optional.empty(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); return Optional.of( ((Number) value).doubleValue() ); } - /** - * Get an argument as an int. - * - * @param index The argument number. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a number. - */ - default int optInt( int index, int def ) throws LuaException - { - return optInt( index ).orElse( def ); - } - /** * Get an argument as an int. * @@ -323,16 +222,122 @@ public interface IArguments default Optional optLong( int index ) throws LuaException { Object value = get( index ); - if( value == null ) - { - return Optional.empty(); - } - if( !(value instanceof Number) ) - { - throw LuaValues.badArgumentOf( index, "number", value ); - } - return Optional.of( LuaValues.checkFiniteNum( index, (Number) value ) - .longValue() ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return Optional.of( LuaValues.checkFiniteNum( index, (Number) value ).longValue() ); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not finite. + */ + default Optional optFiniteDouble( int index ) throws LuaException + { + Optional value = optDouble( index ); + if( value.isPresent() ) LuaValues.checkFiniteNum( index, value.get() ); + return value; + } + + /** + * Get an argument as a boolean. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a boolean. + */ + default Optional optBoolean( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value ); + return Optional.of( (Boolean) value ); + } + + /** + * Get an argument as a string. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a string. + */ + default Optional optString( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value ); + return Optional.of( (String) value ); + } + + /** + * Get a string argument as a byte array. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. This is a read only buffer. + * @throws LuaException If the value is not a string. + */ + default Optional optBytes( int index ) throws LuaException + { + return optString( index ).map( LuaValues::encode ); + } + + /** + * Get a string argument as an enum value. + * + * @param index The argument number. + * @param klass The type of enum to parse. + * @param The type of enum to parse. + * @return The argument's value. + * @throws LuaException If the value is not a string or not a valid option for this enum. + */ + @Nonnull + default > Optional optEnum( int index, Class klass ) throws LuaException + { + Optional str = optString( index ); + return str.isPresent() ? Optional.of( LuaValues.checkEnum( index, klass, str.get() ) ) : Optional.empty(); + } + + /** + * Get an argument as a table. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a table. + */ + default Optional> optTable( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Map) ) throw LuaValues.badArgumentOf( index, "map", value ); + return Optional.of( (Map) value ); + } + + /** + * Get an argument as a double. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + default double optDouble( int index, double def ) throws LuaException + { + return optDouble( index ).orElse( def ); + } + + /** + * Get an argument as an int. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + default int optInt( int index, int def ) throws LuaException + { + return optInt( index ).orElse( def ); } /** @@ -361,23 +366,6 @@ public interface IArguments return optFiniteDouble( index ).orElse( def ); } - /** - * Get an argument as a finite number (not infinite or NaN). - * - * @param index The argument number. - * @return The argument's value, or {@link Optional#empty()} if not present. - * @throws LuaException If the value is not finite. - */ - default Optional optFiniteDouble( int index ) throws LuaException - { - Optional value = optDouble( index ); - if( value.isPresent() ) - { - LuaValues.checkFiniteNum( index, value.get() ); - } - return value; - } - /** * Get an argument as a boolean. * @@ -391,27 +379,6 @@ public interface IArguments return optBoolean( index ).orElse( def ); } - /** - * Get an argument as a boolean. - * - * @param index The argument number. - * @return The argument's value, or {@link Optional#empty()} if not present. - * @throws LuaException If the value is not a boolean. - */ - default Optional optBoolean( int index ) throws LuaException - { - Object value = get( index ); - if( value == null ) - { - return Optional.empty(); - } - if( !(value instanceof Boolean) ) - { - throw LuaValues.badArgumentOf( index, "boolean", value ); - } - return Optional.of( (Boolean) value ); - } - /** * Get an argument as a string. * @@ -437,25 +404,4 @@ public interface IArguments { return optTable( index ).orElse( def ); } - - /** - * Get an argument as a table. - * - * @param index The argument number. - * @return The argument's value, or {@link Optional#empty()} if not present. - * @throws LuaException If the value is not a table. - */ - default Optional> optTable( int index ) throws LuaException - { - Object value = get( index ); - if( value == null ) - { - return Optional.empty(); - } - if( !(value instanceof Map) ) - { - throw LuaValues.badArgumentOf( index, "map", value ); - } - return Optional.of( (Map) value ); - } } diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java index d9069b52a..fb76aceb4 100644 --- a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.filesystem.IFileSystem; @@ -12,7 +11,8 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import javax.annotation.Nullable; /** - * An interface passed to {@link ILuaAPIFactory} in order to provide additional information about a computer. + * An interface passed to {@link ILuaAPIFactory} in order to provide additional information + * about a computer. */ public interface IComputerSystem extends IComputerAccess { diff --git a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java index 49c4d6a47..ac3d3ce15 100644 --- a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java +++ b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.peripheral.IDynamicPeripheral; @@ -13,13 +12,15 @@ import javax.annotation.Nonnull; /** * An interface for representing custom objects returned by peripherals or other Lua objects. * - * Generally, one does not need to implement this type - it is sufficient to return an object with some methods annotated with {@link LuaFunction}. {@link - * IDynamicLuaObject} is useful when you wish your available methods to change at runtime. + * Generally, one does not need to implement this type - it is sufficient to return an object with some methods + * annotated with {@link LuaFunction}. {@link IDynamicLuaObject} is useful when you wish your available methods to + * change at runtime. */ public interface IDynamicLuaObject { /** - * Get the names of the methods that this object implements. This should not change over the course of the object's lifetime. + * Get the names of the methods that this object implements. This should not change over the course of the object's + * lifetime. * * @return The method names this object provides. * @see IDynamicPeripheral#getMethodNames() @@ -30,10 +31,13 @@ public interface IDynamicLuaObject /** * Called when a user calls one of the methods that this object implements. * - * @param context The context of the currently running lua thread. This can be used to wait for events or otherwise yield. - * @param method An integer identifying which method index from {@link #getMethodNames()} the computer wishes to call. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which method index from {@link #getMethodNames()} the computer wishes + * to call. * @param arguments The arguments for this method. - * @return The result of this function. Either an immediate value ({@link MethodResult#of(Object...)} or an instruction to yield. + * @return The result of this function. Either an immediate value ({@link MethodResult#of(Object...)} or an + * instruction to yield. * @throws LuaException If the function threw an exception. */ @Nonnull diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java index ca33136dc..e1a1d4a54 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -3,17 +3,16 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.ComputerCraftAPI; /** - * Represents a Lua object which is stored as a global variable on computer startup. This must either provide {@link LuaFunction} annotated functions or - * implement {@link IDynamicLuaObject}. + * Represents a Lua object which is stored as a global variable on computer startup. This must either provide + * {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}. * - * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred to use peripherals to provide - * functionality to users. + * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred + * to use peripherals to provide functionality to users. * * @see ILuaAPIFactory * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java index 9b4fbbc47..7db976eb9 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java index b24e4b25e..e999042af 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; @@ -18,7 +17,8 @@ public interface ILuaCallback /** * Resume this coroutine. * - * @param args The result of resuming this coroutine. These will have the same form as described in {@link LuaFunction}. + * @param args The result of resuming this coroutine. These will have the same form as described in + * {@link LuaFunction}. * @return The result of this continuation. Either the result to return to the callee, or another yield. * @throws LuaException On an error. */ diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java index 6d1aba949..4d29b57d1 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; @@ -41,5 +40,8 @@ public interface ILuaContext * @throws LuaException If the task could not be queued, or if the task threw an exception. */ @Nonnull - MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; + default MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException + { + return TaskCallback.make( this, task ); + } } diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java index 70d900c2c..7813cbbdc 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java @@ -3,14 +3,13 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; /** - * A function, which can be called from Lua. If you need to return a table of functions, it is recommended to use an object with {@link LuaFunction} - * methods, or implement {@link IDynamicLuaObject}. + * A function, which can be called from Lua. If you need to return a table of functions, it is recommended to use + * an object with {@link LuaFunction} methods, or implement {@link IDynamicLuaObject}. * * @see MethodResult#of(Object) */ @@ -18,8 +17,8 @@ import javax.annotation.Nonnull; public interface ILuaFunction { /** - * Call this function with a series of arguments. Note, this will always be called on the computer thread, and so its implementation must be - * thread-safe. + * Call this function with a series of arguments. Note, this will always be called on the computer thread, + * and so its implementation must be thread-safe. * * @param arguments The arguments for this function * @return The result of calling this function. diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java index 44a429ed4..808e635b5 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -3,14 +3,14 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nullable; /** - * A task which can be executed via {@link ILuaContext#issueMainThreadTask(ILuaTask)} This will be run on the main thread, at the beginning of the next - * tick. + * A task which can be executed via {@link ILuaContext#issueMainThreadTask(ILuaTask)} This will be run on the main + * thread, at the beginning of the + * next tick. * * @see ILuaContext#issueMainThreadTask(ILuaTask) */ @@ -21,8 +21,9 @@ public interface ILuaTask * Execute this task. * * @return The arguments to add to the {@code task_completed} event. - * @throws LuaException If you throw any exception from this function, a lua error will be raised with the same message as your exception. Use this - * to throw appropriate errors if the wrong arguments are supplied to your method. + * @throws LuaException If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. */ @Nullable Object[] execute() throws LuaException; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java index df97ed0fa..e2738ea91 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nullable; @@ -42,7 +41,8 @@ public class LuaException extends Exception } /** - * The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so on. + * The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so + * on. * * @return The level to raise the error at. */ diff --git a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java index 064149466..5558b153c 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -16,8 +15,8 @@ import java.util.Optional; /** * Used to mark a Java function which is callable from Lua. * - * Methods annotated with {@link LuaFunction} must be public final instance methods. They can have any number of parameters, but they must be of the - * following types: + * Methods annotated with {@link LuaFunction} must be public final instance methods. They can have any number of + * parameters, but they must be of the following types: * *
    *
  • {@link ILuaContext} (and {@link IComputerAccess} if on a {@link IPeripheral})
  • @@ -49,7 +48,8 @@ public @interface LuaFunction String[] value() default {}; /** - * Run this function on the main server thread. This should be specified for any method which interacts with Minecraft in a thread-unsafe manner. + * Run this function on the main server thread. This should be specified for any method which interacts with + * Minecraft in a thread-unsafe manner. * * @return Whether this functi * @see ILuaContext#issueMainThreadTask(ILuaTask) diff --git a/src/main/java/dan200/computercraft/api/lua/LuaValues.java b/src/main/java/dan200/computercraft/api/lua/LuaValues.java index a78091060..8eec784ff 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaValues.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaValues.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; @@ -38,8 +37,41 @@ public final class LuaValues chars[i] = c < 256 ? (byte) c : 63; } - return ByteBuffer.wrap( chars ) - .asReadOnlyBuffer(); + return ByteBuffer.wrap( chars ).asReadOnlyBuffer(); + } + + /** + * Returns a more detailed representation of this number's type. If this is finite, it will just return "number", + * otherwise it returns whether it is infinite or NaN. + * + * @param value The value to extract the type for. + * @return This value's numeric type. + */ + @Nonnull + public static String getNumericType( double value ) + { + if( Double.isNaN( value ) ) return "nan"; + if( value == Double.POSITIVE_INFINITY ) return "inf"; + if( value == Double.NEGATIVE_INFINITY ) return "-inf"; + return "number"; + } + + /** + * Get a string representation of the given value's type. + * + * @param value The value whose type we are trying to compute. + * @return A string representation of the given value's type, in a similar format to that provided by Lua's + * {@code type} function. + */ + @Nonnull + public static String getType( @Nullable Object value ) + { + if( value == null ) return "nil"; + if( value instanceof String ) return "string"; + if( value instanceof Boolean ) return "boolean"; + if( value instanceof Number ) return "number"; + if( value instanceof Map ) return "table"; + return "userdata"; } /** @@ -70,38 +102,6 @@ public final class LuaValues return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); } - /** - * Get a string representation of the given value's type. - * - * @param value The value whose type we are trying to compute. - * @return A string representation of the given value's type, in a similar format to that provided by Lua's {@code type} function. - */ - @Nonnull - public static String getType( @Nullable Object value ) - { - if( value == null ) - { - return "nil"; - } - if( value instanceof String ) - { - return "string"; - } - if( value instanceof Boolean ) - { - return "boolean"; - } - if( value instanceof Number ) - { - return "number"; - } - if( value instanceof Map ) - { - return "table"; - } - return "userdata"; - } - /** * Ensure a numeric argument is finite (i.e. not infinite or {@link Double#NaN}. * @@ -126,38 +126,10 @@ public final class LuaValues */ public static double checkFinite( int index, double value ) throws LuaException { - if( !Double.isFinite( value ) ) - { - throw badArgument( index, "number", getNumericType( value ) ); - } + if( !Double.isFinite( value ) ) throw badArgument( index, "number", getNumericType( value ) ); return value; } - /** - * Returns a more detailed representation of this number's type. If this is finite, it will just return "number", otherwise it returns whether it is - * infinite or NaN. - * - * @param value The value to extract the type for. - * @return This value's numeric type. - */ - @Nonnull - public static String getNumericType( double value ) - { - if( Double.isNaN( value ) ) - { - return "nan"; - } - if( value == Double.POSITIVE_INFINITY ) - { - return "inf"; - } - if( value == Double.NEGATIVE_INFINITY ) - { - return "-inf"; - } - return "number"; - } - /** * Ensure a string is a valid enum value. * @@ -172,11 +144,7 @@ public final class LuaValues { for( T possibility : klass.getEnumConstants() ) { - if( possibility.name() - .equalsIgnoreCase( value ) ) - { - return possibility; - } + if( possibility.name().equalsIgnoreCase( value ) ) return possibility; } throw new LuaException( "bad argument #" + (index + 1) + " (unknown option " + value + ")" ); diff --git a/src/main/java/dan200/computercraft/api/lua/MethodResult.java b/src/main/java/dan200/computercraft/api/lua/MethodResult.java index 8787bf911..7d15d60b7 100644 --- a/src/main/java/dan200/computercraft/api/lua/MethodResult.java +++ b/src/main/java/dan200/computercraft/api/lua/MethodResult.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -18,8 +17,8 @@ import java.util.Objects; /** * The result of invoking a Lua method. * - * Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine. When the current coroutine is resumed, - * we invoke the provided {@link ILuaCallback#resume(Object[])} callback. + * Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine. + * When the current coroutine is resumed, we invoke the provided {@link ILuaCallback#resume(Object[])} callback. */ public final class MethodResult { @@ -57,11 +56,12 @@ public final class MethodResult /** * Return a single value immediately. * - * Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be converted to their corresponding Lua - * type. {@code byte[]} and {@link ByteBuffer} will be treated as binary strings. {@link ILuaFunction} will be treated as a function. + * Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be + * converted to their corresponding Lua type. {@code byte[]} and {@link ByteBuffer} will be treated as binary + * strings. {@link ILuaFunction} will be treated as a function. * - * In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary class with {@link LuaFunction} - * annotations. Anything else will be converted to {@code nil}. + * In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary + * class with {@link LuaFunction} annotations. Anything else will be converted to {@code nil}. * * @param value The value to return to the calling Lua function. * @return A method result which returns immediately with the given value. @@ -85,8 +85,8 @@ public final class MethodResult } /** - * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly equivalent to {@code os.pullEvent()} in - * lua. + * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly + * equivalent to {@code os.pullEvent()} in lua. * * @param filter A specific event to wait for, or null to wait for any event. * @param callback The callback to resume with the name of the event that occurred, and any event parameters. @@ -98,17 +98,15 @@ public final class MethodResult { Objects.requireNonNull( callback, "callback cannot be null" ); return new MethodResult( new Object[] { filter }, results -> { - if( results.length >= 1 && results[0].equals( "terminate" ) ) - { - throw new LuaException( "Terminated", 0 ); - } + if( results.length >= 1 && results[0].equals( "terminate" ) ) throw new LuaException( "Terminated", 0 ); return callback.resume( results ); } ); } /** - * The same as {@link #pullEvent(String, ILuaCallback)}, except "terminated" events are ignored. Only use this if you want to prevent program - * termination, which is not recommended. This method is exactly equivalent to {@code os.pullEventRaw()} in Lua. + * The same as {@link #pullEvent(String, ILuaCallback)}, except "terminated" events are ignored. Only use this if + * you want to prevent program termination, which is not recommended. This method is exactly equivalent to + * {@code os.pullEventRaw()} in Lua. * * @param filter A specific event to wait for, or null to wait for any event. * @param callback The callback to resume with the name of the event that occurred, and any event parameters. @@ -123,8 +121,8 @@ public final class MethodResult } /** - * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to {@code coroutine.yield()} in lua. Use - * {@code pullEvent()} if you wish to wait for events. + * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to + * {@code coroutine.yield()} in lua. Use {@code pullEvent()} if you wish to wait for events. * * @param arguments An object array containing the arguments to pass to coroutine.yield() * @param callback The callback to resume with an array containing the return values from coroutine.yield() @@ -156,7 +154,8 @@ public final class MethodResult } /** - * Increase the Lua error by a specific amount. One should never need to use this function - it largely exists for some CC internal code. + * Increase the Lua error by a specific amount. One should never need to use this function - it largely exists for + * some CC internal code. * * @param adjust The amount to increase the level by. * @return The new {@link MethodResult} with an adjusted error. This has no effect on immediate results. @@ -164,14 +163,8 @@ public final class MethodResult @Nonnull public MethodResult adjustError( int adjust ) { - if( adjust < 0 ) - { - throw new IllegalArgumentException( "cannot adjust by a negative amount" ); - } - if( adjust == 0 || callback == null ) - { - return this; - } + if( adjust < 0 ) throw new IllegalArgumentException( "cannot adjust by a negative amount" ); + if( adjust == 0 || callback == null ) return this; return new MethodResult( result, callback, this.adjust + adjust ); } } diff --git a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java index d800d0ac6..6dd7e3c0f 100644 --- a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nullable; @@ -36,41 +35,32 @@ public final class ObjectArguments implements IArguments this.args = Objects.requireNonNull( args ); } - @Override - public IArguments drop( int count ) - { - if( count < 0 ) - { - throw new IllegalStateException( "count cannot be negative" ); - } - if( count == 0 ) - { - return this; - } - if( count >= args.size() ) - { - return EMPTY; - } - - return new ObjectArguments( args.subList( count, args.size() ) ); - } - - @Override - public Object[] getAll() - { - return args.toArray(); - } - @Override public int count() { return args.size(); } + @Override + public IArguments drop( int count ) + { + if( count < 0 ) throw new IllegalStateException( "count cannot be negative" ); + if( count == 0 ) return this; + if( count >= args.size() ) return EMPTY; + + return new ObjectArguments( args.subList( count, args.size() ) ); + } + @Nullable @Override public Object get( int index ) { return index >= args.size() ? null : args.get( index ); } + + @Override + public Object[] getAll() + { + return args.toArray(); + } } diff --git a/src/main/java/dan200/computercraft/api/lua/TaskCallback.java b/src/main/java/dan200/computercraft/api/lua/TaskCallback.java new file mode 100644 index 000000000..85870a221 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/TaskCallback.java @@ -0,0 +1,53 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +final class TaskCallback implements ILuaCallback +{ + private final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); + private final long task; + + private TaskCallback( long task ) + { + this.task = task; + } + + @Nonnull + @Override + public MethodResult resume( Object[] response ) throws LuaException + { + if( response.length < 3 || !(response[1] instanceof Number) || !(response[2] instanceof Boolean) ) + { + return pull; + } + + if( ((Number) response[1]).longValue() != task ) return pull; + + if( (Boolean) response[2] ) + { + // Extract the return values from the event and return them + return MethodResult.of( Arrays.copyOfRange( response, 3, response.length ) ); + } + else if( response.length >= 4 && response[3] instanceof String ) + { + // Extract the error message from the event and raise it + throw new LuaException( (String) response[3] ); + } + else + { + throw new LuaException( "error" ); + } + } + + static MethodResult make( ILuaContext context, ILuaTask func ) throws LuaException + { + long task = context.issueMainThreadTask( func ); + return new TaskCallback( task ).pull; + } +} diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index 414d9895b..da0be8da7 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.media; import dan200.computercraft.api.filesystem.IMount; @@ -18,7 +17,8 @@ import javax.annotation.Nullable; /** * Represents an item that can be placed in a disk drive and used by a Computer. * - * Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register a {@link IMediaProvider}. + * Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register + * a {@link IMediaProvider}. */ public interface IMedia { @@ -44,7 +44,8 @@ public interface IMedia } /** - * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathan Coulton - Still Alive" + * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: + * "Jonathan Coulton - Still Alive" * * @param stack The {@link ItemStack} to modify. * @return The name, or null if this item does not represent an item with audio. @@ -68,13 +69,13 @@ public interface IMedia } /** - * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of - * the computer while the media is in the disk drive. + * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will + * be mounted onto the filesystem of the computer while the media is in the disk drive. * * @param stack The {@link ItemStack} to modify. * @param world The world in which the item and disk drive reside. - * @return The mount, or null if this item does not represent an item with data. If the mount returned also implements {@link - * dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable() + * @return The mount, or null if this item does not represent an item with data. If the mount returned also + * implements {@link dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable() * @see IMount * @see dan200.computercraft.api.filesystem.IWritableMount * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(Level, String, long) diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index 023e4d12c..04ec9f9d6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.media; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java index b897717c6..277150156 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network; import javax.annotation.Nonnull; @@ -38,8 +37,8 @@ public interface IPacketNetwork boolean isWireless(); /** - * Submit a packet for transmitting across the network. This will route the packet through the network, sending it to all receivers within range (or any - * interdimensional ones). + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers within range (or any interdimensional ones). * * @param packet The packet to send. * @param range The maximum distance this packet will be sent. @@ -49,8 +48,8 @@ public interface IPacketNetwork void transmitSameDimension( @Nonnull Packet packet, double range ); /** - * Submit a packet for transmitting across the network. This will route the packet through the network, sending it to all receivers across all - * dimensions. + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers across all dimensions. * * @param packet The packet to send. * @see #transmitSameDimension(Packet, double) diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index ccea2630f..b8a639828 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network; import net.minecraft.world.level.Level; @@ -22,7 +21,7 @@ public interface IPacketReceiver * @return The receivers's world. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Get the position in the world at which this receiver exists. @@ -35,8 +34,9 @@ public interface IPacketReceiver /** * Get the maximum distance this receiver can send and receive messages. * - * When determining whether a receiver can receive a message, the largest distance of the packet and receiver is used - ensuring it is within range. If - * the packet or receiver is inter-dimensional, then the packet will always be received. + * When determining whether a receiver can receive a message, the largest distance of the packet and receiver is + * used - ensuring it is within range. If the packet or receiver is inter-dimensional, then the packet will always + * be received. * * @return The maximum distance this device can send and receive messages. * @see #isInterdimensional() @@ -60,8 +60,8 @@ public interface IPacketReceiver /** * Receive a network packet from the same dimension. * - * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, if so, queue the appropriate - * modem event. + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. * @param distance The distance this packet has travelled from the source. * @see Packet * @see #getRange() @@ -73,8 +73,8 @@ public interface IPacketReceiver /** * Receive a network packet from a different dimension. * - * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, if so, queue the appropriate - * modem event. + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. * @see Packet * @see IPacketNetwork#transmitInterdimensional(Packet) * @see IPacketNetwork#transmitSameDimension(Packet, double) diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index 310dd92d1..b6346952a 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network; import net.minecraft.world.level.Level; @@ -22,7 +21,7 @@ public interface IPacketSender * @return The sender's world. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Get the position in the world at which this sender exists. @@ -33,8 +32,8 @@ public interface IPacketSender Vec3 getPosition(); /** - * Get some sort of identification string for this sender. This does not strictly need to be unique, but you should be able to extract some identifiable - * information from it. + * Get some sort of identification string for this sender. This does not strictly need to be unique, but you + * should be able to extract some identifiable information from it. * * @return This device's id. */ diff --git a/src/main/java/dan200/computercraft/api/network/Packet.java b/src/main/java/dan200/computercraft/api/network/Packet.java index 34b2bd41f..5d1854120 100644 --- a/src/main/java/dan200/computercraft/api/network/Packet.java +++ b/src/main/java/dan200/computercraft/api/network/Packet.java @@ -3,128 +3,28 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - /** * Represents a packet which may be sent across a {@link IPacketNetwork}. * + * @param channel The channel to send the packet along. Receiving devices should only process packets from on + * channels they are listening to. + * @param replyChannel The channel to reply on. + * @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an + * event or returning from a peripheral call. + * @param sender The object which sent this packet. * @see IPacketSender * @see IPacketNetwork#transmitSameDimension(Packet, double) * @see IPacketNetwork#transmitInterdimensional(Packet) * @see IPacketReceiver#receiveDifferentDimension(Packet) * @see IPacketReceiver#receiveSameDimension(Packet, double) */ -public class Packet +public record Packet( + int channel, + int replyChannel, + Object payload, + IPacketSender sender +) { - private final int channel; - private final int replyChannel; - private final Object payload; - - private final IPacketSender sender; - - /** - * Create a new packet, ready for transmitting across the network. - * - * @param channel The channel to send the packet along. Receiving devices should only process packets from on channels they are listening to. - * @param replyChannel The channel to reply on. - * @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an event or returning from a peripheral - * call. - * @param sender The object which sent this packet. - */ - public Packet( int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender ) - { - Objects.requireNonNull( sender, "sender cannot be null" ); - - this.channel = channel; - this.replyChannel = replyChannel; - this.payload = payload; - this.sender = sender; - } - - /** - * Get the channel this packet is sent along. Receivers should generally only process packets from on channels they are listening to. - * - * @return This packet's channel. - */ - public int getChannel() - { - return channel; - } - - /** - * The channel to reply on. Objects which will reply should send it along this channel. - * - * @return This channel to reply on. - */ - public int getReplyChannel() - { - return replyChannel; - } - - /** - * The actual data of this packet. This should be a "valid" Lua object, safe for queuing as an event or returning from a peripheral call. - * - * @return The packet's payload - */ - @Nullable - public Object getPayload() - { - return payload; - } - - /** - * The object which sent this message. - * - * @return The sending object. - */ - @Nonnull - public IPacketSender getSender() - { - return sender; - } - - @Override - public int hashCode() - { - int result; - result = channel; - result = 31 * result + replyChannel; - result = 31 * result + (payload != null ? payload.hashCode() : 0); - result = 31 * result + sender.hashCode(); - return result; - } - - @Override - public boolean equals( Object o ) - { - if( this == o ) - { - return true; - } - if( o == null || getClass() != o.getClass() ) - { - return false; - } - - Packet packet = (Packet) o; - - if( channel != packet.channel ) - { - return false; - } - if( replyChannel != packet.replyChannel ) - { - return false; - } - if( !Objects.equals( payload, packet.payload ) ) - { - return false; - } - return sender.equals( packet.sender ); - } } diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java index 5ca0ddb9f..390bd91e9 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.ComputerCraftAPI; @@ -13,16 +12,18 @@ import javax.annotation.Nonnull; /** * An object which may be part of a wired network. * - * Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts as a proxy for all network objects. - * Whilst the node may change networks, an element's node should remain constant for its lifespan. + * Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts + * as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant + * for its lifespan. * - * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the {@link IWiredElement} capability for the - * appropriate sides. + * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the + * {@link IWiredElement} capability for the appropriate sides. */ public interface IWiredElement extends IWiredSender { /** - * Called when objects on the network change. This may occur when network nodes are added or removed, or when peripherals change. + * Called when objects on the network change. This may occur when network nodes are added or removed, or when + * peripherals change. * * @param change The change which occurred. * @see IWiredNetworkChange diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java index fa44c4d1b..ae18cb691 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.peripheral.IPeripheral; @@ -12,14 +11,16 @@ import javax.annotation.Nonnull; import java.util.Map; /** - * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series of peripherals. + * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series + * of peripherals. * - * Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if there is some path between two nodes - * then they must be on the same network. {@link IWiredNetwork} will automatically handle the merging and splitting of networks (and thus changing of - * available nodes and peripherals) as connections change. + * Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if + * there is some path between two nodes then they must be on the same network. {@link IWiredNetwork} will automatically + * handle the merging and splitting of networks (and thus changing of available nodes and peripherals) as connections + * change. * - * This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently, it is generally preferred to use the - * methods provided by {@link IWiredNode}. + * This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently, + * it is generally preferred to use the methods provided by {@link IWiredNode}. * * @see IWiredNode#getNetwork() */ @@ -58,10 +59,12 @@ public interface IWiredNetwork /** * Sever all connections this node has, removing it from this network. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param node The node to remove - * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the only element. + * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the + * only element. * @throws IllegalArgumentException If the node is not in the network. * @see IWiredNode#remove() */ @@ -70,7 +73,8 @@ public interface IWiredNetwork /** * Update the peripherals a node provides. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param node The node to attach peripherals for. * @param peripherals The new peripherals for this node. diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java index bef4b1048..0663509a6 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.peripheral.IPeripheral; @@ -19,8 +18,8 @@ import java.util.Map; public interface IWiredNetworkChange { /** - * A set of peripherals which have been removed. Note that there may be entries with the same name in the added and removed set, but with a different - * peripheral. + * A set of peripherals which have been removed. Note that there may be entries with the same name + * in the added and removed set, but with a different peripheral. * * @return The set of removed peripherals. */ @@ -28,8 +27,8 @@ public interface IWiredNetworkChange Map peripheralsRemoved(); /** - * A set of peripherals which have been added. Note that there may be entries with the same name in the added and removed set, but with a different - * peripheral. + * A set of peripherals which have been added. Note that there may be entries with the same name + * in the added and removed set, but with a different peripheral. * * @return The set of added peripherals. */ diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java index 73afe2fd7..e72f25a62 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.network.IPacketNetwork; @@ -15,14 +14,15 @@ import java.util.Map; /** * Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s. * - * Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These methods may be safely used on any - * thread. + * Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These + * methods may be safely used on any thread. * - * When sending a packet, the system will attempt to find the shortest path between the two nodes based on their element's position. Note that packet - * senders and receivers can have different locations from their associated element: the distance between the two will be added to the total packet's - * distance. + * When sending a packet, the system will attempt to find the shortest path between the two nodes based on their + * element's position. Note that packet senders and receivers can have different locations from their associated + * element: the distance between the two will be added to the total packet's distance. * - * Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever be used on the main server thread. + * Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever + * be used on the main server thread. */ public interface IWiredNode extends IPacketNetwork { @@ -34,6 +34,17 @@ public interface IWiredNode extends IPacketNetwork @Nonnull IWiredElement getElement(); + /** + * The network this node is currently connected to. Note that this may change + * after any network operation, so it should not be cached. + * + * This should only be used on the server thread. + * + * @return This node's network. + */ + @Nonnull + IWiredNetwork getNetwork(); + /** * Create a connection from this node to another. * @@ -49,16 +60,6 @@ public interface IWiredNode extends IPacketNetwork return getNetwork().connect( this, node ); } - /** - * The network this node is currently connected to. Note that this may change after any network operation, so it should not be cached. - * - * This should only be used on the server thread. - * - * @return This node's network. - */ - @Nonnull - IWiredNetwork getNetwork(); - /** * Destroy a connection between this node and another. * @@ -78,9 +79,11 @@ public interface IWiredNode extends IPacketNetwork /** * Sever all connections this node has, removing it from this network. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * - * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the only element. + * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the + * only element. * @throws IllegalArgumentException If the node is not in the network. * @see IWiredNetwork#remove(IWiredNode) */ @@ -92,7 +95,8 @@ public interface IWiredNode extends IPacketNetwork /** * Mark this node's peripherals as having changed. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param peripherals The new peripherals for this node. * @see IWiredNetwork#updatePeripherals(IWiredNode, Map) diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java index c306b0a6b..f2795eced 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.network.IPacketSender; @@ -13,14 +12,16 @@ import javax.annotation.Nonnull; /** * An object on a {@link IWiredNetwork} capable of sending packets. * - * Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to to send the packet from. + * Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to + * to send the packet from. */ public interface IWiredSender extends IPacketSender { /** * The node in the network representing this object. * - * This should be used as a proxy for the main network. One should send packets and register receivers through this object. + * This should be used as a proxy for the main network. One should send packets + * and register receivers through this object. * * @return The node for this element. */ diff --git a/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java new file mode 100644 index 000000000..15988b3d3 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java @@ -0,0 +1,45 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.peripheral; + +import dan200.computercraft.api.lua.GenericSource; +import net.minecraft.world.Container; +import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; + +/** + * A {@link GenericSource} which provides methods for a peripheral. + * + * Unlike a {@link GenericSource}, all methods should target the same type, for instance a + * {@link BlockEntity} subclass or a capability interface. This is not currently enforced. + */ +public interface GenericPeripheral extends GenericSource +{ + /** + * Get the type of the exposed peripheral. + * + * Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the + * resulting peripheral uses the resource name of the wrapped {@link BlockEntity} (for instance {@literal minecraft:chest}). + * + * However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows + * you to do so. + * + * When multiple {@link GenericPeripheral}s return a non-empty peripheral type for a single tile entity, the + * lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be + * implemented when your peripheral targets a single tile entity AND it's likely that you're the + * only mod to do so. Similarly this should NOT be implemented when your methods target an + * interface (i.e. {@link Container}). + * + * @return The type of this peripheral or {@link PeripheralType#untyped()}. + * @see IPeripheral#getType() + */ + @Nonnull + default PeripheralType getType() + { + return PeripheralType.untyped(); + } +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 7012b482e..11c9dec1a 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import dan200.computercraft.api.ComputerCraftAPI; @@ -20,8 +19,9 @@ import javax.annotation.Nullable; import java.util.Map; /** - * The interface passed to peripherals by computers or turtles, providing methods that they can call. This should not be implemented by your classes. Do not - * interact with computers except via this interface. + * The interface passed to peripherals by computers or turtles, providing methods + * that they can call. This should not be implemented by your classes. Do not interact + * with computers except via this interface. */ public interface IComputerAccess { @@ -30,8 +30,8 @@ public interface IComputerAccess * * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. - * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a file in the desired location. - * Store this value if you wish to unmount the mount later. + * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a + * file in the desired location. Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -52,8 +52,8 @@ public interface IComputerAccess * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. - * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a file in the desired location. - * Store this value if you wish to unmount the mount later. + * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a + * file in the desired location. Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -65,24 +65,13 @@ public interface IComputerAccess @Nullable String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName ); - /** - * Get a string, unique to the computer, by which the computer refers to this peripheral. For directly attached peripherals this will be - * "left","right","front","back",etc, but for peripherals attached remotely it will be different. It is good practice to supply this string when raising - * events to the computer, so that the computer knows from which peripheral the event came. - * - * @return A string unique to the computer, but not globally. - * @throws NotAttachedException If the peripheral has been detached. - */ - @Nonnull - String getAttachmentName(); - /** * Mount a mount onto the computer's file system in a writable mode. * * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. - * @return The location on the computer's file system where you the mount mounted, or null if there was already a file in the desired location. Store - * this value if you wish to unmount the mount later. + * @return The location on the computer's file system where you the mount mounted, or null if there was already a + * file in the desired location. Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -102,8 +91,8 @@ public interface IComputerAccess * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. - * @return The location on the computer's file system where you the mount mounted, or null if there was already a file in the desired location. Store - * this value if you wish to unmount the mount later. + * @return The location on the computer's file system where you the mount mounted, or null if there was already a + * file in the desired location. Store this value if you wish to unmount the mount later. * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -114,16 +103,18 @@ public interface IComputerAccess String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName ); /** - * Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)} or {@link #mountWritable(String, - * IWritableMount)}. + * Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)} + * or {@link #mountWritable(String, IWritableMount)}. * - * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to access it. All directories - * mounted by a mount or mountWritable are automatically unmounted when the peripheral is attached if they have not been explicitly unmounted. + * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be + * able to access it. All directories mounted by a mount or mountWritable are automatically unmounted when the + * peripheral is attached if they have not been explicitly unmounted. * * Note that you cannot unmount another peripheral's mounts. * - * @param location The desired location in the computers file system of the directory to unmount. This must be the location of a directory - * previously mounted by {@link #mount(String, IMount)} or {@link #mountWritable(String, IWritableMount)}, as indicated by their return value. + * @param location The desired location in the computers file system of the directory to unmount. + * This must be the location of a directory previously mounted by {@link #mount(String, IMount)} or + * {@link #mountWritable(String, IWritableMount)}, as indicated by their return value. * @throws NotAttachedException If the peripheral has been detached. * @throws IllegalStateException If the mount does not exist, or was mounted by another peripheral. * @see #mount(String, IMount) @@ -134,22 +125,26 @@ public interface IComputerAccess /** * Returns the numerical ID of this computer. * - * This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua, and is guaranteed unique. This number - * will be positive. + * This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua, + * and is guaranteed unique. This number will be positive. * * @return The identifier. */ int getID(); /** - * Causes an event to be raised on this computer, which the computer can respond to by calling {@code os.pullEvent()}. This can be used to notify the - * computer when things happen in the world or to this peripheral. + * Causes an event to be raised on this computer, which the computer can respond to by calling + * {@code os.pullEvent()}. This can be used to notify the computer when things happen in the world or to + * this peripheral. * - * @param event A string identifying the type of event that has occurred, this will be returned as the first value from {@code os.pullEvent()}. It - * is recommended that you you choose a name that is unique, and recognisable as originating from your peripheral. eg: If your peripheral type is - * "button", a suitable event would be "button_pressed". - * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will be supplied as extra return values to - * os.pullEvent(). Objects in the array will be converted to lua data types in the same fashion as the return values of IPeripheral.callMethod(). + * @param event A string identifying the type of event that has occurred, this will be + * returned as the first value from {@code os.pullEvent()}. It is recommended that you + * you choose a name that is unique, and recognisable as originating from your + * peripheral. eg: If your peripheral type is "button", a suitable event would be + * "button_pressed". + * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will + * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted + * to lua data types in the same fashion as the return values of IPeripheral.callMethod(). * * You may supply {@code null} to indicate that no arguments are to be supplied. * @throws NotAttachedException If the peripheral has been detached. @@ -157,6 +152,19 @@ public interface IComputerAccess */ void queueEvent( @Nonnull String event, @Nullable Object... arguments ); + /** + * Get a string, unique to the computer, by which the computer refers to this peripheral. + * For directly attached peripherals this will be "left","right","front","back",etc, but + * for peripherals attached remotely it will be different. It is good practice to supply + * this string when raising events to the computer, so that the computer knows from + * which peripheral the event came. + * + * @return A string unique to the computer, but not globally. + * @throws NotAttachedException If the peripheral has been detached. + */ + @Nonnull + String getAttachmentName(); + /** * Get a set of peripherals that this computer access can "see", along with their attachment name. * @@ -171,8 +179,8 @@ public interface IComputerAccess Map getAvailablePeripherals(); /** - * Get a reachable peripheral with the given attachment name. This is a equivalent to {@link #getAvailablePeripherals()}{@code .get(name)}, though may - * be more efficient. + * Get a reachable peripheral with the given attachment name. This is a equivalent to + * {@link #getAvailablePeripherals()}{@code .get(name)}, though may be more efficient. * * @param name The peripheral's attached name * @return The reachable peripheral, or {@code null} if none can be found. @@ -184,11 +192,13 @@ public interface IComputerAccess /** * Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread. * - * This should be used to ensure your peripheral integrates with ComputerCraft's monitoring and limiting of how much server time each computer consumes. - * You should not need to use this if you use {@link ILuaContext#issueMainThreadTask(ILuaTask)} - this is intended for mods with their own system for - * running work on the main thread. + * This should be used to ensure your peripheral integrates with ComputerCraft's monitoring and limiting of how much + * server time each computer consumes. You should not need to use this if you use + * {@link ILuaContext#issueMainThreadTask(ILuaTask)} - this is intended for mods with their own system for running + * work on the main thread. * - * Please note that the returned implementation is not thread-safe, and should only be used from the main thread. + * Please note that the returned implementation is not thread-safe, and should only be used from the main + * thread. * * @return The work monitor for the main thread, or {@code null} if this computer does not have one. * @throws NotAttachedException If the peripheral has been detached. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java index e06c14096..695680b94 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import dan200.computercraft.api.lua.*; @@ -13,14 +12,14 @@ import javax.annotation.Nonnull; /** * A peripheral whose methods are not known at runtime. * - * This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}. Generally one may use {@link LuaFunction} - * instead of implementing this interface. + * This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}. + * Generally one may use {@link LuaFunction} instead of implementing this interface. */ public interface IDynamicPeripheral extends IPeripheral { /** - * Should return an array of strings that identify the methods that this peripheral exposes to Lua. This will be called once before each attachment, and - * should not change when called multiple times. + * Should return an array of strings that identify the methods that this peripheral exposes to Lua. This will be + * called once before each attachment, and should not change when called multiple times. * * @return An array of strings representing method names. * @see #callMethod @@ -29,19 +28,24 @@ public interface IDynamicPeripheral extends IPeripheral String[] getMethodNames(); /** - * This is called when a lua program on an attached computer calls {@code peripheral.call()} with one of the methods exposed by {@link - * #getMethodNames()}. + * This is called when a lua program on an attached computer calls {@code peripheral.call()} with + * one of the methods exposed by {@link #getMethodNames()}. * - * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe when interacting with Minecraft objects. + * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe when interacting + * with Minecraft objects. * - * @param computer The interface to the computer that is making the call. Remember that multiple computers can be attached to a peripheral at once. - * @param context The context of the currently running lua thread. This can be used to wait for events or otherwise yield. - * @param method An integer identifying which of the methods from getMethodNames() the computercraft wishes to call. The integer indicates the index - * into the getMethodNames() table that corresponds to the string passed into peripheral.call() + * @param computer The interface to the computer that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which of the methods from getMethodNames() the computercraft + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() * @param arguments The arguments for this method. * @return A {@link MethodResult} containing the values to return or the action to perform. - * @throws LuaException If you throw any exception from this function, a lua error will be raised with the same message as your exception. Use this - * to throw appropriate errors if the wrong arguments are supplied to your method. + * @throws LuaException If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. * @see #getMethodNames() */ @Nonnull diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 09a63c64d..eddc30861 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import dan200.computercraft.api.lua.LuaFunction; @@ -17,12 +16,14 @@ import javax.annotation.Nullable; * In order to expose a peripheral for your block or tile entity, you register a {@link IPeripheralProvider}. This cannot be implemented {@link * IPeripheral} directly on the tile. * - * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing {@link IDynamicPeripheral}. + * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing + * {@link IDynamicPeripheral}. */ public interface IPeripheral { /** - * Should return a string that uniquely identifies this type of peripheral. This can be queried from lua by calling {@code peripheral.getType()} + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling {@code peripheral.getType()} * * @return A string identifying the type of peripheral. */ @@ -32,15 +33,19 @@ public interface IPeripheral /** * Is called when when a computer is attaching to the peripheral. * - * This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a peripheral, when a turtle travels into - * a square next to a peripheral, or when a wired modem adjacent to this peripheral is does any of the above. + * This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a + * peripheral, when a turtle travels into a square next to a peripheral, or when a wired modem adjacent to this + * peripheral is does any of the above. * - * Between calls to attach and {@link #detach}, the attached computer can make method calls on the peripheral using {@code peripheral.call()}. This - * method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment occurs. + * Between calls to attach and {@link #detach}, the attached computer can make method calls on the peripheral using + * {@code peripheral.call()}. This method can be used to keep track of which computers are attached to the + * peripheral, or to take action when attachment occurs. * - * Be aware that will be called from both the server thread and ComputerCraft Lua thread, and so must be thread-safe and reentrant. + * Be aware that will be called from both the server thread and ComputerCraft Lua thread, and so must be thread-safe + * and reentrant. * - * @param computer The interface to the computer that is being attached. Remember that multiple computers can be attached to a peripheral at once. + * @param computer The interface to the computer that is being attached. Remember that multiple computers can be + * attached to a peripheral at once. * @see #detach */ default void attach( @Nonnull IComputerAccess computer ) @@ -50,14 +55,18 @@ public interface IPeripheral /** * Called when a computer is detaching from the peripheral. * - * This will occur when a computer shuts down, when the peripheral is removed while attached to computers, when a turtle moves away from a block - * attached to a peripheral, or when a wired modem adjacent to this peripheral is detached. + * This will occur when a computer shuts down, when the peripheral is removed while attached to computers, when a + * turtle moves away from a block attached to a peripheral, or when a wired modem adjacent to this peripheral is + * detached. * - * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment occurs. + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when + * detachment occurs. * - * Be aware that this will be called from both the server and ComputerCraft Lua thread, and must be thread-safe and reentrant. + * Be aware that this will be called from both the server and ComputerCraft Lua thread, and must be thread-safe + * and reentrant. * - * @param computer The interface to the computer that is being detached. Remember that multiple computers can be attached to a peripheral at once. + * @param computer The interface to the computer that is being detached. Remember that multiple computers can be + * attached to a peripheral at once. * @see #attach */ default void detach( @Nonnull IComputerAccess computer ) @@ -65,7 +74,8 @@ public interface IPeripheral } /** - * Get the object that this peripheral provides methods for. This will generally be the tile entity or block, but may be an inventory, entity, etc... + * Get the object that this peripheral provides methods for. This will generally be the tile entity + * or block, but may be an inventory, entity, etc... * * @return The object this peripheral targets */ @@ -78,8 +88,8 @@ public interface IPeripheral /** * Determine whether this peripheral is equivalent to another one. * - * The minimal example should at least check whether they are the same object. However, you may wish to check if they point to the same block or tile - * entity. + * The minimal example should at least check whether they are the same object. However, you may wish to check if + * they point to the same block or tile entity. * * @param other The peripheral to compare against. This may be {@code null}. * @return Whether these peripherals are equivalent. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 20e8e416f..98e97d628 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -3,22 +3,18 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nonnull; -import java.util.Optional; +import javax.annotation.Nullable; /** * This interface is used to create peripheral implementations for blocks. * - * If you have a {@link BlockEntity} which acts as a peripheral, you may alternatively expose the {@link IPeripheral} capability. - * * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ @FunctionalInterface @@ -30,9 +26,9 @@ public interface IPeripheralProvider * @param world The world the block is in. * @param pos The position the block is at. * @param side The side to get the peripheral from. - * @return A peripheral, or {@link Optional#empty()} if there is not a peripheral here you'd like to handle. + * @return A peripheral or {@literal null} if there is not a peripheral here you'd like to handle. * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ - @Nonnull + @Nullable IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java index 21ae59438..2ec3f3df9 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import javax.annotation.Nonnull; @@ -11,14 +10,15 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; /** - * Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every computer receives a fair share of any - * processing time. + * Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every + * computer receives a fair share of any processing time. * - * This is primarily intended for work done by peripherals on the main thread (such as on a tile entity's tick), but could be used for other purposes (such - * as complex computations done on another thread). + * This is primarily intended for work done by peripherals on the main thread (such as on a tile entity's tick), but + * could be used for other purposes (such as complex computations done on another thread). * - * Before running a task, one should call {@link #canWork()} to determine if the computer is currently allowed to execute work. If that returns true, you - * should execute the task and use {@link #trackWork(long, TimeUnit)} to inform the monitor how long that task took. + * Before running a task, one should call {@link #canWork()} to determine if the computer is currently allowed to + * execute work. If that returns true, you should execute the task and use {@link #trackWork(long, TimeUnit)} to inform + * the monitor how long that task took. * * Alternatively, use {@link #runWork(Runnable)} to run and keep track of work. * @@ -26,16 +26,31 @@ import java.util.concurrent.TimeUnit; */ public interface IWorkMonitor { + /** + * If the owning computer is currently allowed to execute work. + * + * @return If we can execute work right now. + */ + boolean canWork(); + /** * If the owning computer is currently allowed to execute work, and has ample time to do so. * - * This is effectively a more restrictive form of {@link #canWork()}. One should use that in order to determine if you may do an initial piece of work, - * and shouldWork to determine if any additional task may be performed. + * This is effectively a more restrictive form of {@link #canWork()}. One should use that in order to determine if + * you may do an initial piece of work, and shouldWork to determine if any additional task may be performed. * * @return If we should execute work right now. */ boolean shouldWork(); + /** + * Inform the monitor how long some piece of work took to execute. + * + * @param time The time some task took to run + * @param unit The unit that {@code time} was measured in. + */ + void trackWork( long time, @Nonnull TimeUnit unit ); + /** * Run a task if possible, and inform the monitor of how long it took. * @@ -45,10 +60,7 @@ public interface IWorkMonitor default boolean runWork( @Nonnull Runnable runnable ) { Objects.requireNonNull( runnable, "runnable should not be null" ); - if( !canWork() ) - { - return false; - } + if( !canWork() ) return false; long start = System.nanoTime(); try @@ -62,19 +74,4 @@ public interface IWorkMonitor return true; } - - /** - * If the owning computer is currently allowed to execute work. - * - * @return If we can execute work right now. - */ - boolean canWork(); - - /** - * Inform the monitor how long some piece of work took to execute. - * - * @param time The time some task took to run - * @param unit The unit that {@code time} was measured in. - */ - void trackWork( long time, @Nonnull TimeUnit unit ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java index 335841cfb..96ebd11ac 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java +++ b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java @@ -3,11 +3,11 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; /** - * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to the computer. + * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to + * the computer. */ public class NotAttachedException extends IllegalStateException { diff --git a/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java b/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java new file mode 100644 index 000000000..2780534c2 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java @@ -0,0 +1,62 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.peripheral; + +import com.google.common.base.Strings; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * The type of a {@link GenericPeripheral}. + * + * When determining the final type of the resulting peripheral, the union of all types is taken, with the + * lexicographically smallest non-empty name being chosen. + */ +public final class PeripheralType +{ + private static final PeripheralType UNTYPED = new PeripheralType( null ); + + private final String type; + + public PeripheralType( String type ) + { + this.type = type; + } + + /** + * An empty peripheral type, used when a {@link GenericPeripheral} does not have an explicit type. + * + * @return The empty peripheral type. + */ + public static PeripheralType untyped() + { + return UNTYPED; + } + + /** + * Create a new non-empty peripheral type. + * + * @param type The name of the type. + * @return The constructed peripheral type. + */ + public static PeripheralType ofType( @Nonnull String type ) + { + if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); + return new PeripheralType( type ); + } + + /** + * Get the name of this peripheral type. This may be {@literal null}. + * + * @return The type of this peripheral. + */ + @Nullable + public String getPrimaryType() + { + return type; + } +} diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index cd8a2f55e..ccb68d834 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import dan200.computercraft.shared.util.NonNullSupplier; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index f8ee4010b..2fa939153 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; @@ -33,7 +32,8 @@ public interface IPocketAccess /** * Get the colour of this pocket computer as a RGB number. * - * @return The colour this pocket computer is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. + * @return The colour this pocket computer is. This will be a RGB colour between {@code 0x000000} and + * {@code 0xFFFFFF} or -1 if it has no colour. * @see #setColour(int) */ int getColour(); @@ -41,8 +41,8 @@ public interface IPocketAccess /** * Set the colour of the pocket computer to a RGB number. * - * @param colour The colour this pocket computer should be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or - * -1 to reset to the default colour. + * @param colour The colour this pocket computer should be changed to. This should be a RGB colour between + * {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getColour() */ void setColour( int colour ); @@ -50,7 +50,8 @@ public interface IPocketAccess /** * Get the colour of this pocket computer's light as a RGB number. * - * @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. + * @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or + * -1 if it has no colour. * @see #setLight(int) */ int getLight(); @@ -58,8 +59,8 @@ public interface IPocketAccess /** * Set the colour of the pocket computer's light to a RGB number. * - * @param colour The colour this modem's light will be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 - * to reset to the default colour. + * @param colour The colour this modem's light will be changed to. This should be a RGB colour between + * {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getLight() */ void setLight( int colour ); diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index d81e59d51..4e39f0b38 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; @@ -24,8 +23,9 @@ public interface IPocketUpgrade extends IUpgradeBase /** * Creates a peripheral for the pocket computer. * - * The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to {@link #update(IPocketAccess, IPeripheral)} and - * will be attached, detached and have methods called in the same manner as an ordinary peripheral. + * The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to + * {@link #update(IPocketAccess, IPeripheral)} and will be attached, detached and have methods called in the same + * manner as an ordinary peripheral. * * @param access The access object for the pocket item stack. * @return The newly created peripheral. @@ -51,8 +51,9 @@ public interface IPocketUpgrade extends IUpgradeBase * @param world The world the computer is in. * @param access The access object for the pocket item stack. * @param peripheral The peripheral for this upgrade. - * @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path which returns {@code false}, such as - * requiring the player to be sneaking - otherwise they will be unable to access the GUI. + * @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path + * which returns {@code false}, such as requiring the player to be sneaking - otherwise they will be unable to + * access the GUI. * @see #createPeripheral(IPocketAccess) */ default boolean onRightClick( @Nonnull Level world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index 092f79d51..1f2f4f4ad 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.redstone; import net.minecraft.core.BlockPos; @@ -26,7 +25,8 @@ public interface IBundledRedstoneProvider * @param world The world this block is in. * @param pos The position this block is at. * @param side The side to extract the bundled redstone output from. - * @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block. + * @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to + * handle this block. * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) */ int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 0f876f109..d9de8062a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import com.mojang.authlib.GameProfile; @@ -24,7 +23,8 @@ import javax.annotation.Nullable; /** * The interface passed to turtle by turtles, providing methods that they can call. * - * This should not be implemented by your classes. Do not interact with turtles except via this interface and {@link ITurtleUpgrade}. + * This should not be implemented by your classes. Do not interact with turtles except via this interface and + * {@link ITurtleUpgrade}. */ public interface ITurtleAccess { @@ -34,7 +34,7 @@ public interface ITurtleAccess * @return the world in which the turtle resides. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Returns a vector containing the integer co-ordinates at which the turtle resides. @@ -47,18 +47,20 @@ public interface ITurtleAccess /** * Attempt to move this turtle to a new position. * - * This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should be used before playing a movement animation - * using {@link #playAnimation(TurtleAnimation)}. + * This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should + * be used before playing a movement animation using {@link #playAnimation(TurtleAnimation)}. * * @param world The new world to move it to * @param pos The new position to move it to. - * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement was cancelled. + * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement + * was cancelled. * @throws UnsupportedOperationException When attempting to teleport on the client side. */ boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ); /** - * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. This will shift when the turtle is moving. + * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. + * This will shift when the turtle is moving. * * @param f The subframe fraction. * @return A vector containing the floating point co-ordinates at which the turtle resides. @@ -86,8 +88,8 @@ public interface ITurtleAccess Direction getDirection(); /** - * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to call {@link - * #playAnimation(TurtleAnimation)} to do so. + * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to + * call {@link #playAnimation(TurtleAnimation)} to do so. * * @param dir The new direction to set. This should be on either the x or z axis (so north, south, east or west). * @see #getDirection() @@ -106,30 +108,32 @@ public interface ITurtleAccess /** * Set the currently selected slot in the turtle's inventory. * - * @param slot The slot to set. This must be greater or equal to 0 and less than the inventory size. Otherwise no action will be taken. + * @param slot The slot to set. This must be greater or equal to 0 and less than the inventory size. Otherwise no + * action will be taken. * @throws UnsupportedOperationException When attempting to change the slot on the client side. * @see #getInventory() * @see #getSelectedSlot() */ void setSelectedSlot( int slot ); - /** - * Get the colour of this turtle as a RGB number. - * - * @return The colour this turtle is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. - * @see #setColour(int) - */ - int getColour(); - /** * Set the colour of the turtle to a RGB number. * - * @param colour The colour this turtle should be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 to - * reset to the default colour. + * @param colour The colour this turtle should be changed to. This should be a RGB colour between {@code 0x000000} + * and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getColour() */ void setColour( int colour ); + /** + * Get the colour of this turtle as a RGB number. + * + * @return The colour this turtle is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or + * -1 if it has no colour. + * @see #setColour(int) + */ + int getColour(); + /** * Get the player who owns this turtle, namely whoever placed it. * @@ -138,6 +142,32 @@ public interface ITurtleAccess @Nullable GameProfile getOwningPlayer(); + /** + * Get the inventory of this turtle. + * + * Note: this inventory should only be accessed and modified on the server thread. + * + * @return This turtle's inventory + * @see #getItemHandler() + */ + @Nonnull + Container getInventory(); + + /** + * Get the inventory of this turtle as an {@link ItemStorage}. + * + * Note: this inventory should only be accessed and modified on the server thread. + * + * @return This turtle's inventory + * @see #getInventory() + * @see ItemStorage + */ + @Nonnull + default ItemStorage getItemHandler() + { + return ItemStorage.wrap( getInventory() ); + } + /** * Determine whether this turtle will require fuel when performing actions. * @@ -157,7 +187,8 @@ public interface ITurtleAccess int getFuelLevel(); /** - * Set the fuel level to a new value. It is generally preferred to use {@link #consumeFuel(int)}} or {@link #addFuel(int)} instead. + * Set the fuel level to a new value. It is generally preferred to use {@link #consumeFuel(int)}} or {@link #addFuel(int)} + * instead. * * @param fuel The new amount of fuel. This must be between 0 and the fuel limit. * @see #getFuelLevel() @@ -178,8 +209,8 @@ public interface ITurtleAccess * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. * * @param fuel The amount of fuel to consume. - * @return Whether the turtle was able to consume the amount of fuel specified. Will return false if you supply a number greater than the current fuel - * level of the turtle. No fuel will be consumed if {@code false} is returned. + * @return Whether the turtle was able to consume the amount of fuel specified. Will return false if you supply a number + * greater than the current fuel level of the turtle. No fuel will be consumed if {@code false} is returned. * @throws UnsupportedOperationException When attempting to consume fuel on the client side. */ boolean consumeFuel( int fuel ); @@ -193,13 +224,15 @@ public interface ITurtleAccess void addFuel( int fuel ); /** - * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed on the main thread, so are - * guaranteed to be able to access Minecraft objects safely, and will be queued up with the turtles standard movement and tool commands. An issued - * command will return an unique integer, which will be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has - * completed. Look at the lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. + * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed + * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up + * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will + * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the + * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. * * @param command An object which will execute the custom command when its point in the queue is reached - * @return The objects the command returned when executed. you should probably return these to the player unchanged if called from a peripheral method. + * @return The objects the command returned when executed. you should probably return these to the player + * unchanged if called from a peripheral method. * @throws UnsupportedOperationException When attempting to execute a command on the client side. * @see ITurtleCommand * @see MethodResult#pullEvent(String, ILuaCallback) @@ -208,7 +241,8 @@ public interface ITurtleAccess MethodResult executeCommand( @Nonnull ITurtleCommand command ); /** - * Start playing a specific animation. This will prevent other turtle commands from executing until it is finished. + * Start playing a specific animation. This will prevent other turtle commands from executing until + * it is finished. * * @param animation The animation to play. * @throws UnsupportedOperationException When attempting to execute play an animation on the client side. @@ -247,8 +281,8 @@ public interface ITurtleAccess /** * Get an upgrade-specific NBT compound, which can be used to store arbitrary data. * - * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must call {@link - * #updateUpgradeNBTData(TurtleSide)} after modifying it. + * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must + * call {@link #updateUpgradeNBTData(TurtleSide)} after modifying it. * * @param side The side to get the upgrade data for. * @return The upgrade-specific data. @@ -258,25 +292,11 @@ public interface ITurtleAccess CompoundTag getUpgradeNBTData( @Nullable TurtleSide side ); /** - * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the client and persisted. + * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the + * client and persisted. * * @param side The side to mark dirty. * @see #updateUpgradeNBTData(TurtleSide) */ void updateUpgradeNBTData( @Nonnull TurtleSide side ); - - default ItemStorage getItemHandler() - { - return ItemStorage.wrap( getInventory() ); - } - - /** - * Get the inventory of this turtle. - * - * Note: this inventory should only be accessed and modified on the server thread. - * - * @return This turtle's inventory - */ - @Nonnull - Container getInventory(); } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java index 134bb346d..e7300a02c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import javax.annotation.Nonnull; @@ -19,8 +18,8 @@ public interface ITurtleCommand /** * Will be called by the turtle on the main thread when it is time to execute the custom command. * - * The handler should either perform the work of the command, and return success, or return failure with an error message to indicate the command cannot - * be executed at this time. + * The handler should either perform the work of the command, and return success, or return + * failure with an error message to indicate the command cannot be executed at this time. * * @param turtle Access to the turtle for whom the command was issued. * @return A result, indicating whether this action succeeded or not. diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 4fc3d69f9..52acab992 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import dan200.computercraft.api.ComputerCraftAPI; @@ -18,7 +17,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new peripheral. + * The primary interface for defining an update for Turtles. A turtle update + * can either be a new tool, or a new peripheral. * * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade) */ @@ -36,12 +36,14 @@ public interface ITurtleUpgrade extends IUpgradeBase /** * Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade. * - * The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to {@link #update(ITurtleAccess, - * TurtleSide)}. It will be attached, detached and have methods called in the same manner as a Computer peripheral. + * The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to + * {@link #update(ITurtleAccess, TurtleSide)}. It will be attached, detached and have methods called in the same + * manner as a Computer peripheral. * * @param turtle Access to the turtle that the peripheral is being created for. * @param side Which side of the turtle (left or right) that the upgrade resides on. - * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool and this method is not expected to be called. + * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool + * and this method is not expected to be called. */ @Nullable default IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) @@ -50,16 +52,19 @@ public interface ITurtleUpgrade extends IUpgradeBase } /** - * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called by the turtle, and the tool is required to do some work. + * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called + * by the turtle, and the tool is required to do some work. * * @param turtle Access to the turtle that the tool resides on. * @param side Which side of the turtle (left or right) the tool resides on. * @param verb Which action (dig or attack) the turtle is being called on to perform. - * @param direction Which world direction the action should be performed in, relative to the turtles position. This will either be up, down, or the - * direction the turtle is facing, depending on whether dig, digUp or digDown was called. - * @return Whether the turtle was able to perform the action, and hence whether the {@code turtle.dig()} or {@code turtle.attack()} lua method should - * return true. If true is returned, the tool will perform a swinging animation. You may return {@code null} if this turtle is a Peripheral and - * this method is not expected to be called. + * @param direction Which world direction the action should be performed in, relative to the turtles + * position. This will either be up, down, or the direction the turtle is facing, depending on + * whether dig, digUp or digDown was called. + * @return Whether the turtle was able to perform the action, and hence whether the {@code turtle.dig()} + * or {@code turtle.attack()} lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return {@code null} if this turtle is a Peripheral and this method is not expected + * to be called. */ @Nonnull default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) @@ -70,6 +75,10 @@ public interface ITurtleUpgrade extends IUpgradeBase /** * Called to obtain the model to be used when rendering a turtle peripheral. * + * This can be obtained from {@link net.minecraft.client.renderer.ItemModelShaper#getItemModel(ItemStack)}, + * {@link net.minecraft.client.resources.model.ModelManager#getModel(ModelResourceLocation)} or any other + * source. + * * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models! * @param side Which side of the turtle (left or right) the upgrade resides on. * @return The model that you wish to be used to render your upgrade. diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java index f4468b5c9..dd67a044a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** @@ -24,34 +23,38 @@ public enum TurtleAnimation NONE, /** - * Make the turtle move forward. Note that the animation starts from the block behind it, and moves into this one. + * Make the turtle move forward. Note that the animation starts from the block behind it, and + * moves into this one. */ MOVE_FORWARD, /** - * Make the turtle move backwards. Note that the animation starts from the block in front it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block in front it, and + * moves into this one. */ MOVE_BACK, /** - * Make the turtle move backwards. Note that the animation starts from the block above it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block above it, and + * moves into this one. */ MOVE_UP, /** - * Make the turtle move backwards. Note that the animation starts from the block below it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block below it, and + * moves into this one. */ MOVE_DOWN, /** - * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and the turtle turns to face in the current - * direction. + * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and + * the turtle turns to face in the current direction. */ TURN_LEFT, /** - * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and the turtle turns to face in the current - * direction. + * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and + * the turtle turns to face in the current direction. */ TURN_RIGHT, diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index 17f42bb85..eccd976e5 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -3,9 +3,10 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; +import net.minecraft.core.Direction; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -19,16 +20,6 @@ public final class TurtleCommandResult { private static final TurtleCommandResult EMPTY_SUCCESS = new TurtleCommandResult( true, null, null ); private static final TurtleCommandResult EMPTY_FAILURE = new TurtleCommandResult( false, null, null ); - private final boolean success; - private final String errorMessage; - private final Object[] results; - - private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) - { - this.success = success; - this.errorMessage = errorMessage; - this.results = results; - } /** * Create a successful command result with no result. @@ -50,10 +41,7 @@ public final class TurtleCommandResult @Nonnull public static TurtleCommandResult success( @Nullable Object[] results ) { - if( results == null || results.length == 0 ) - { - return EMPTY_SUCCESS; - } + if( results == null || results.length == 0 ) return EMPTY_SUCCESS; return new TurtleCommandResult( true, null, results ); } @@ -77,13 +65,21 @@ public final class TurtleCommandResult @Nonnull public static TurtleCommandResult failure( @Nullable String errorMessage ) { - if( errorMessage == null ) - { - return EMPTY_FAILURE; - } + if( errorMessage == null ) return EMPTY_FAILURE; return new TurtleCommandResult( false, errorMessage, null ); } + private final boolean success; + private final String errorMessage; + private final Object[] results; + + private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) + { + this.success = success; + this.errorMessage = errorMessage; + this.results = results; + } + /** * Determine whether the command executed successfully. * diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index 86edade62..e944cfe43 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java index a6c6fede4..daa036a8a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** @@ -14,20 +13,21 @@ package dan200.computercraft.api.turtle; public enum TurtleUpgradeType { /** - * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} and {@code turtle.attack()} methods (Such as - * pickaxe or sword on Mining and Melee turtles). + * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} + * and {@code turtle.attack()} methods (Such as pickaxe or sword on Mining and Melee turtles). */ TOOL, /** - * A peripheral adds a special peripheral which is attached to the side of the turtle, and can be interacted with the {@code peripheral} API (Such as - * the modem on Wireless Turtles). + * A peripheral adds a special peripheral which is attached to the side of the turtle, + * and can be interacted with the {@code peripheral} API (Such as the modem on Wireless Turtles). */ PERIPHERAL, /** - * An upgrade which provides both a tool and a peripheral. This can be used when you wish your upgrade to also provide methods. For example, a pickaxe - * could provide methods determining whether it can break the given block or not. + * An upgrade which provides both a tool and a peripheral. This can be used when you wish + * your upgrade to also provide methods. For example, a pickaxe could provide methods + * determining whether it can break the given block or not. */ BOTH; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index d4622b1a0..53a2b0ceb 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -3,11 +3,13 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; +import net.minecraft.core.Direction; + /** - * An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by a turtle. + * An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by + * a turtle. * * @see ITurtleUpgrade#getType() * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction) diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java deleted file mode 100644 index ca5ccecf6..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -/** - * A basic action that a turtle may perform, as accessed by the {@code turtle} API. - * - * @see TurtleActionEvent - */ -public enum TurtleAction -{ - /** - * A turtle moves to a new position. - * - * @see TurtleBlockEvent.Move - */ - MOVE, - - /** - * A turtle turns in a specific direction. - */ - TURN, - - /** - * A turtle attempts to dig a block. - * - * @see TurtleBlockEvent.Dig - */ - DIG, - - /** - * A turtle attempts to place a block or item in the world. - * - * @see TurtleBlockEvent.Place - */ - PLACE, - - /** - * A turtle attempts to attack an entity. - * - * @see TurtleActionEvent - */ - ATTACK, - - /** - * Drop an item into an inventory/the world. - * - * @see TurtleInventoryEvent.Drop - */ - DROP, - - /** - * Suck an item from an inventory or the world. - * - * @see TurtleInventoryEvent.Suck - */ - SUCK, - - /** - * Refuel the turtle's fuel levels. - */ - REFUEL, - - /** - * Equip or unequip an item. - */ - EQUIP, - - /** - * Inspect a block in world. - * - * @see TurtleBlockEvent.Inspect - */ - INSPECT, - - /** - * Gather metdata about an item in the turtle's inventory. - */ - INSPECT_ITEM, -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java deleted file mode 100644 index b6c129855..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.TurtleCommandResult; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - -/** - * An event fired when a turtle is performing a known action. - */ -public class TurtleActionEvent extends TurtleEvent -{ - private final TurtleAction action; - private String failureMessage; - private boolean cancelled = false; - - public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action ) - { - super( turtle ); - - Objects.requireNonNull( action, "action cannot be null" ); - this.action = action; - } - - public TurtleAction getAction() - { - return action; - } - - /** - * Sets the cancellation state of this action. - * - * If {@code cancel} is {@code true}, this action will not be carried out. - * - * @param cancel The new canceled value. - * @see TurtleCommandResult#failure() - * @deprecated Use {@link #setCanceled(boolean, String)} instead. - */ - @Deprecated - public void setCanceled( boolean cancel ) - { - setCanceled( cancel, null ); - } - - /** - * Set the cancellation state of this action, setting a failure message if required. - * - * If {@code cancel} is {@code true}, this action will not be carried out. - * - * @param cancel The new canceled value. - * @param failureMessage The message to return to the user explaining the failure. - * @see TurtleCommandResult#failure(String) - */ - public void setCanceled( boolean cancel, @Nullable String failureMessage ) - { - cancelled = true; - this.failureMessage = cancel ? failureMessage : null; - } - - /** - * Get the message with which this will fail. - * - * @return The failure message. - * @see TurtleCommandResult#failure() - * @see #setCanceled(boolean, String) - */ - @Nullable - public String getFailureMessage() - { - return failureMessage; - } - - public boolean isCancelled() - { - return cancelled; - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java deleted file mode 100644 index 64126aa39..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.world.entity.Entity; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * Fired when a turtle attempts to attack an entity. - * - * @see TurtleAction#ATTACK - */ -public class TurtleAttackEvent extends TurtlePlayerEvent -{ - private final Entity target; - private final ITurtleUpgrade upgrade; - private final TurtleSide side; - - public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade, - @Nonnull TurtleSide side ) - { - super( turtle, TurtleAction.ATTACK, player ); - Objects.requireNonNull( target, "target cannot be null" ); - Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - Objects.requireNonNull( side, "side cannot be null" ); - this.target = target; - this.upgrade = upgrade; - this.side = side; - } - - /** - * Get the entity being attacked by this turtle. - * - * @return The entity being attacked. - */ - @Nonnull - public Entity getTarget() - { - return target; - } - - /** - * Get the upgrade responsible for attacking. - * - * @return The upgrade responsible for attacking. - */ - @Nonnull - public ITurtleUpgrade getUpgrade() - { - return upgrade; - } - - /** - * Get the side the attacking upgrade is on. - * - * @return The upgrade's side. - */ - @Nonnull - public TurtleSide getSide() - { - return side; - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java deleted file mode 100644 index ca757dd7d..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; - -import javax.annotation.Nonnull; -import java.util.Map; -import java.util.Objects; - -/** - * A general event for when a turtle interacts with a block or region. - * - * You should generally listen to one of the sub-events instead, cancelling them where appropriate. - * - * Note that you are not guaranteed to receive this event, if it has been cancelled by other mechanisms, such as block protection systems. - * - * Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact with a block, simply objects within that block space. - */ -public abstract class TurtleBlockEvent extends TurtlePlayerEvent -{ - private final Level world; - private final BlockPos pos; - - protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, - @Nonnull BlockPos pos ) - { - super( turtle, action, player ); - - Objects.requireNonNull( world, "world cannot be null" ); - Objects.requireNonNull( pos, "pos cannot be null" ); - this.world = world; - this.pos = pos; - } - - /** - * Get the world the turtle is interacting in. - * - * @return The world the turtle is interacting in. - */ - public Level getWorld() - { - return world; - } - - /** - * Get the position the turtle is interacting with. Note that this is different to {@link ITurtleAccess#getPosition()}. - * - * @return The position the turtle is interacting with. - */ - public BlockPos getPos() - { - return pos; - } - - /** - * Fired when a turtle attempts to dig a block. - * - * @see TurtleAction#DIG - */ - public static class Dig extends TurtleBlockEvent - { - private final BlockState block; - private final ITurtleUpgrade upgrade; - private final TurtleSide side; - - public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState block, - @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side ) - { - super( turtle, TurtleAction.DIG, player, world, pos ); - - Objects.requireNonNull( block, "block cannot be null" ); - Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - Objects.requireNonNull( side, "side cannot be null" ); - this.block = block; - this.upgrade = upgrade; - this.side = side; - } - - /** - * Get the block which is about to be broken. - * - * @return The block which is going to be broken. - */ - @Nonnull - public BlockState getBlock() - { - return block; - } - - /** - * Get the upgrade doing the digging. - * - * @return The upgrade doing the digging. - */ - @Nonnull - public ITurtleUpgrade getUpgrade() - { - return upgrade; - } - - /** - * Get the side the upgrade doing the digging is on. - * - * @return The upgrade's side. - */ - @Nonnull - public TurtleSide getSide() - { - return side; - } - } - - /** - * Fired when a turtle attempts to move into a block. - * - * @see TurtleAction#MOVE - */ - public static class Move extends TurtleBlockEvent - { - public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos ) - { - super( turtle, TurtleAction.MOVE, player, world, pos ); - } - } - - /** - * Fired when a turtle attempts to place a block in the world. - * - * @see TurtleAction#PLACE - */ - public static class Place extends TurtleBlockEvent - { - private final ItemStack stack; - - public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull ItemStack stack ) - { - super( turtle, TurtleAction.PLACE, player, world, pos ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - this.stack = stack; - } - - /** - * Get the item stack that will be placed. This should not be modified. - * - * @return The item stack to be placed. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - } - - /** - * Fired when a turtle gathers data on a block in world. - * - * You may prevent blocks being inspected, or add additional information to the result. - * - * @see TurtleAction#INSPECT - */ - public static class Inspect extends TurtleBlockEvent - { - private final BlockState state; - private final Map data; - - public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, - @Nonnull Map data ) - { - super( turtle, TurtleAction.INSPECT, player, world, pos ); - - Objects.requireNonNull( state, "state cannot be null" ); - Objects.requireNonNull( data, "data cannot be null" ); - this.data = data; - this.state = state; - } - - /** - * Get the block state which is being inspected. - * - * @return The inspected block state. - */ - @Nonnull - public BlockState getState() - { - return state; - } - - /** - * Get the "inspection data" from this block, which will be returned to the user. - * - * @return This block's inspection data. - */ - @Nonnull - public Map getData() - { - return data; - } - - /** - * Add new information to the inspection result. Note this will override fields with the same name. - * - * @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}). - */ - public void addData( @Nonnull Map newData ) - { - Objects.requireNonNull( newData, "newData cannot be null" ); - data.putAll( newData ); - } - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java index 726a059ae..6557efc12 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import com.google.common.eventbus.EventBus; @@ -13,12 +12,10 @@ import javax.annotation.Nonnull; import java.util.Objects; /** - * A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, so sever specific methods on {@link - * ITurtleAccess} are safe to use. + * A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, + * so sever specific methods on {@link ITurtleAccess} are safe to use. * * You should generally not need to subscribe to this event, preferring one of the more specific classes. - * - * @see TurtleActionEvent */ public abstract class TurtleEvent { @@ -32,12 +29,6 @@ public abstract class TurtleEvent this.turtle = turtle; } - public static boolean post( TurtleActionEvent event ) - { - EVENT_BUS.post( event ); - return event.isCancelled(); - } - /** * Get the turtle which is performing this action. * @@ -48,5 +39,4 @@ public abstract class TurtleEvent { return turtle; } - } diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java deleted file mode 100644 index 14a5e20aa..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.Nonnull; -import java.util.Map; -import java.util.Objects; - -/** - * Fired when a turtle gathers data on an item in its inventory. - * - * You may prevent items being inspected, or add additional information to the result. Be aware that this may be fired on the computer thread, and so any - * operations on it must be thread safe. - * - * @see TurtleAction#INSPECT_ITEM - */ -public class TurtleInspectItemEvent extends TurtleActionEvent -{ - private final ItemStack stack; - private final Map data; - private final boolean mainThread; - - @Deprecated - public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map data ) - { - this( turtle, stack, data, false ); - } - - public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map data, boolean mainThread ) - { - super( turtle, TurtleAction.INSPECT_ITEM ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - Objects.requireNonNull( data, "data cannot be null" ); - this.stack = stack; - this.data = data; - this.mainThread = mainThread; - } - - /** - * The item which is currently being inspected. - * - * @return The item stack which is being inspected. This should not be modified. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - - /** - * Get the "inspection data" from this item, which will be returned to the user. - * - * @return This items's inspection data. - */ - @Nonnull - public Map getData() - { - return data; - } - - /** - * If this event is being fired on the server thread. When true, information which relies on server state may be exposed. - * - * @return If this is run on the main thread. - */ - public boolean onMainThread() - { - return mainThread; - } - - /** - * Add new information to the inspection result. Note this will override fields with the same name. - * - * @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}). - */ - public void addData( @Nonnull Map newData ) - { - Objects.requireNonNull( newData, "newData cannot be null" ); - data.putAll( newData ); - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java deleted file mode 100644 index 83033a513..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.core.BlockPos; -import net.minecraft.world.Container; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - -/** - * Fired when a turtle attempts to interact with an inventory. - */ -public abstract class TurtleInventoryEvent extends TurtleBlockEvent -{ - private final Container handler; - - protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, - @Nonnull BlockPos pos, @Nullable Container handler ) - { - super( turtle, action, player, world, pos ); - this.handler = handler; - } - - /** - * Get the inventory being interacted with. - * - * @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world. - */ - @Nullable - public Container getItemHandler() - { - return handler; - } - - /** - * Fired when a turtle attempts to suck from an inventory. - * - * @see TurtleAction#SUCK - */ - public static class Suck extends TurtleInventoryEvent - { - public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler ) - { - super( turtle, TurtleAction.SUCK, player, world, pos, handler ); - } - } - - /** - * Fired when a turtle attempts to drop an item into an inventory. - * - * @see TurtleAction#DROP - */ - public static class Drop extends TurtleInventoryEvent - { - private final ItemStack stack; - - public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler, - @Nonnull ItemStack stack ) - { - super( turtle, TurtleAction.DROP, player, world, pos, handler ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - this.stack = stack; - } - - /** - * The item which will be inserted into the inventory/dropped on the ground. - * - * @return The item stack which will be dropped. This should not be modified. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java deleted file mode 100644 index 463a6602c..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ - -package dan200.computercraft.api.turtle.event; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * An action done by a turtle which is normally done by a player. - * - * {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks. - */ -public abstract class TurtlePlayerEvent extends TurtleActionEvent -{ - private final FakePlayer player; - - protected TurtlePlayerEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player ) - { - super( turtle, action ); - - Objects.requireNonNull( player, "player cannot be null" ); - this.player = player; - } - - /** - * A fake player, representing this turtle. - * - * This may be used for triggering permission checks. - * - * @return A {@link FakePlayer} representing this turtle. - */ - @Nonnull - public FakePlayer getPlayer() - { - return player; - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index 47327afee..ec7f41244 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; @@ -16,17 +15,16 @@ import java.util.Objects; /** * Fired when a turtle attempts to refuel from an item. * - * One may use {@link #setCanceled(boolean, String)} to prevent refueling from this specific item. Additionally, you may use {@link #setHandler(Handler)} to - * register a custom fuel provider. + * One may use {@link #setHandler(Handler)} to register a custom fuel provider for a given item. */ -public class TurtleRefuelEvent extends TurtleActionEvent +public class TurtleRefuelEvent extends TurtleEvent { private final ItemStack stack; private Handler handler; public TurtleRefuelEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack ) { - super( turtle, TurtleAction.REFUEL ); + super( turtle ); Objects.requireNonNull( turtle, "turtle cannot be null" ); this.stack = stack; @@ -59,7 +57,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent /** * Set the refuel handler for this stack. * - * You should call this if you can actually refuel from this item, and ideally only if there are no existing handlers. + * You should call this if you can actually refuel from this item, and ideally only if there are no existing + * handlers. * * @param handler The new refuel handler. * @see #getHandler() @@ -81,7 +80,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent * @param turtle The turtle to refuel. * @param stack The stack to refuel with. * @param slot The slot the stack resides within. This may be used to modify the inventory afterwards. - * @param limit The maximum number of refuel operations to perform. This will often correspond to the number of items to consume. + * @param limit The maximum number of refuel operations to perform. This will often correspond to the number of + * items to consume. * @return The amount of fuel gained. */ int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, int slot, int limit ); diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 77203c656..fdf68c141 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -35,6 +35,7 @@ public abstract class ComputerAccess implements IComputerAccess { ComputerCraft.log.warn( "Peripheral or API called mount but did not call unmount for {}", mounts ); } + for( String mount : mounts ) { fileSystem.unmount( mount ); diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 6d1e5f2f6..9e1059545 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -68,6 +68,13 @@ public class FSAPI implements ILuaAPI * @param path The path to list. * @return A table with a list of files in the directory. * @throws LuaException If the path doesn't exist. + * @cc.usage List all files under {@code /rom/} + *
    {@code
    +     * local files = fs.list("/rom/")
    +     * for i = 1, #files do
    +     *   print(files[i])
    +     * end
    +     * }
    */ @LuaFunction public final String[] list( String path ) throws LuaException @@ -92,6 +99,12 @@ public class FSAPI implements ILuaAPI * @throws LuaException On argument errors. * @cc.tparam string path The first part of the path. For example, a parent directory path. * @cc.tparam string ... Additional parts of the path to combine. + * @cc.changed 1.95.0 Now supports multiple arguments. + * @cc.usage Combine several file paths together + *
    {@code
    +     * fs.combine("/rom/programs", "../apis", "parallel.lua")
    +     * -- => rom/apis/parallel.lua
    +     * }
    */ @LuaFunction public final String combine( IArguments arguments ) throws LuaException @@ -114,6 +127,12 @@ public class FSAPI implements ILuaAPI * * @param path The path to get the name from. * @return The final part of the path (the file name). + * @cc.since 1.2 + * @cc.usage Get the file name of {@code rom/startup.lua} + *
    {@code
    +     * fs.getName("rom/startup.lua")
    +     * -- => startup.lua
    +     * }
    */ @LuaFunction public final String getName( String path ) @@ -126,6 +145,12 @@ public class FSAPI implements ILuaAPI * * @param path The path to get the directory from. * @return The path with the final part removed (the parent directory). + * @cc.since 1.63 + * @cc.usage Get the directory name of {@code rom/startup.lua} + *
    {@code
    +     * fs.getDir("rom/startup.lua")
    +     * -- => rom
    +     * }
    */ @LuaFunction public final String getDir( String path ) @@ -139,6 +164,7 @@ public class FSAPI implements ILuaAPI * @param path The file to get the file size of. * @return The size of the file, in bytes. * @throws LuaException If the path doesn't exist. + * @cc.since 1.3 */ @LuaFunction public final long getSize( String path ) throws LuaException @@ -304,10 +330,15 @@ public class FSAPI implements ILuaAPI /** * Opens a file for reading or writing at a path. * - * The mode parameter can be {@code r} to read, {@code w} to write (deleting - * all contents), or {@code a} to append (keeping contents). If {@code b} is - * added to the end, the file will be opened in binary mode; otherwise, it's - * opened in text mode. + * The {@code mode} string can be any of the following: + *
      + *
    • "r": Read mode
    • + *
    • "w": Write mode
    • + *
    • "a": Append mode
    • + *
    + * + * The mode may also have a "b" at the end, which opens the file in "binary + * mode". This allows you to read binary files, as well as seek within a file. * * @param path The path to the file to open. * @param mode The mode to open the file with. @@ -316,6 +347,37 @@ public class FSAPI implements ILuaAPI * @cc.treturn [1] table A file handle object for the file. * @cc.treturn [2] nil If the file does not exist, or cannot be opened. * @cc.treturn string|nil A message explaining why the file cannot be opened. + * @cc.usage Read the contents of a file. + *
    {@code
    +     * local file = fs.open("/rom/help/intro.txt", "r")
    +     * local contents = file.readAll()
    +     * file.close()
    +     *
    +     * print(contents)
    +     * }
    + * @cc.usage Open a file and read all lines into a table. @{io.lines} offers an alternative way to do this. + *
    {@code
    +     * local file = fs.open("/rom/motd.txt", "r")
    +     * local lines = {}
    +     * while true do
    +     *   local line = file.readLine()
    +     *
    +     *   -- If line is nil then we've reached the end of the file and should stop
    +     *   if not line then break end
    +     *
    +     *   lines[#lines + 1] = line
    +     * end
    +     *
    +     * file.close()
    +     *
    +     * print(lines[math.random(#lines)]) -- Pick a random line and print it.
    +     * }
    + * @cc.usage Open a file and write some text to it. You can run {@code edit out.txt} to see the written text. + *
    {@code
    +     * local file = fs.open("out.txt", "w")
    +     * file.write("Just testing some code")
    +     * file.close() -- Remember to call close, otherwise changes may not be written!
    +     * }
    */ @LuaFunction public final Object[] open( String path, String mode ) throws LuaException @@ -344,9 +406,11 @@ public class FSAPI implements ILuaAPI return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; } case "rb": + { // Open the file for binary reading, then create a wrapper around the reader FileSystemWrapper reader = fileSystem.openForRead( path, Function.identity() ); return new Object[] { BinaryReadableHandle.of( reader.get(), reader ) }; + } case "wb": { // Open the file for binary writing, then create a wrapper around the writer @@ -354,9 +418,11 @@ public class FSAPI implements ILuaAPI return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; } case "ab": + { // Open the file for binary appending, then create a wrapper around the reader FileSystemWrapper writer = fileSystem.openForWrite( path, true, Function.identity() ); return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; + } default: throw new LuaException( "Unsupported mode" ); } @@ -396,6 +462,8 @@ public class FSAPI implements ILuaAPI * @return The amount of free space available, in bytes. * @throws LuaException If the path doesn't exist. * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". + * @cc.since 1.4 + * @see #getCapacity To get the capacity of this drive. */ @LuaFunction public final Object getFreeSpace( String path ) throws LuaException @@ -422,6 +490,7 @@ public class FSAPI implements ILuaAPI * @param path The wildcard-qualified path to search for. * @return A list of paths that match the search string. * @throws LuaException If the path doesn't exist. + * @cc.since 1.6 */ @LuaFunction public final String[] find( String path ) throws LuaException @@ -438,17 +507,15 @@ public class FSAPI implements ILuaAPI } /** - * Returns true if a path is mounted to the parent filesystem. - * - * The root filesystem "/" is considered a mount, along with disk folders and the rom folder. Other programs - * (such as network shares) can extend this to make other mount types by correctly assigning their return value for - * getDrive. + * Returns the capacity of the drive the path is located on. * * @param path The path of the drive to get. * @return The drive's capacity. * @throws LuaException If the capacity cannot be determined. * @cc.treturn number|nil This drive's capacity. This will be nil for "read-only" drives, such as the ROM or * treasure disks. + * @cc.since 1.87.0 + * @see #getFreeSpace To get the free space available on this drive. */ @LuaFunction public final Object getCapacity( String path ) throws LuaException @@ -477,6 +544,9 @@ public class FSAPI implements ILuaAPI * @return The resulting attributes. * @throws LuaException If the path does not exist. * @cc.treturn { size = number, isDir = boolean, isReadOnly = boolean, created = number, modified = number } The resulting attributes. + * @cc.since 1.87.0 + * @cc.changed 1.91.0 Renamed `modification` field to `modified`. + * @cc.changed 1.95.2 Added `isReadOnly` to attributes. * @see #getSize If you only care about the file's size. * @see #isDir If you only care whether a path is a directory or not. */ diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 0ef4899bc..3140326d7 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -204,14 +204,15 @@ public class OSAPI implements ILuaAPI } /** - * Sets an alarm that will fire at the specified world time. When it fires, - * an {@code alarm} event will be added to the event queue with the ID - * returned from this function as the first parameter. + * Sets an alarm that will fire at the specified in-game time. When it + * fires, * an {@code alarm} event will be added to the event queue with the + * ID * returned from this function as the first parameter. * * @param time The time at which to fire the alarm, in the range [0.0, 24.0). * @return The ID of the new alarm. This can be used to filter the * {@code alarm} event, or {@link #cancelAlarm cancel the alarm}. * @throws LuaException If the time is out of range. + * @cc.since 1.2 * @see #cancelAlarm To cancel an alarm. */ @LuaFunction @@ -232,6 +233,7 @@ public class OSAPI implements ILuaAPI * alarm from firing. * * @param token The ID of the alarm to cancel. + * @cc.since 1.2 * @see #setAlarm To set an alarm. */ @LuaFunction @@ -277,6 +279,7 @@ public class OSAPI implements ILuaAPI * * @return The label of the computer. * @cc.treturn string The label of the computer. + * @cc.since 1.3 */ @LuaFunction( { "getComputerLabel", "computerLabel" } ) public final Object[] getComputerLabel() @@ -289,6 +292,7 @@ public class OSAPI implements ILuaAPI * Set the label of this computer. * * @param label The new label. May be {@code nil} in order to clear it. + * @cc.since 1.3 */ @LuaFunction public final void setComputerLabel( Optional label ) @@ -300,6 +304,7 @@ public class OSAPI implements ILuaAPI * Returns the number of seconds that the computer has been running. * * @return The computer's uptime. + * @cc.since 1.2 */ @LuaFunction public final double clock() @@ -311,7 +316,7 @@ public class OSAPI implements ILuaAPI * Returns the current time depending on the string passed in. This will * always be in the range [0.0, 24.0). * - * * If called with {@code ingame}, the current world time will be returned. + * * If called with {@code dan200.computercraft.ingame}, the current world time will be returned. * This is the default if nothing is passed. * * If called with {@code utc}, returns the hour of the day in UTC time. * * If called with {@code local}, returns the hour of the day in the @@ -321,10 +326,19 @@ public class OSAPI implements ILuaAPI * which will convert the date fields into a UNIX timestamp (number of * seconds since 1 January 1970). * - * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. + * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code dan200.computercraft.ingame} locale if not specified. * @return The hour of the selected locale, or a UNIX timestamp from the table, depending on the argument passed in. * @throws LuaException If an invalid locale is passed. - * @cc.tparam [opt] string|table locale The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. + * @cc.tparam [opt] string|table locale The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code dan200.computercraft.ingame} locale if not specified. + * @cc.see textutils.formatTime To convert times into a user-readable string. + * @cc.usage Print the current in-game time. + *
    {@code
    +     * textutils.formatTime(os.time())
    +     * }
    + * @cc.since 1.2 + * @cc.changed 1.80pr1 Add support for getting the local local and UTC time. + * @cc.changed 1.82.0 Arguments are now case insensitive. + * @cc.changed 1.83.0 {@link #time(IArguments)} now accepts table arguments and converts them to UNIX timestamps. * @see #date To get a date table that can be converted with this function. */ @LuaFunction @@ -333,14 +347,14 @@ public class OSAPI implements ILuaAPI Object value = args.get( 0 ); if( value instanceof Map ) return LuaDateTime.fromTable( (Map) value ); - String param = args.optString( 0, "ingame" ); + String param = args.optString( 0, "dan200.computercraft.ingame" ); switch( param.toLowerCase( Locale.ROOT ) ) { case "utc": // Get Hour of day (UTC) return getTimeForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); case "local": // Get Hour of day (local time) return getTimeForCalendar( Calendar.getInstance() ); - case "ingame": // Get in-game hour + case "dan200.computercraft.ingame": // Get in-game hour return time; default: throw new LuaException( "Unsupported operation" ); @@ -350,27 +364,29 @@ public class OSAPI implements ILuaAPI /** * Returns the day depending on the locale specified. * - * * If called with {@code ingame}, returns the number of days since the + * * If called with {@code dan200.computercraft.ingame}, returns the number of days since the * world was created. This is the default. * * If called with {@code utc}, returns the number of days since 1 January * 1970 in the UTC timezone. * * If called with {@code local}, returns the number of days since 1 * January 1970 in the server's local timezone. * - * @param args The locale to get the day for. Defaults to {@code ingame} if not set. + * @param args The locale to get the day for. Defaults to {@code dan200.computercraft.ingame} if not set. * @return The day depending on the selected locale. * @throws LuaException If an invalid locale is passed. + * @cc.since 1.48 + * @cc.changed 1.82.0 Arguments are now case insensitive. */ @LuaFunction public final int day( Optional args ) throws LuaException { - switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + switch( args.orElse( "dan200.computercraft.ingame" ).toLowerCase( Locale.ROOT ) ) { case "utc": // Get numbers of days since 1970-01-01 (utc) return getDayForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); case "local": // Get numbers of days since 1970-01-01 (local time) return getDayForCalendar( Calendar.getInstance() ); - case "ingame":// Get game day + case "dan200.computercraft.ingame":// Get game day return day; default: throw new LuaException( "Unsupported operation" ); @@ -380,21 +396,29 @@ public class OSAPI implements ILuaAPI /** * Returns the number of milliseconds since an epoch depending on the locale. * - * * If called with {@code ingame}, returns the number of milliseconds since the + * * If called with {@code dan200.computercraft.ingame}, returns the number of milliseconds since the * world was created. This is the default. * * If called with {@code utc}, returns the number of milliseconds since 1 * January 1970 in the UTC timezone. * * If called with {@code local}, returns the number of milliseconds since 1 * January 1970 in the server's local timezone. * - * @param args The locale to get the milliseconds for. Defaults to {@code ingame} if not set. + * @param args The locale to get the milliseconds for. Defaults to {@code dan200.computercraft.ingame} if not set. * @return The milliseconds since the epoch depending on the selected locale. * @throws LuaException If an invalid locale is passed. + * @cc.since 1.80pr1 + * @cc.usage Get the current time and use {@link #date} to convert it to a table. + *
    {@code
    +     * -- Dividing by 1000 converts it from milliseconds to seconds.
    +     * local time = os.epoch("local") / 1000
    +     * local time_table = os.date("*t", time)
    +     * print(textutils.serialize(time_table))
    +     * }
    */ @LuaFunction public final long epoch( Optional args ) throws LuaException { - switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + switch( args.orElse( "dan200.computercraft.ingame" ).toLowerCase( Locale.ROOT ) ) { case "utc": { @@ -403,10 +427,12 @@ public class OSAPI implements ILuaAPI return getEpochForCalendar( c ); } case "local": + { // Get local epoch Calendar c = Calendar.getInstance(); return getEpochForCalendar( c ); - case "ingame": + } + case "dan200.computercraft.ingame": // Get in-game epoch synchronized( alarms ) { @@ -436,6 +462,11 @@ public class OSAPI implements ILuaAPI * @param timeA The time to convert to a string. This defaults to the current time. * @return The resulting format string. * @throws LuaException If an invalid format is passed. + * @cc.since 1.83.0 + * @cc.usage Print the current date in a user-friendly string. + *
    {@code
    +     * os.date("%A %d %B %Y") -- See the reference above!
    +     * }
    */ @LuaFunction public final Object date( Optional formatA, Optional timeA ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 186199302..3fc1285d4 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -30,15 +30,15 @@ import dan200.computercraft.core.computer.ComputerSide; * * @cc.usage Toggle the redstone signal above the computer every 0.5 seconds. * - *
    + * 
    {@code
      * while true do
      *   redstone.setOutput("top", not redstone.getOutput("top"))
      *   sleep(0.5)
      * end
    - * 
    + * }
    * @cc.usage Mimic a redstone comparator in [subtraction mode][comparator]. * - *
    + * 
    {@code
      * while true do
      *   local rear = rs.getAnalogueInput("back")
      *   local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right"))
    @@ -46,7 +46,7 @@ import dan200.computercraft.core.computer.ComputerSide;
      *
      *   os.pullEvent("redstone") -- Wait for a change to inputs.
      * end
    - * 
    + * }
    * * [comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on * the Minecraft wiki." @@ -72,6 +72,7 @@ public class RedstoneAPI implements ILuaAPI * "back". * * @return A table of valid sides. + * @cc.since 1.2 */ @LuaFunction public final String[] getSides() @@ -122,6 +123,7 @@ public class RedstoneAPI implements ILuaAPI * @param side The side to set. * @param value The signal strength between 0 and 15. * @throws LuaException If {@code value} is not betwene 0 and 15. + * @cc.since 1.51 */ @LuaFunction( { "setAnalogOutput", "setAnalogueOutput" } ) public final void setAnalogOutput( ComputerSide side, int value ) throws LuaException @@ -135,6 +137,7 @@ public class RedstoneAPI implements ILuaAPI * * @param side The side to get. * @return The output signal strength, between 0 and 15. + * @cc.since 1.51 * @see #setAnalogOutput */ @LuaFunction( { "getAnalogOutput", "getAnalogueOutput" } ) @@ -148,6 +151,7 @@ public class RedstoneAPI implements ILuaAPI * * @param side The side to get. * @return The input signal strength, between 0 and 15. + * @cc.since 1.51 */ @LuaFunction( { "getAnalogInput", "getAnalogueInput" } ) public final int getAnalogInput( ComputerSide side ) @@ -201,9 +205,9 @@ public class RedstoneAPI implements ILuaAPI * @param mask The mask to test. * @return If the colours are on. * @cc.usage Check if @{colors.white} and @{colors.black} are on above the computer. - *
    +     * 
    {@code
          * print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
    -     * 
    + * }
    * @see #getBundledInput */ @LuaFunction diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 6b1816096..d0fa42ff1 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -46,6 +46,7 @@ public class TermAPI extends TermMethods implements ILuaAPI * @cc.treturn number The red channel, will be between 0 and 1. * @cc.treturn number The green channel, will be between 0 and 1. * @cc.treturn number The blue channel, will be between 0 and 1. + * @cc.since 1.81.0 * @see TermMethods#setPaletteColour(IArguments) To change the palette colour. */ @LuaFunction( { "nativePaletteColour", "nativePaletteColor" } ) diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java index ce5545124..420c8fc95 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -112,6 +112,7 @@ public abstract class TermMethods * * @return If the cursor is blinking. * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.80pr1.9 */ @LuaFunction public final boolean getCursorBlink() throws LuaException @@ -179,6 +180,7 @@ public abstract class TermMethods * @return The current text colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants, returned by this function. + * @cc.since 1.74 */ @LuaFunction( { "getTextColour", "getTextColor" } ) public final int getTextColour() throws LuaException @@ -192,6 +194,8 @@ public abstract class TermMethods * @param colourArg The new text colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. */ @LuaFunction( { "setTextColour", "setTextColor" } ) public final void setTextColour( int colourArg ) throws LuaException @@ -211,6 +215,7 @@ public abstract class TermMethods * @return The current background colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants, returned by this function. + * @cc.since 1.74 */ @LuaFunction( { "getBackgroundColour", "getBackgroundColor" } ) public final int getBackgroundColour() throws LuaException @@ -225,6 +230,8 @@ public abstract class TermMethods * @param colourArg The new background colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. */ @LuaFunction( { "setBackgroundColour", "setBackgroundColor" } ) public final void setBackgroundColour( int colourArg ) throws LuaException @@ -245,6 +252,7 @@ public abstract class TermMethods * * @return Whether this terminal supports colour. * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.45 */ @LuaFunction( { "isColour", "isColor" } ) public final boolean getIsColour() throws LuaException @@ -267,6 +275,8 @@ public abstract class TermMethods * @param backgroundColour The corresponding background colours. * @throws LuaException If the three inputs are not the same length. * @cc.see colors For a list of colour constants, and their hexadecimal values. + * @cc.since 1.74 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. * @cc.usage Prints "Hello, world!" in rainbow text. *
    {@code
          * term.blit("Hello, world!","01234456789ab","0000000000000")
    @@ -319,6 +329,7 @@ public abstract class TermMethods
          * }
    * @cc.see colors.unpackRGB To convert from the 24-bit format to three separate channels. * @cc.see colors.packRGB To convert from three separate channels to the 24-bit format. + * @cc.since 1.80pr1 */ @LuaFunction( { "setPaletteColour", "setPaletteColor" } ) public final void setPaletteColour( IArguments args ) throws LuaException @@ -348,6 +359,7 @@ public abstract class TermMethods * @cc.treturn number The red channel, will be between 0 and 1. * @cc.treturn number The green channel, will be between 0 and 1. * @cc.treturn number The blue channel, will be between 0 and 1. + * @cc.since 1.80pr1 */ @LuaFunction( { "getPaletteColour", "getPaletteColor" } ) public final Object[] getPaletteColour( int colourArg ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index 4477dde92..b026aa750 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -61,6 +61,7 @@ public class BinaryReadableHandle extends HandleGeneric * @cc.treturn [1] nil If we are at the end of the file. * @cc.treturn [2] number The value of the byte read. This is returned when the {@code count} is absent. * @cc.treturn [3] string The bytes read as a string. This is returned when the {@code count} is given. + * @cc.changed 1.80pr1 Now accepts an integer argument to read multiple bytes, returning a string instead of a number. */ @LuaFunction public final Object[] read( Optional countArg ) throws LuaException @@ -145,6 +146,7 @@ public class BinaryReadableHandle extends HandleGeneric * @return The file, or {@code null} if at the end of it. * @throws LuaException If the file has been closed. * @cc.treturn string|nil The remaining contents of the file, or {@code nil} if we are at the end. + * @cc.since 1.80pr1 */ @LuaFunction public final Object[] readAll() throws LuaException @@ -182,6 +184,8 @@ public class BinaryReadableHandle extends HandleGeneric * @return The read string. * @throws LuaException If the file has been closed. * @cc.treturn string|nil The read line or {@code nil} if at the end of the file. + * @cc.since 1.80pr1.9 + * @cc.changed 1.81.0 `\r` is now stripped. */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException @@ -259,6 +263,7 @@ public class BinaryReadableHandle extends HandleGeneric * @cc.treturn [1] number The new position. * @cc.treturn [2] nil If seeking failed. * @cc.treturn string The reason seeking failed. + * @cc.since 1.80pr1.9 */ @LuaFunction public final Object[] seek( Optional whence, Optional offset ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index 796582855..39e234648 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -55,6 +55,7 @@ public class BinaryWritableHandle extends HandleGeneric * @throws LuaException If the file has been closed. * @cc.tparam [1] number The byte to write. * @cc.tparam [2] string The string to write. + * @cc.changed 1.80pr1 Now accepts a string to write multiple bytes. */ @LuaFunction public final void write( IArguments arguments ) throws LuaException @@ -130,6 +131,7 @@ public class BinaryWritableHandle extends HandleGeneric * @cc.treturn [1] number The new position. * @cc.treturn [2] nil If seeking failed. * @cc.treturn string The reason seeking failed. + * @cc.since 1.80pr1.9 */ @LuaFunction public final Object[] seek( Optional whence, Optional offset ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 28576f70d..27e1b7083 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -50,6 +50,7 @@ public class EncodedReadableHandle extends HandleGeneric * @return The read string. * @throws LuaException If the file has been closed. * @cc.treturn string|nil The read line or {@code nil} if at the end of the file. + * @cc.changed 1.81.0 Added option to return trailing newline. */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException @@ -116,6 +117,7 @@ public class EncodedReadableHandle extends HandleGeneric * @throws LuaException When trying to read a negative number of characters. * @throws LuaException If the file has been closed. * @cc.treturn string|nil The read characters, or {@code nil} if at the of the file. + * @cc.since 1.80pr1.4 */ @LuaFunction public final Object[] read( Optional countA ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index ffd895b0b..d5b1b18f2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -201,7 +201,7 @@ public final class NetworkUtils { return "Timed out"; } - else if( cause instanceof SSLHandshakeException || cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException ) + else if( cause instanceof SSLHandshakeException || (cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException) ) { return "Could not create a secure connection"; } diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java index 13365b453..955e89d4d 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java @@ -75,7 +75,7 @@ public final class AddressRule if( this.port != null && this.port != port ) return false; return predicate.matches( domain ) || predicate.matches( address ) - || ipv4Address != null && predicate.matches( ipv4Address ); + || (ipv4Address != null && predicate.matches( ipv4Address )); } public static Options apply( Iterable rules, String domain, InetSocketAddress socketAddress ) diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index c5d72134b..4dcd82c9b 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -46,6 +46,7 @@ public class HttpResponseHandle implements ObjectSource * @return The response code and message. * @cc.treturn number The response code (i.e. 200) * @cc.treturn string The response message (i.e. "OK") + * @cc.changed 1.80pr1.13 Added response message return value. */ @LuaFunction public final Object[] getResponseCode() diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index 0c74c0c9f..0901cc25e 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -55,6 +55,8 @@ public class WebsocketHandle implements Closeable * @cc.treturn [1] string The received message. * @cc.treturn boolean If this was a binary message. * @cc.treturn [2] nil If the websocket was closed while waiting, or if we timed out. + * @cc.changed 1.80pr1.13 Added return value indicating whether the message was binary. + * @cc.changed 1.87.0 Added timeout argument. */ @LuaFunction public final MethodResult receive( Optional timeout ) throws LuaException @@ -74,6 +76,7 @@ public class WebsocketHandle implements Closeable * @param binary Whether this message should be treated as a * @throws LuaException If the message is too large. * @throws LuaException If the websocket has been closed. + * @cc.changed 1.81.0 Added argument for binary mode. */ @LuaFunction public final void send( Object message, Optional binary ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index e68732f95..4cd2d66cf 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -15,6 +15,7 @@ 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 dan200.computercraft.api.peripheral.PeripheralType; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; @@ -108,7 +109,7 @@ public final class Generator if( instance == null ) continue; if( methods == null ) methods = new ArrayList<>(); - addMethod( methods, method, annotation, instance ); + addMethod( methods, method, annotation, null, instance ); } for( GenericMethod method : GenericMethod.all() ) @@ -119,7 +120,7 @@ public final class Generator if( instance == null ) continue; if( methods == null ) methods = new ArrayList<>(); - addMethod( methods, method.method, method.annotation, instance ); + addMethod( methods, method.method, method.annotation, method.peripheralType, instance ); } if( methods == null ) return Collections.emptyList(); @@ -127,7 +128,7 @@ public final class Generator return Collections.unmodifiableList( methods ); } - private void addMethod( List> methods, Method method, LuaFunction annotation, T instance ) + private void addMethod( List> methods, Method method, LuaFunction annotation, PeripheralType genericType, T instance ) { if( annotation.mainThread() ) instance = wrap.apply( instance ); @@ -135,13 +136,13 @@ public final class Generator boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); if( names.length == 0 ) { - methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); + methods.add( new NamedMethod<>( method.getName(), instance, isSimple, genericType ) ); } else { for( String name : names ) { - methods.add( new NamedMethod<>( name, instance, isSimple ) ); + methods.add( new NamedMethod<>( name, instance, isSimple, genericType ) ); } } } diff --git a/src/main/java/dan200/computercraft/core/asm/GenericMethod.java b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java index e0c916c2e..691d9b742 100644 --- a/src/main/java/dan200/computercraft/core/asm/GenericMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java @@ -8,6 +8,8 @@ package dan200.computercraft.core.asm; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.GenericPeripheral; +import dan200.computercraft.api.peripheral.PeripheralType; import javax.annotation.Nonnull; import java.lang.reflect.Method; @@ -18,6 +20,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A generic method is a method belonging to a {@link GenericSource} with a known target. @@ -27,15 +30,17 @@ public class GenericMethod final Method method; final LuaFunction annotation; final Class target; + final PeripheralType peripheralType; private static final List sources = new ArrayList<>(); private static List cache; - GenericMethod( Method method, LuaFunction annotation, Class target ) + GenericMethod( Method method, LuaFunction annotation, Class target, PeripheralType peripheralType ) { this.method = method; this.annotation = annotation; this.target = target; + this.peripheralType = peripheralType; } /** @@ -46,10 +51,28 @@ public class GenericMethod static List all() { if( cache != null ) return cache; - return cache = sources.stream() - .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) - .map( method -> - { + return cache = sources.stream().flatMap( GenericMethod::getMethods ).collect( Collectors.toList() ); + } + + public static synchronized void register( @Nonnull GenericSource source ) + { + Objects.requireNonNull( source, "Source cannot be null" ); + + if( cache != null ) + { + ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); + } + + sources.add( source ); + } + + private static Stream getMethods( GenericSource source ) + { + Class klass = source.getClass(); + PeripheralType type = source instanceof GenericPeripheral ? ((GenericPeripheral) source).getType() : null; + + return Arrays.stream( klass.getDeclaredMethods() ) + .map( method -> { LuaFunction annotation = method.getAnnotation( LuaFunction.class ); if( annotation == null ) return null; @@ -69,22 +92,8 @@ public class GenericMethod Class target = Reflect.getRawType( method, types[0], false ); if( target == null ) return null; - return new GenericMethod( method, annotation, target ); + return new GenericMethod( method, annotation, target, type ); } ) - .filter( Objects::nonNull ) - .collect( Collectors.toList() ); - } - - - public static synchronized void register( @Nonnull GenericSource source ) - { - Objects.requireNonNull( source, "Source cannot be null" ); - - if( cache != null ) - { - ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); - } - - sources.add( source ); + .filter( Objects::nonNull ); } } diff --git a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java index b0562835c..281ab9c56 100644 --- a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java @@ -13,7 +13,7 @@ import java.util.Collections; public interface LuaMethod { Generator GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), - m -> ( target, context, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ) + m -> ( target, context, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, args ) ) ) ); IntCache DYNAMIC = new IntCache<>( diff --git a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java index ea72bb7a4..35d9c0a77 100644 --- a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java @@ -5,7 +5,10 @@ */ package dan200.computercraft.core.asm; +import dan200.computercraft.api.peripheral.PeripheralType; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class NamedMethod { @@ -13,11 +16,14 @@ public final class NamedMethod private final T method; private final boolean nonYielding; - NamedMethod( String name, T method, boolean nonYielding ) + private final PeripheralType genericType; + + NamedMethod( String name, T method, boolean nonYielding, PeripheralType genericType ) { this.name = name; this.method = method; this.nonYielding = nonYielding; + this.genericType = genericType; } @Nonnull @@ -36,4 +42,10 @@ public final class NamedMethod { return nonYielding; } + + @Nullable + public PeripheralType getGenericType() + { + return genericType; + } } diff --git a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java index 38618442f..146896b04 100644 --- a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java @@ -18,7 +18,7 @@ import java.util.Arrays; public interface PeripheralMethod { Generator GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), - m -> ( target, context, computer, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ) + m -> ( target, context, computer, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, computer, args ) ) ) ); IntCache DYNAMIC = new IntCache<>( diff --git a/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java b/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java new file mode 100644 index 000000000..7b9b464b2 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java @@ -0,0 +1,27 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.MethodResult; + +final class ResultHelpers +{ + private ResultHelpers() + { + } + + static Object[] checkNormalResult( MethodResult result ) + { + if( result.getCallback() != null ) + { + // Due to how tasks are implemented, we can't currently return a MethodResult. This is an + // entirely artificial limitation - we can remove it if it ever becomes an issue. + throw new IllegalStateException( "Must return MethodResult.of from mainThread function." ); + } + + return result.getResult(); + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index ecc8aea80..3931629f1 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -309,9 +309,9 @@ public final class Environment implements IAPIEnvironment { int index = side.ordinal(); IPeripheral existing = peripherals[index]; - if( existing == null && peripheral != null || - existing != null && peripheral == null || - existing != null && !existing.equals( peripheral ) ) + if( (existing == null && peripheral != null) || + (existing != null && peripheral == null) || + (existing != null && !existing.equals( peripheral )) ) { peripherals[index] = peripheral; if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral ); diff --git a/src/main/java/dan200/computercraft/core/computer/MainThread.java b/src/main/java/dan200/computercraft/core/computer/MainThread.java index 8f53541e2..1c77e3692 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThread.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThread.java @@ -93,7 +93,7 @@ public final class MainThread executor.updateTime(); // We're not currently on the queue, so update its current execution time to - // ensure its at least as high as the minimum. + // ensure it's at least as high as the minimum. long newRuntime = minimumTime; // Slow down new computers a little bit. diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 90566970e..d31757cda 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -7,7 +7,6 @@ package dan200.computercraft.core.filesystem; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.common.collect.MapMaker; import com.google.common.io.ByteStreams; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; @@ -15,10 +14,11 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.shared.util.IoUtil; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -27,7 +27,9 @@ import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; public final class ResourceMount implements IMount @@ -56,50 +58,37 @@ public final class ResourceMount implements IMount .weigher( ( k, v ) -> v.length ) .build(); - private static final MapMaker CACHE_TEMPLATE = new MapMaker().weakValues().concurrencyLevel( 1 ); - /** * Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes. */ - private static final Map> MOUNT_CACHE = new WeakHashMap<>( 2 ); + private static final Map MOUNT_CACHE = new HashMap<>( 2 ); private final String namespace; private final String subPath; - private final ReloadableResourceManager manager; + private ResourceManager manager; @Nullable private FileEntry root; - public static ResourceMount get( String namespace, String subPath, ReloadableResourceManager manager ) + public static ResourceMount get( String namespace, String subPath, ResourceManager manager ) { - Map cache; - + ResourceLocation path = new ResourceLocation( namespace, subPath ); synchronized( MOUNT_CACHE ) { - cache = MOUNT_CACHE.get( manager ); - if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() ); - } - - ResourceLocation path = new ResourceLocation( namespace, subPath ); - synchronized( cache ) - { - ResourceMount mount = cache.get( path ); - if( mount == null ) cache.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); + ResourceMount mount = MOUNT_CACHE.get( path ); + if( mount == null ) MOUNT_CACHE.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); return mount; } } - private ResourceMount( String namespace, String subPath, ReloadableResourceManager manager ) + private ResourceMount( String namespace, String subPath, ResourceManager manager ) { this.namespace = namespace; this.subPath = subPath; - this.manager = manager; - - Listener.INSTANCE.add( manager, this ); - if( root == null ) load(); + load( manager ); } - private void load() + private void load( ResourceManager manager ) { boolean hasAny = false; String existingNamespace = null; @@ -117,6 +106,7 @@ public final class ResourceMount implements IMount hasAny = true; } + this.manager = manager; root = hasAny ? newRoot : null; if( !hasAny ) @@ -292,28 +282,30 @@ public final class ResourceMount implements IMount } /** - * A {@link ResourceReloader} which reloads any associated mounts. - * - * While people should really be keeping a permanent reference to this, some people construct it every - * method call, so let's make this as small as possible. + * A {@link PreparableReloadListener} which reloads any associated mounts and correctly updates the resource manager + * they point to. */ - static class Listener implements ResourceManagerReloadListener + public static final SimplePreparableReloadListener RELOAD_LISTENER = new SimplePreparableReloadListener<>() { - private static final Listener INSTANCE = new Listener(); - - private final Set mounts = Collections.newSetFromMap( new WeakHashMap<>() ); - private final Set managers = Collections.newSetFromMap( new WeakHashMap<>() ); + @Nonnull + @Override + protected Void prepare( @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) + { + profiler.push( "Reloading ComputerCraft mounts" ); + try + { + for( ResourceMount mount : MOUNT_CACHE.values() ) mount.load( manager ); + } + finally + { + profiler.pop(); + } + return null; + } @Override - public void onResourceManagerReload( @Nonnull ResourceManager manager ) + protected void apply( @Nonnull Void result, @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) { - for( ResourceMount mount : mounts ) mount.load(); } - - synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) - { - if( managers.add( manager ) ) manager.registerReloadListener( this ); - mounts.add( mount ); - } - } + }; } diff --git a/src/main/java/dan200/computercraft/core/lua/LuaContext.java b/src/main/java/dan200/computercraft/core/lua/LuaContext.java index 0e5c792c8..626d15fad 100644 --- a/src/main/java/dan200/computercraft/core/lua/LuaContext.java +++ b/src/main/java/dan200/computercraft/core/lua/LuaContext.java @@ -9,8 +9,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.MainThread; @@ -68,11 +66,4 @@ class LuaContext implements ILuaContext throw new LuaException( "Task limit exceeded" ); } } - - @Nonnull - @Override - public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException - { - return TaskCallback.make( this, task ); - } } diff --git a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java index 495d1a2d1..b2cbb021c 100644 --- a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java @@ -24,7 +24,7 @@ class ResultInterpreterFunction extends ResumableVarArgFunction SKIP = new HashSet<>( Arrays.asList( + TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME, + TrackingField.SERVER_COUNT, TrackingField.SERVER_TIME + ) ); + + private static ComputerMBean instance; + + private final Map attributes = new HashMap<>(); + private final Map values = new HashMap<>(); + private final MBeanInfo info; + + private ComputerMBean() + { + List attributes = new ArrayList<>(); + for( Map.Entry field : TrackingField.fields().entrySet() ) + { + if( SKIP.contains( field.getValue() ) ) continue; + + String name = CaseFormat.LOWER_UNDERSCORE.to( CaseFormat.LOWER_CAMEL, field.getKey() ); + add( name, field.getValue(), attributes, null ); + } + + add( "task", TrackingField.TOTAL_TIME, attributes, TrackingField.TASKS ); + add( "serverTask", TrackingField.SERVER_TIME, attributes, TrackingField.SERVER_COUNT ); + + info = new MBeanInfo( + ComputerMBean.class.getSimpleName(), + "metrics about all computers on the server", + attributes.toArray( new MBeanAttributeInfo[0] ), null, null, null + ); + } + + public static void register() + { + try + { + ManagementFactory.getPlatformMBeanServer().registerMBean( instance = new ComputerMBean(), new ObjectName( "dan200.computercraft:type=Computers" ) ); + } + catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | MalformedObjectNameException e ) + { + ComputerCraft.log.warn( "Failed to register JMX bean", e ); + } + } + + public static void registerTracker() + { + if( instance != null ) Tracking.add( instance ); + } + + @Override + public Object getAttribute( String attribute ) throws AttributeNotFoundException + { + LongSupplier value = attributes.get( attribute ); + if( value == null ) throw new AttributeNotFoundException(); + return value.getAsLong(); + } + + @Override + public void setAttribute( Attribute attribute ) throws InvalidAttributeValueException + { + throw new InvalidAttributeValueException( "Cannot set attribute" ); + } + + @Override + public AttributeList getAttributes( String[] attributes ) + { + return null; + } + + @Override + public AttributeList setAttributes( AttributeList attributes ) + { + return new AttributeList(); + } + + @Override + public Object invoke( String actionName, Object[] params, String[] signature ) + { + return null; + } + + @Override + @Nonnull + public MBeanInfo getMBeanInfo() + { + return info; + } + + @Override + public void addTaskTiming( Computer computer, long time ) + { + addValue( computer, TrackingField.TOTAL_TIME, time ); + } + + @Override + public void addServerTiming( Computer computer, long time ) + { + addValue( computer, TrackingField.SERVER_TIME, time ); + } + + @Override + public void addValue( Computer computer, TrackingField field, long change ) + { + Counter counter = values.get( field ); + counter.value.addAndGet( change ); + counter.count.incrementAndGet(); + } + + private MBeanAttributeInfo addAttribute( String name, String description, LongSupplier value ) + { + attributes.put( name, value ); + return new MBeanAttributeInfo( name, "long", description, true, false, false ); + } + + private void add( String name, TrackingField field, List attributes, TrackingField count ) + { + Counter counter = new Counter(); + values.put( field, counter ); + + String prettyName = Language.getInstance().getOrDefault( field.translationKey() ); + attributes.add( addAttribute( name, prettyName, counter.value::longValue ) ); + if( count != null ) + { + String countName = Language.getInstance().getOrDefault( count.translationKey() ); + attributes.add( addAttribute( name + "Count", countName, counter.count::longValue ) ); + } + } + + private static class Counter + { + final AtomicLong value = new AtomicLong(); + final AtomicLong count = new AtomicLong(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index fec0609ae..e312c43ff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.api.lua.LuaException; @@ -28,9 +27,9 @@ import java.util.Set; */ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { + private IPacketNetwork network; private final Set computers = new HashSet<>( 1 ); private final ModemState state; - private IPacketNetwork network; protected ModemPeripheral( ModemState state ) { @@ -42,6 +41,20 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return state; } + private synchronized void setNetwork( IPacketNetwork network ) + { + if( this.network == network ) return; + + // Leave old network + if( this.network != null ) this.network.removeReceiver( this ); + + // Set new network + this.network = network; + + // Join new network + if( this.network != null ) this.network.addReceiver( this ); + } + public void destroy() { setNetwork( null ); @@ -50,21 +63,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveSameDimension( @Nonnull Packet packet, double distance ) { - if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) - { - return; - } + if( packet.sender() == this || !state.isOpen( packet.channel() ) ) return; synchronized( computers ) { for( IComputerAccess computer : computers ) { computer.queueEvent( "modem_message", - computer.getAttachmentName(), - packet.getChannel(), - packet.getReplyChannel(), - packet.getPayload(), - distance ); + computer.getAttachmentName(), packet.channel(), packet.replyChannel(), packet.payload(), distance ); } } } @@ -72,20 +78,20 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveDifferentDimension( @Nonnull Packet packet ) { - if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) - { - return; - } + if( packet.sender() == this || !state.isOpen( packet.channel() ) ) return; synchronized( computers ) { for( IComputerAccess computer : computers ) { - computer.queueEvent( "modem_message", computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() ); + computer.queueEvent( "modem_message", + computer.getAttachmentName(), packet.channel(), packet.replyChannel(), packet.payload() ); } } } + protected abstract IPacketNetwork getNetwork(); + @Nonnull @Override public String getType() @@ -93,60 +99,15 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return "modem"; } - @Override - public synchronized void attach( @Nonnull IComputerAccess computer ) + private static int parseChannel( int channel ) throws LuaException { - synchronized( computers ) - { - computers.add( computer ); - } - - setNetwork( getNetwork() ); - } - - protected abstract IPacketNetwork getNetwork(); - - private synchronized void setNetwork( IPacketNetwork network ) - { - if( this.network == network ) - { - return; - } - - // Leave old network - if( this.network != null ) - { - this.network.removeReceiver( this ); - } - - // Set new network - this.network = network; - - // Join new network - if( this.network != null ) - { - this.network.addReceiver( this ); - } - } - - @Override - public synchronized void detach( @Nonnull IComputerAccess computer ) - { - boolean empty; - synchronized( computers ) - { - computers.remove( computer ); - empty = computers.isEmpty(); - } - - if( empty ) - { - setNetwork( null ); - } + if( channel < 0 || channel > 65535 ) throw new LuaException( "Expected number in range 0-65535" ); + return channel; } /** - * Open a channel on a modem. A channel must be open in order to receive messages. Modems can have up to 128 channels open at one time. + * Open a channel on a modem. A channel must be open in order to receive messages. Modems can have up to 128 + * channels open at one time. * * @param channel The channel to open. This must be a number between 0 and 65535. * @throws LuaException If the channel is out of range. @@ -158,15 +119,6 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa state.open( parseChannel( channel ) ); } - private static int parseChannel( int channel ) throws LuaException - { - if( channel < 0 || channel > 65535 ) - { - throw new LuaException( "Expected number in range 0-65535" ); - } - return channel; - } - /** * Check if a channel is open. * @@ -202,13 +154,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa } /** - * Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message} event on adjacent computers. + * Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message} + * event on adjacent computers. * *
    Note: The channel does not need be open to send a message.
    * * @param channel The channel to send messages on. * @param replyChannel The channel that responses to this message should be sent on. - * @param payload The object to send. This can be a string, number, or table. + * @param payload The object to send. This can be a boolean, string, number, or table. * @throws LuaException If the channel is out of range. */ @LuaFunction @@ -217,14 +170,11 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa parseChannel( channel ); parseChannel( replyChannel ); - Level world = getWorld(); + Level world = getLevel(); Vec3 position = getPosition(); IPacketNetwork network = this.network; - if( world == null || position == null || network == null ) - { - return; - } + if( world == null || position == null || network == null ) return; Packet packet = new Packet( channel, replyChannel, payload, this ); if( isInterdimensional() ) @@ -240,7 +190,8 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa /** * Determine if this is a wired or wireless modem. * - * Some methods (namely those dealing with wired networks and remote peripherals) are only available on wired modems. + * Some methods (namely those dealing with wired networks and remote peripherals) are only available on wired + * modems. * * @return {@code true} if this is a wireless modem. */ @@ -251,6 +202,30 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return network != null && network.isWireless(); } + @Override + public synchronized void attach( @Nonnull IComputerAccess computer ) + { + synchronized( computers ) + { + computers.add( computer ); + } + + setNetwork( getNetwork() ); + } + + @Override + public synchronized void detach( @Nonnull IComputerAccess computer ) + { + boolean empty; + synchronized( computers ) + { + computers.remove( computer ); + empty = computers.isEmpty(); + } + + if( empty ) setNetwork( null ); + } + @Nonnull @Override public String getSenderID() @@ -263,8 +238,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa } else { - IComputerAccess computer = computers.iterator() - .next(); + IComputerAccess computer = computers.iterator().next(); return computer.getID() + "_" + computer.getAttachmentName(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index fefdf28c3..4c8c7ebb5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -419,7 +419,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile { @Nonnull @Override - public Level getWorld() + public Level getLevel() { return TileCable.this.getLevel(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 11dd6ebfe..37de3790b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -430,7 +430,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Level getWorld() + public Level getLevel() { return entity.getLevel(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index aae60b894..6cf699655 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -122,9 +122,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW @Nonnull @Override - public Level getWorld() + public Level getLevel() { - return modem.getWorld(); + return modem.getLevel(); } /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index b1a3379e8..809fa0761 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -121,7 +121,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Level getWorld() + public Level getLevel() { return entity.getLevel(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 3f0ca47aa..07f685542 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -32,7 +32,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } else { - Level world = getWorld(); + Level world = getLevel(); if( world != null ) { Vec3 position = getPosition(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java index 7f3dcb35f..c1f06c922 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.api.network.IPacketNetwork; @@ -20,14 +19,10 @@ import java.util.concurrent.ConcurrentHashMap; public class WirelessNetwork implements IPacketNetwork { private static WirelessNetwork universalNetwork = null; - private final Set receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); public static WirelessNetwork getUniversal() { - if( universalNetwork == null ) - { - universalNetwork = new WirelessNetwork(); - } + if( universalNetwork == null ) universalNetwork = new WirelessNetwork(); return universalNetwork; } @@ -36,6 +31,8 @@ public class WirelessNetwork implements IPacketNetwork universalNetwork = null; } + private final Set receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); + @Override public void addReceiver( @Nonnull IPacketReceiver receiver ) { @@ -50,40 +47,27 @@ public class WirelessNetwork implements IPacketNetwork receivers.remove( receiver ); } - @Override - public boolean isWireless() - { - return true; - } - @Override public void transmitSameDimension( @Nonnull Packet packet, double range ) { Objects.requireNonNull( packet, "packet cannot be null" ); - for( IPacketReceiver device : receivers ) - { - tryTransmit( device, packet, range, false ); - } + for( IPacketReceiver device : receivers ) tryTransmit( device, packet, range, false ); } @Override public void transmitInterdimensional( @Nonnull Packet packet ) { Objects.requireNonNull( packet, "packet cannot be null" ); - for( IPacketReceiver device : receivers ) - { - tryTransmit( device, packet, 0, true ); - } + for( IPacketReceiver device : receivers ) tryTransmit( device, packet, 0, true ); } private static void tryTransmit( IPacketReceiver receiver, Packet packet, double range, boolean interdimensional ) { - IPacketSender sender = packet.getSender(); - if( receiver.getWorld() == sender.getWorld() ) + IPacketSender sender = packet.sender(); + if( receiver.getLevel() == sender.getLevel() ) { double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical - double distanceSq = receiver.getPosition() - .distanceToSqr( sender.getPosition() ); + double distanceSq = receiver.getPosition().distanceToSqr( sender.getPosition() ); if( interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange ) { receiver.receiveSameDimension( packet, Math.sqrt( distanceSq ) ); @@ -97,4 +81,10 @@ public class WirelessNetwork implements IPacketNetwork } } } + + @Override + public boolean isWireless() + { + return true; + } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index f13b41927..f31a7d14d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -32,7 +32,7 @@ public class PocketModemPeripheral extends WirelessModemPeripheral @Nonnull @Override - public Level getWorld() + public Level getLevel() { return world; } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 27de26e94..5e875d045 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -28,7 +28,6 @@ import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.turtle.FurnaceRefuelHandler; -import dan200.computercraft.shared.turtle.SignInspectHandler; import dan200.computercraft.shared.util.Config; import dan200.computercraft.shared.util.TickScheduler; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; @@ -139,7 +138,6 @@ public final class ComputerCraftProxyCommon TurtleEvent.EVENT_BUS.register( FurnaceRefuelHandler.INSTANCE ); TurtleEvent.EVENT_BUS.register( new TurtlePermissions() ); - TurtleEvent.EVENT_BUS.register( new SignInspectHandler() ); } public static void registerLoot() diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index ab02d655a..c8f3ad0a0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -51,7 +51,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler if( !remainder.isEmpty() ) { WorldUtil.dropItemStack( remainder, - turtle.getWorld(), + turtle.getLevel(), turtle.getPosition(), turtle.getDirection() .getOpposite() ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java deleted file mode 100644 index 574274d97..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.turtle; - -import com.google.common.eventbus.Subscribe; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignBlockEntity; - -import java.util.HashMap; -import java.util.Map; - -public class SignInspectHandler -{ - @Subscribe - public void onTurtleInspect( TurtleBlockEvent.Inspect event ) - { - BlockEntity be = event.getWorld().getBlockEntity( event.getPos() ); - if( be instanceof SignBlockEntity ) - { - SignBlockEntity sbe = (SignBlockEntity) be; - Map textTable = new HashMap<>(); - for( int k = 0; k < 4; k++ ) - { - textTable.put( k + 1, sbe.getMessage( k, true ).getString() ); - } - event.getData().put( "text", textTable ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 79438be47..3da20374e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -11,9 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; -import dan200.computercraft.api.turtle.event.TurtleInspectItemEvent; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.tracking.TrackingField; @@ -774,12 +771,6 @@ public class TurtleAPI implements ILuaAPI ? ItemData.fill( new HashMap<>(), stack ) : ItemData.fillBasicSafe( new HashMap<>(), stack ); - TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed ); - if( TurtleEvent.post( event ) ) - { - return new Object[] { false, event.getFailureMessage() }; - } - return new Object[] { table }; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index d00fbdd03..57f7c76e5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -160,7 +160,7 @@ public class TurtleBrain implements ITurtleAccess public void update() { - Level world = getWorld(); + Level world = getLevel(); if( !world.isClientSide ) { // Advance movement @@ -187,7 +187,7 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Level getWorld() + public Level getLevel() { return owner.getLevel(); } @@ -202,13 +202,13 @@ public class TurtleBrain implements ITurtleAccess @Override public boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ) { - if( world.isClientSide || getWorld().isClientSide ) + if( world.isClientSide || getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot teleport on the client" ); } // Cache info about the old turtle (so we don't access this after we delete ourselves) - Level oldWorld = getWorld(); + Level oldWorld = getLevel(); TileTurtle oldOwner = owner; BlockPos oldPos = owner.getBlockPos(); BlockState oldBlock = owner.getBlockState(); @@ -341,7 +341,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void setSelectedSlot( int slot ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot set the slot on the client" ); } @@ -419,7 +419,7 @@ public class TurtleBrain implements ITurtleAccess @Override public boolean consumeFuel( int fuel ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot consume fuel on the client" ); } @@ -441,7 +441,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void addFuel( int fuel ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot add fuel on the client" ); } @@ -454,7 +454,7 @@ public class TurtleBrain implements ITurtleAccess @Override public MethodResult executeCommand( @Nonnull ITurtleCommand command ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot run commands on the client" ); } @@ -474,7 +474,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void playAnimation( @Nonnull TurtleAnimation animation ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot play animations on the client" ); } @@ -646,7 +646,7 @@ public class TurtleBrain implements ITurtleAccess { if( animation != TurtleAnimation.NONE ) { - Level world = getWorld(); + Level world = getLevel(); if( ComputerCraft.turtlesCanPush ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index c18fe8b44..d5acdc3d2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -41,7 +41,7 @@ public class TurtleCompareCommand implements ITurtleCommand .getItem( turtle.getSelectedSlot() ); // Get stack representing thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index 80af2ff7e..ac7e7652d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -33,7 +33,7 @@ public class TurtleCraftCommand implements ITurtleCommand { // Craft the item TurtleInventoryCrafting crafting = new TurtleInventoryCrafting( turtle ); - List results = crafting.doCrafting( turtle.getWorld(), limit ); + List results = crafting.doCrafting( turtle.getLevel(), limit ); if( results == null ) { return TurtleCommandResult.failure( "No matching recipes" ); @@ -45,7 +45,7 @@ public class TurtleCraftCommand implements ITurtleCommand ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); if( !remainder.isEmpty() ) { - WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection() ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), turtle.getPosition(), turtle.getDirection() ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index b35416964..e422cbdb2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -33,7 +33,7 @@ public class TurtleDetectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 81fc98340..a035ba148 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -10,8 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleEvent; -import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; @@ -56,22 +54,13 @@ public class TurtleDropCommand implements ITurtleCommand } // Get inventory for thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); Direction side = direction.getOpposite(); Container inventory = InventoryUtil.getInventory( world, newPosition, side ); - // Fire the event, restoring the inventory and exiting if it is cancelled. - TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); - TurtleInventoryEvent.Drop event = new TurtleInventoryEvent.Drop( turtle, player, world, newPosition, inventory, stack ); - if( TurtleEvent.post( event ) ) - { - InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( inventory != null ) { // Drop the item into the inventory diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index e2bc8f065..b87bc201f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -7,9 +7,6 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.*; -import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; @@ -66,12 +63,6 @@ public class TurtleEquipCommand implements ITurtleCommand oldUpgradeStack = null; } - TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.EQUIP ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - // Do the swapping: if( newUpgradeStack != null ) { @@ -86,7 +77,7 @@ public class TurtleEquipCommand implements ITurtleCommand { // If there's no room for the items, drop them BlockPos position = turtle.getPosition(); - WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), position, turtle.getDirection() ); } } turtle.setUpgrade( side, newUpgrade ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index f65811149..1dee94820 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -9,8 +9,6 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.peripheral.generic.data.BlockData; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -39,7 +37,7 @@ public class TurtleInspectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); @@ -51,14 +49,6 @@ public class TurtleInspectCommand implements ITurtleCommand Map table = BlockData.fill( new HashMap<>(), state ); - // Fire the event, exiting if it is cancelled - TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); - TurtleBlockEvent.Inspect event = new TurtleBlockEvent.Inspect( turtle, turtlePlayer, world, newPosition, state, table ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - return TurtleCommandResult.success( new Object[] { table } ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 4d7092230..0d6956fae 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; @@ -45,7 +43,7 @@ public class TurtleMoveCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if we can move - Level oldWorld = turtle.getWorld(); + Level oldWorld = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); @@ -88,12 +86,6 @@ public class TurtleMoveCommand implements ITurtleCommand } } - TurtleBlockEvent.Move moveEvent = new TurtleBlockEvent.Move( turtle, turtlePlayer, oldWorld, newPosition ); - if( TurtleEvent.post( moveEvent ) ) - { - return TurtleCommandResult.failure( moveEvent.getFailureMessage() ); - } - // Check fuel level if( turtle.isFuelNeeded() && turtle.getFuelLevel() < 1 ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 2d92ddd14..edf5d8181 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DropConsumer; @@ -83,12 +81,6 @@ public class TurtlePlaceCommand implements ITurtleCommand .relative( direction ); TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction ); - TurtleBlockEvent.Place place = new TurtleBlockEvent.Place( turtle, turtlePlayer, turtle.getWorld(), coordinates, stack ); - if( TurtleEvent.post( place ) ) - { - return TurtleCommandResult.failure( place.getFailureMessage() ); - } - // Do the deploying String[] errorMessage = new String[1]; ItemStack remainder = deploy( stack, turtle, turtlePlayer, direction, extraArguments, errorMessage ); @@ -221,7 +213,7 @@ public class TurtlePlaceCommand implements ITurtleCommand Object[] extraArguments, String[] outErrorMessage ) { // See if there is an entity present - final Level world = turtle.getWorld(); + final Level world = turtle.getLevel(); final BlockPos position = turtle.getPosition(); Vec3 turtlePos = turtlePlayer.position(); Vec3 rayDir = turtlePlayer.getViewVector( 1.0f ); @@ -324,7 +316,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Do the deploying (put everything in the players inventory) boolean placed = false; - BlockEntity existingTile = turtle.getWorld() + BlockEntity existingTile = turtle.getLevel() .getBlockEntity( position ); if( stackCopy.useOn( context ).consumesAction() ) @@ -335,7 +327,7 @@ public class TurtlePlaceCommand implements ITurtleCommand if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof WaterLilyBlockItem || item instanceof BottleItem) ) { - InteractionResultHolder result = stackCopy.use( turtle.getWorld(), turtlePlayer, InteractionHand.MAIN_HAND ); + InteractionResultHolder result = stackCopy.use( turtle.getLevel(), turtlePlayer, InteractionHand.MAIN_HAND ); if( result.getResult() .consumesAction() && !ItemStack.matches( stack, result.getObject() ) ) { @@ -349,7 +341,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { if( extraArguments != null && extraArguments.length >= 1 && extraArguments[0] instanceof String ) { - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockEntity tile = world.getBlockEntity( position ); if( tile == null || tile == existingTile ) { @@ -404,7 +396,7 @@ public class TurtlePlaceCommand implements ITurtleCommand private static boolean canDeployOnBlock( @Nonnull BlockPlaceContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage ) { - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); if( !world.isInWorldBounds( position ) || world.isEmptyBlock( position ) || (context.getItemInHand() .getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index bb00bbedd..fc7830834 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -48,7 +48,7 @@ public final class TurtlePlayer extends FakePlayer private static TurtlePlayer create( ITurtleAccess turtle ) { - ServerLevel world = (ServerLevel) turtle.getWorld(); + ServerLevel world = (ServerLevel) turtle.getLevel(); GameProfile profile = turtle.getOwningPlayer(); TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); @@ -96,7 +96,7 @@ public final class TurtlePlayer extends FakePlayer TurtleBrain brain = (TurtleBrain) access; TurtlePlayer player = brain.cachedPlayer; - if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getWorld() ) + if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getLevel() ) { player = brain.cachedPlayer = create( brain ); } @@ -133,7 +133,7 @@ public final class TurtlePlayer extends FakePlayer ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); if( !remainder.isEmpty() ) { - WorldUtil.dropItemStack( remainder, turtle.getWorld(), dropPosition, dropDirection ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), dropPosition, dropDirection ); } getInventory().setItem( i, ItemStack.EMPTY ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index 51a71febf..7a913666a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; @@ -30,27 +29,16 @@ public class TurtleRefuelCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { int slot = turtle.getSelectedSlot(); - ItemStack stack = turtle.getInventory() - .getItem( slot ); - if( stack.isEmpty() ) - { - return TurtleCommandResult.failure( "No items to combust" ); - } + ItemStack stack = turtle.getInventory().getItem( slot ); + if( stack.isEmpty() ) return TurtleCommandResult.failure( "No items to combust" ); TurtleRefuelEvent event = new TurtleRefuelEvent( turtle, stack ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( event.getHandler() == null ) - { - return TurtleCommandResult.failure( "Items not combustible" ); - } + TurtleEvent.EVENT_BUS.post( event ); + if( event.getHandler() == null ) return TurtleCommandResult.failure( "Items not combustible" ); if( limit != 0 ) { - turtle.addFuel( event.getHandler() - .refuel( turtle, stack, slot, limit ) ); + turtle.addFuel( event.getHandler().refuel( turtle, stack, slot, limit ) ); turtle.playAnimation( TurtleAnimation.WAIT ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index be448c095..54138dc99 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -10,8 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleEvent; -import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import net.minecraft.core.BlockPos; @@ -52,21 +50,13 @@ public class TurtleSuckCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Get inventory for thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos turtlePosition = turtle.getPosition(); BlockPos blockPosition = turtlePosition.relative( direction ); Direction side = direction.getOpposite(); Container inventory = InventoryUtil.getInventory( world, blockPosition, side ); - // Fire the event, exiting if it is cancelled. - TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); - TurtleInventoryEvent.Suck event = new TurtleInventoryEvent.Suck( turtle, player, world, blockPosition, inventory ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( inventory != null ) { // Take from inventory of thing in front diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index add8d1fec..78c27ecf3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -10,9 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import javax.annotation.Nonnull; @@ -29,12 +26,6 @@ public class TurtleTurnCommand implements ITurtleCommand @Override public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { - TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.TURN ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - switch( direction ) { case LEFT: diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 1c2d0189b..bfc6a5c00 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; @@ -27,8 +26,8 @@ import java.util.List; public class TurtleInventoryCrafting extends CraftingContainer { private final ITurtleAccess turtle; - private int xStart; - private int yStart; + private int xStart = 0; + private int yStart = 0; @SuppressWarnings( "ConstantConditions" ) public TurtleInventoryCrafting( ITurtleAccess turtle ) @@ -37,8 +36,6 @@ public class TurtleInventoryCrafting extends CraftingContainer // avoid throwing any NPEs. super( null, 0, 0 ); this.turtle = turtle; - xStart = 0; - yStart = 0; } @Nullable @@ -52,11 +49,10 @@ public class TurtleInventoryCrafting extends CraftingContainer { for( int y = 0; y < TileTurtle.INVENTORY_HEIGHT; y++ ) { - if( x < this.xStart || x >= this.xStart + 3 || y < this.yStart || y >= this.yStart + 3 ) + if( x < this.xStart || x >= this.xStart + 3 || + y < this.yStart || y >= this.yStart + 3 ) { - if( !turtle.getInventory() - .getItem( x + y * TileTurtle.INVENTORY_WIDTH ) - .isEmpty() ) + if( !turtle.getInventory().getItem( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() ) { return null; } @@ -65,44 +61,23 @@ public class TurtleInventoryCrafting extends CraftingContainer } // Check the actual crafting - return turtle.getWorld() - .getRecipeManager() - .getRecipeFor( RecipeType.CRAFTING, this, turtle.getWorld() ) - .orElse( null ); + return turtle.getLevel().getRecipeManager().getRecipeFor( RecipeType.CRAFTING, this, turtle.getLevel() ).orElse( null ); } @Nullable public List doCrafting( Level world, int maxCount ) { - if( world.isClientSide || !(world instanceof ServerLevel) ) - { - return null; - } + if( world.isClientSide || !(world instanceof ServerLevel) ) return null; // Find out what we can craft Recipe recipe = tryCrafting( 0, 0 ); - if( recipe == null ) - { - recipe = tryCrafting( 0, 1 ); - } - if( recipe == null ) - { - recipe = tryCrafting( 1, 0 ); - } - if( recipe == null ) - { - recipe = tryCrafting( 1, 1 ); - } - if( recipe == null ) - { - return null; - } + if( recipe == null ) recipe = tryCrafting( 0, 1 ); + if( recipe == null ) recipe = tryCrafting( 1, 0 ); + if( recipe == null ) recipe = tryCrafting( 1, 1 ); + if( recipe == null ) return null; // Special case: craft(0) just returns an empty list if crafting was possible - if( maxCount == 0 ) - { - return Collections.emptyList(); - } + if( maxCount == 0 ) return Collections.emptyList(); TurtlePlayer player = TurtlePlayer.get( turtle ); @@ -110,13 +85,11 @@ public class TurtleInventoryCrafting extends CraftingContainer for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ ) { ItemStack result = recipe.assemble( this ); - if( result.isEmpty() ) - { - break; - } + if( result.isEmpty() ) break; results.add( result ); result.onCraftedBy( world, player, result.getCount() ); + NonNullList remainders = recipe.getRemainingItems( this ); for( int slot = 0; slot < remainders.size(); slot++ ) @@ -130,10 +103,7 @@ public class TurtleInventoryCrafting extends CraftingContainer existing = getItem( slot ); } - if( remainder.isEmpty() ) - { - continue; - } + if( remainder.isEmpty() ) continue; // Either update the current stack or add it to the remainder list (to be inserted into the inventory // afterwards). @@ -156,27 +126,12 @@ public class TurtleInventoryCrafting extends CraftingContainer return results; } - @Override - public int getMaxStackSize() - { - return turtle.getInventory() - .getMaxStackSize(); - } - @Override public int getWidth() { return 3; } - @Override - public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) - { - i = modifyIndex( i ); - return turtle.getInventory() - .canPlaceItem( i, stack ); - } - @Override public int getHeight() { @@ -187,7 +142,9 @@ public class TurtleInventoryCrafting extends CraftingContainer { int x = xStart + index % getWidth(); int y = yStart + index / getHeight(); - return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT ? x + y * TileTurtle.INVENTORY_WIDTH : -1; + return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT + ? x + y * TileTurtle.INVENTORY_WIDTH + : -1; } // IInventory implementation @@ -203,8 +160,7 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack getItem( int i ) { i = modifyIndex( i ); - return turtle.getInventory() - .getItem( i ); + return turtle.getInventory().getItem( i ); } @Nonnull @@ -212,8 +168,7 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack removeItemNoUpdate( int i ) { i = modifyIndex( i ); - return turtle.getInventory() - .removeItemNoUpdate( i ); + return turtle.getInventory().removeItemNoUpdate( i ); } @Nonnull @@ -221,24 +176,26 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack removeItem( int i, int size ) { i = modifyIndex( i ); - return turtle.getInventory() - .removeItem( i, size ); + return turtle.getInventory().removeItem( i, size ); } @Override public void setItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); - turtle.getInventory() - .setItem( i, stack ); + turtle.getInventory().setItem( i, stack ); } + @Override + public int getMaxStackSize() + { + return turtle.getInventory().getMaxStackSize(); + } @Override public void setChanged() { - turtle.getInventory() - .setChanged(); + turtle.getInventory().setChanged(); } @Override @@ -247,6 +204,12 @@ public class TurtleInventoryCrafting extends CraftingContainer return true; } + @Override + public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) + { + i = modifyIndex( i ); + return turtle.getInventory().canPlaceItem( i, stack ); + } @Override public void clearContent() @@ -254,8 +217,7 @@ public class TurtleInventoryCrafting extends CraftingContainer for( int i = 0; i < getContainerSize(); i++ ) { int j = modifyIndex( i ); - turtle.getInventory() - .setItem( j, ItemStack.EMPTY ); + turtle.getInventory().setItem( j, ItemStack.EMPTY ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 97a0851c9..74edc1935 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -100,7 +100,7 @@ public class TurtleModem extends AbstractTurtleUpgrade public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) { // Advance the modem - if( !turtle.getWorld().isClientSide ) + if( !turtle.getLevel().isClientSide ) { IPeripheral peripheral = turtle.getPeripheral( side ); if( peripheral instanceof Peripheral ) @@ -128,9 +128,9 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override - public Level getWorld() + public Level getLevel() { - return turtle.getWorld(); + return turtle.getLevel(); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index bd35ecd90..e31884bed 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -83,7 +83,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade @Override public Level getWorld() { - return turtle.getWorld(); + return turtle.getLevel(); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index c25d9dbef..d18ff84a5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -11,9 +11,6 @@ import com.mojang.math.Transformation; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.*; -import dan200.computercraft.api.turtle.event.TurtleAttackEvent; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.fabric.mixininterface.IMatrix4f; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.turtle.core.TurtleBrain; @@ -114,7 +111,7 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult attack( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Create a fake player, and orient it appropriately - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos position = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( position ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); @@ -144,12 +141,6 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Nothing to attack here" ); } - TurtleAttackEvent attackEvent = new TurtleAttackEvent( turtle, turtlePlayer, hitEntity, this, side ); - if( TurtleEvent.post( attackEvent ) ) - { - return TurtleCommandResult.failure( attackEvent.getFailureMessage() ); - } - // Start claiming entity drops DropConsumer.set( hitEntity, turtleDropConsumer( turtleBlock, turtle ) ); @@ -199,7 +190,7 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult dig( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Get ready to dig - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos turtlePosition = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( turtlePosition ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); @@ -231,13 +222,6 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Unbreakable block detected" ); } - // Fire the dig event, checking whether it was cancelled. - TurtleBlockEvent.Dig digEvent = new TurtleBlockEvent.Dig( turtle, turtlePlayer, world, blockPosition, state, this, side ); - if( TurtleEvent.post( digEvent ) ) - { - return TurtleCommandResult.failure( digEvent.getFailureMessage() ); - } - if( !PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak( world, turtlePlayer, blockPosition, state, null ) ) { return TurtleCommandResult.failure( "Break cancelled" ); @@ -291,7 +275,7 @@ public class TurtleTool extends AbstractTurtleUpgrade for( ItemStack remainder : extra ) { WorldUtil.dropItemStack( remainder, - turtle.getWorld(), + turtle.getLevel(), turtle.getPosition(), direction ); } diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java index 0fc7fc4a6..1f46afc71 100644 --- a/src/main/java/dan200/computercraft/shared/util/Config.java +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -13,7 +13,6 @@ import com.electronwill.nightconfig.core.file.FileNotFoundAction; import com.google.common.base.CaseFormat; import com.google.common.base.Converter; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRuleConfig; import dan200.computercraft.fabric.mixin.LevelResourceAccess; @@ -25,7 +24,10 @@ import net.minecraft.world.level.storage.LevelResource; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -208,10 +210,6 @@ public final class Config serverSpec.comment( "turtle.can_push", "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" ); serverSpec.define( "turtle.can_push", ComputerCraft.turtlesCanPush ); - - serverSpec.comment( "turtle.disabled_actions", - "A list of turtle actions which are disabled." ); - serverSpec.defineList( "turtle.disabled_actions", Collections.emptyList(), x -> x instanceof String && getAction( (String) x ) != null ); } { // Terminal sizes @@ -372,12 +370,6 @@ public final class Config ComputerCraft.turtlesObeyBlockProtection = serverConfig.get( "turtle.obey_block_protection" ); ComputerCraft.turtlesCanPush = serverConfig.get( "turtle.can_push" ); - ComputerCraft.turtleDisabledActions.clear(); - for( String value : serverConfig.>get( "turtle.disabled_actions" ) ) - { - ComputerCraft.turtleDisabledActions.add( getAction( value ) ); - } - // Terminal Size ComputerCraft.computerTermWidth = serverConfig.get( "term_sizes.computer.width" ); ComputerCraft.computerTermHeight = serverConfig.get( "term_sizes.computer.height" ); @@ -397,16 +389,4 @@ public final class Config } private static final Converter converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE ); - - private static TurtleAction getAction( String value ) - { - try - { - return TurtleAction.valueOf( converter.convert( value ) ); - } - catch( IllegalArgumentException e ) - { - return null; - } - } } diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index 558de86ca..34db6a87f 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import com.google.common.collect.ImmutableMap; @@ -36,21 +35,299 @@ public final class WiredNetwork implements IWiredNetwork this.nodes = nodes; } + @Override + public boolean connect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) + { + WiredNode wiredU = checkNode( nodeU ); + WiredNode wiredV = checkNode( nodeV ); + if( nodeU == nodeV ) throw new IllegalArgumentException( "Cannot add a connection to oneself." ); + + lock.writeLock().lock(); + try + { + if( nodes == null ) throw new IllegalStateException( "Cannot add a connection to an empty network." ); + + boolean hasU = wiredU.network == this; + boolean hasV = wiredV.network == this; + if( !hasU && !hasV ) throw new IllegalArgumentException( "Neither node is in the network." ); + + // We're going to assimilate a node. Copy across all edges and vertices. + if( !hasU || !hasV ) + { + WiredNetwork other = hasU ? wiredV.network : wiredU.network; + other.lock.writeLock().lock(); + try + { + // Cache several properties for iterating over later + Map otherPeripherals = other.peripherals; + Map thisPeripherals = otherPeripherals.isEmpty() ? peripherals : new HashMap<>( peripherals ); + + Collection thisNodes = otherPeripherals.isEmpty() ? nodes : new ArrayList<>( nodes ); + Collection otherNodes = other.nodes; + + // Move all nodes across into this network, destroying the original nodes. + nodes.addAll( otherNodes ); + for( WiredNode node : otherNodes ) node.network = this; + other.nodes = null; + + // Move all peripherals across, + other.peripherals = null; + peripherals.putAll( otherPeripherals ); + + if( !thisPeripherals.isEmpty() ) + { + WiredNetworkChange.added( thisPeripherals ).broadcast( otherNodes ); + } + + if( !otherPeripherals.isEmpty() ) + { + WiredNetworkChange.added( otherPeripherals ).broadcast( thisNodes ); + } + } + finally + { + other.lock.writeLock().unlock(); + } + } + + boolean added = wiredU.neighbours.add( wiredV ); + if( added ) wiredV.neighbours.add( wiredU ); + + InvariantChecker.checkNetwork( this ); + InvariantChecker.checkNode( wiredU ); + InvariantChecker.checkNode( wiredV ); + + return added; + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public boolean disconnect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) + { + WiredNode wiredU = checkNode( nodeU ); + WiredNode wiredV = checkNode( nodeV ); + if( nodeU == nodeV ) throw new IllegalArgumentException( "Cannot remove a connection to oneself." ); + + lock.writeLock().lock(); + try + { + boolean hasU = wiredU.network == this; + boolean hasV = wiredV.network == this; + if( !hasU || !hasV ) throw new IllegalArgumentException( "One node is not in the network." ); + + // If there was no connection to remove then split. + if( !wiredU.neighbours.remove( wiredV ) ) return false; + wiredV.neighbours.remove( wiredU ); + + // Determine if there is still some connection from u to v. + // Note this is an inlining of reachableNodes which short-circuits + // if all nodes are reachable. + Queue enqueued = new ArrayDeque<>(); + HashSet reachableU = new HashSet<>(); + + reachableU.add( wiredU ); + enqueued.add( wiredU ); + + while( !enqueued.isEmpty() ) + { + WiredNode node = enqueued.remove(); + for( WiredNode neighbour : node.neighbours ) + { + // If we can reach wiredV from wiredU then abort. + if( neighbour == wiredV ) return true; + + // Otherwise attempt to enqueue this neighbour as well. + if( reachableU.add( neighbour ) ) enqueued.add( neighbour ); + } + } + + // Create a new network with all U-reachable nodes/edges and remove them + // from the existing graph. + WiredNetwork networkU = new WiredNetwork( reachableU ); + networkU.lock.writeLock().lock(); + try + { + // Remove nodes from this network + nodes.removeAll( reachableU ); + + // Set network and transfer peripherals + for( WiredNode node : reachableU ) + { + node.network = networkU; + networkU.peripherals.putAll( node.peripherals ); + peripherals.keySet().removeAll( node.peripherals.keySet() ); + } + + // Broadcast changes + if( !peripherals.isEmpty() ) WiredNetworkChange.removed( peripherals ).broadcast( networkU.nodes ); + if( !networkU.peripherals.isEmpty() ) + { + WiredNetworkChange.removed( networkU.peripherals ).broadcast( nodes ); + } + + InvariantChecker.checkNetwork( this ); + InvariantChecker.checkNetwork( networkU ); + InvariantChecker.checkNode( wiredU ); + InvariantChecker.checkNode( wiredV ); + + return true; + } + finally + { + networkU.lock.writeLock().unlock(); + } + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public boolean remove( @Nonnull IWiredNode node ) + { + WiredNode wired = checkNode( node ); + + lock.writeLock().lock(); + try + { + // If we're the empty graph then just abort: nodes must have _some_ network. + if( nodes == null ) return false; + if( nodes.size() <= 1 ) return false; + if( wired.network != this ) return false; + + HashSet neighbours = wired.neighbours; + + // Remove this node and move into a separate network. + nodes.remove( wired ); + for( WiredNode neighbour : neighbours ) neighbour.neighbours.remove( wired ); + + WiredNetwork wiredNetwork = new WiredNetwork( wired ); + + // If we're a leaf node in the graph (only one neighbour) then we don't need to + // check for network splitting + if( neighbours.size() == 1 ) + { + // Broadcast our simple peripheral changes + removeSingleNode( wired, wiredNetwork ); + InvariantChecker.checkNode( wired ); + InvariantChecker.checkNetwork( wiredNetwork ); + return true; + } + + HashSet reachable = reachableNodes( neighbours.iterator().next() ); + + // If all nodes are reachable then exit. + if( reachable.size() == nodes.size() ) + { + // Broadcast our simple peripheral changes + removeSingleNode( wired, wiredNetwork ); + InvariantChecker.checkNode( wired ); + InvariantChecker.checkNetwork( wiredNetwork ); + return true; + } + + // A split may cause 2..neighbours.size() separate networks, so we + // iterate through our neighbour list, generating child networks. + neighbours.removeAll( reachable ); + ArrayList maximals = new ArrayList<>( neighbours.size() + 1 ); + maximals.add( wiredNetwork ); + maximals.add( new WiredNetwork( reachable ) ); + + while( !neighbours.isEmpty() ) + { + reachable = reachableNodes( neighbours.iterator().next() ); + neighbours.removeAll( reachable ); + maximals.add( new WiredNetwork( reachable ) ); + } + + for( WiredNetwork network : maximals ) network.lock.writeLock().lock(); + + try + { + // We special case the original node: detaching all peripherals when needed. + wired.network = wiredNetwork; + wired.peripherals = Collections.emptyMap(); + + // Ensure every network is finalised + for( WiredNetwork network : maximals ) + { + for( WiredNode child : network.nodes ) + { + child.network = network; + network.peripherals.putAll( child.peripherals ); + } + } + + for( WiredNetwork network : maximals ) InvariantChecker.checkNetwork( network ); + InvariantChecker.checkNode( wired ); + + // Then broadcast network changes once all nodes are finalised + for( WiredNetwork network : maximals ) + { + WiredNetworkChange.changeOf( peripherals, network.peripherals ).broadcast( network.nodes ); + } + } + finally + { + for( WiredNetwork network : maximals ) network.lock.writeLock().unlock(); + } + + nodes.clear(); + peripherals.clear(); + + return true; + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map newPeripherals ) + { + WiredNode wired = checkNode( node ); + Objects.requireNonNull( peripherals, "peripherals cannot be null" ); + + lock.writeLock().lock(); + try + { + if( wired.network != this ) throw new IllegalStateException( "Node is not on this network" ); + + Map oldPeripherals = wired.peripherals; + WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals ); + if( change.isEmpty() ) return; + + wired.peripherals = ImmutableMap.copyOf( newPeripherals ); + + // Detach the old peripherals then remove them. + peripherals.keySet().removeAll( change.peripheralsRemoved().keySet() ); + + // Add the new peripherals and attach them + peripherals.putAll( change.peripheralsAdded() ); + + change.broadcast( nodes ); + } + finally + { + lock.writeLock().unlock(); + } + } + static void transmitPacket( WiredNode start, Packet packet, double range, boolean interdimensional ) { Map points = new HashMap<>(); TreeSet transmitTo = new TreeSet<>(); { - TransmitPoint startEntry = start.element.getWorld() != packet.getSender() - .getWorld() ? new TransmitPoint( start, - Double.POSITIVE_INFINITY, - true ) : new TransmitPoint( start, - start.element.getPosition() - .distanceTo( - packet.getSender() - .getPosition() ), - false ); + TransmitPoint startEntry = start.element.getLevel() != packet.sender().getLevel() + ? new TransmitPoint( start, Double.POSITIVE_INFINITY, true ) + : new TransmitPoint( start, start.element.getPosition().distanceTo( packet.sender().getPosition() ), false ); points.put( start, startEntry ); transmitTo.add( startEntry ); } @@ -59,7 +336,7 @@ public final class WiredNetwork implements IWiredNetwork TransmitPoint point; while( (point = transmitTo.pollFirst()) != null ) { - Level world = point.node.element.getWorld(); + Level world = point.node.element.getLevel(); Vec3 position = point.node.element.getPosition(); for( WiredNode neighbour : point.node.neighbours ) { @@ -67,7 +344,7 @@ public final class WiredNetwork implements IWiredNetwork boolean newInterdimensional; double newDistance; - if( world != neighbour.element.getWorld() ) + if( world != neighbour.element.getLevel() ) { newInterdimensional = true; newDistance = Double.POSITIVE_INFINITY; @@ -101,378 +378,9 @@ public final class WiredNetwork implements IWiredNetwork } } - @Override - public boolean connect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) - { - WiredNode wiredU = checkNode( nodeU ); - WiredNode wiredV = checkNode( nodeV ); - if( nodeU == nodeV ) - { - throw new IllegalArgumentException( "Cannot add a connection to oneself." ); - } - - lock.writeLock() - .lock(); - try - { - if( nodes == null ) - { - throw new IllegalStateException( "Cannot add a connection to an empty network." ); - } - - boolean hasU = wiredU.network == this; - boolean hasV = wiredV.network == this; - if( !hasU && !hasV ) - { - throw new IllegalArgumentException( "Neither node is in the network." ); - } - - // We're going to assimilate a node. Copy across all edges and vertices. - if( !hasU || !hasV ) - { - WiredNetwork other = hasU ? wiredV.network : wiredU.network; - other.lock.writeLock() - .lock(); - try - { - // Cache several properties for iterating over later - Map otherPeripherals = other.peripherals; - Map thisPeripherals = otherPeripherals.isEmpty() ? peripherals : new HashMap<>( peripherals ); - - Collection thisNodes = otherPeripherals.isEmpty() ? nodes : new ArrayList<>( nodes ); - Collection otherNodes = other.nodes; - - // Move all nodes across into this network, destroying the original nodes. - nodes.addAll( otherNodes ); - for( WiredNode node : otherNodes ) - { - node.network = this; - } - other.nodes = null; - - // Move all peripherals across, - other.peripherals = null; - peripherals.putAll( otherPeripherals ); - - if( !thisPeripherals.isEmpty() ) - { - WiredNetworkChange.added( thisPeripherals ) - .broadcast( otherNodes ); - } - - if( !otherPeripherals.isEmpty() ) - { - WiredNetworkChange.added( otherPeripherals ) - .broadcast( thisNodes ); - } - } - finally - { - other.lock.writeLock() - .unlock(); - } - } - - boolean added = wiredU.neighbours.add( wiredV ); - if( added ) - { - wiredV.neighbours.add( wiredU ); - } - - InvariantChecker.checkNetwork( this ); - InvariantChecker.checkNode( wiredU ); - InvariantChecker.checkNode( wiredV ); - - return added; - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public boolean disconnect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) - { - WiredNode wiredU = checkNode( nodeU ); - WiredNode wiredV = checkNode( nodeV ); - if( nodeU == nodeV ) - { - throw new IllegalArgumentException( "Cannot remove a connection to oneself." ); - } - - lock.writeLock() - .lock(); - try - { - boolean hasU = wiredU.network == this; - boolean hasV = wiredV.network == this; - if( !hasU || !hasV ) - { - throw new IllegalArgumentException( "One node is not in the network." ); - } - - // If there was no connection to remove then split. - if( !wiredU.neighbours.remove( wiredV ) ) - { - return false; - } - wiredV.neighbours.remove( wiredU ); - - // Determine if there is still some connection from u to v. - // Note this is an inlining of reachableNodes which short-circuits - // if all nodes are reachable. - Queue enqueued = new ArrayDeque<>(); - HashSet reachableU = new HashSet<>(); - - reachableU.add( wiredU ); - enqueued.add( wiredU ); - - while( !enqueued.isEmpty() ) - { - WiredNode node = enqueued.remove(); - for( WiredNode neighbour : node.neighbours ) - { - // If we can reach wiredV from wiredU then abort. - if( neighbour == wiredV ) - { - return true; - } - - // Otherwise attempt to enqueue this neighbour as well. - if( reachableU.add( neighbour ) ) - { - enqueued.add( neighbour ); - } - } - } - - // Create a new network with all U-reachable nodes/edges and remove them - // from the existing graph. - WiredNetwork networkU = new WiredNetwork( reachableU ); - networkU.lock.writeLock() - .lock(); - try - { - // Remove nodes from this network - nodes.removeAll( reachableU ); - - // Set network and transfer peripherals - for( WiredNode node : reachableU ) - { - node.network = networkU; - networkU.peripherals.putAll( node.peripherals ); - peripherals.keySet() - .removeAll( node.peripherals.keySet() ); - } - - // Broadcast changes - if( !peripherals.isEmpty() ) - { - WiredNetworkChange.removed( peripherals ) - .broadcast( networkU.nodes ); - } - if( !networkU.peripherals.isEmpty() ) - { - WiredNetworkChange.removed( networkU.peripherals ) - .broadcast( nodes ); - } - - InvariantChecker.checkNetwork( this ); - InvariantChecker.checkNetwork( networkU ); - InvariantChecker.checkNode( wiredU ); - InvariantChecker.checkNode( wiredV ); - - return true; - } - finally - { - networkU.lock.writeLock() - .unlock(); - } - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public boolean remove( @Nonnull IWiredNode node ) - { - WiredNode wired = checkNode( node ); - - lock.writeLock() - .lock(); - try - { - // If we're the empty graph then just abort: nodes must have _some_ network. - if( nodes == null ) - { - return false; - } - if( nodes.size() <= 1 ) - { - return false; - } - if( wired.network != this ) - { - return false; - } - - HashSet neighbours = wired.neighbours; - - // Remove this node and move into a separate network. - nodes.remove( wired ); - for( WiredNode neighbour : neighbours ) - { - neighbour.neighbours.remove( wired ); - } - - WiredNetwork wiredNetwork = new WiredNetwork( wired ); - - // If we're a leaf node in the graph (only one neighbour) then we don't need to - // check for network splitting - if( neighbours.size() == 1 ) - { - // Broadcast our simple peripheral changes - removeSingleNode( wired, wiredNetwork ); - InvariantChecker.checkNode( wired ); - InvariantChecker.checkNetwork( wiredNetwork ); - return true; - } - - HashSet reachable = reachableNodes( neighbours.iterator() - .next() ); - - // If all nodes are reachable then exit. - if( reachable.size() == nodes.size() ) - { - // Broadcast our simple peripheral changes - removeSingleNode( wired, wiredNetwork ); - InvariantChecker.checkNode( wired ); - InvariantChecker.checkNetwork( wiredNetwork ); - return true; - } - - // A split may cause 2..neighbours.size() separate networks, so we - // iterate through our neighbour list, generating child networks. - neighbours.removeAll( reachable ); - ArrayList maximals = new ArrayList<>( neighbours.size() + 1 ); - maximals.add( wiredNetwork ); - maximals.add( new WiredNetwork( reachable ) ); - - while( !neighbours.isEmpty() ) - { - reachable = reachableNodes( neighbours.iterator() - .next() ); - neighbours.removeAll( reachable ); - maximals.add( new WiredNetwork( reachable ) ); - } - - for( WiredNetwork network : maximals ) - { - network.lock.writeLock() - .lock(); - } - - try - { - // We special case the original node: detaching all peripherals when needed. - wired.network = wiredNetwork; - wired.peripherals = Collections.emptyMap(); - - // Ensure every network is finalised - for( WiredNetwork network : maximals ) - { - for( WiredNode child : network.nodes ) - { - child.network = network; - network.peripherals.putAll( child.peripherals ); - } - } - - for( WiredNetwork network : maximals ) - { - InvariantChecker.checkNetwork( network ); - } - InvariantChecker.checkNode( wired ); - - // Then broadcast network changes once all nodes are finalised - for( WiredNetwork network : maximals ) - { - WiredNetworkChange.changeOf( peripherals, network.peripherals ) - .broadcast( network.nodes ); - } - } - finally - { - for( WiredNetwork network : maximals ) - { - network.lock.writeLock() - .unlock(); - } - } - - nodes.clear(); - peripherals.clear(); - - return true; - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map newPeripherals ) - { - WiredNode wired = checkNode( node ); - Objects.requireNonNull( peripherals, "peripherals cannot be null" ); - - lock.writeLock() - .lock(); - try - { - if( wired.network != this ) - { - throw new IllegalStateException( "Node is not on this network" ); - } - - Map oldPeripherals = wired.peripherals; - WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals ); - if( change.isEmpty() ) - { - return; - } - - wired.peripherals = ImmutableMap.copyOf( newPeripherals ); - - // Detach the old peripherals then remove them. - peripherals.keySet() - .removeAll( change.peripheralsRemoved() - .keySet() ); - - // Add the new peripherals and attach them - peripherals.putAll( change.peripheralsAdded() ); - - change.broadcast( nodes ); - } - finally - { - lock.writeLock() - .unlock(); - } - } - private void removeSingleNode( WiredNode wired, WiredNetwork wiredNetwork ) { - wiredNetwork.lock.writeLock() - .lock(); + wiredNetwork.lock.writeLock().lock(); try { // Cache all the old nodes. @@ -485,62 +393,16 @@ public final class WiredNetwork implements IWiredNetwork wired.peripherals = Collections.emptyMap(); // Broadcast the change - if( !peripherals.isEmpty() ) - { - WiredNetworkChange.removed( peripherals ) - .broadcast( wired ); - } + if( !peripherals.isEmpty() ) WiredNetworkChange.removed( peripherals ).broadcast( wired ); // Now remove all peripherals from this network and broadcast the change. - peripherals.keySet() - .removeAll( wiredPeripherals.keySet() ); - if( !wiredPeripherals.isEmpty() ) - { - WiredNetworkChange.removed( wiredPeripherals ) - .broadcast( nodes ); - } + peripherals.keySet().removeAll( wiredPeripherals.keySet() ); + if( !wiredPeripherals.isEmpty() ) WiredNetworkChange.removed( wiredPeripherals ).broadcast( nodes ); } finally { - wiredNetwork.lock.writeLock() - .unlock(); - } - } - - private static HashSet reachableNodes( WiredNode start ) - { - Queue enqueued = new ArrayDeque<>(); - HashSet reachable = new HashSet<>(); - - reachable.add( start ); - enqueued.add( start ); - - WiredNode node; - while( (node = enqueued.poll()) != null ) - { - for( WiredNode neighbour : node.neighbours ) - { - // Otherwise attempt to enqueue this neighbour as well. - if( reachable.add( neighbour ) ) - { - enqueued.add( neighbour ); - } - } - } - - return reachable; - } - - private static WiredNode checkNode( IWiredNode node ) - { - if( node instanceof WiredNode ) - { - return (WiredNode) node; - } - else - { - throw new IllegalArgumentException( "Unknown implementation of IWiredNode: " + node ); + wiredNetwork.lock.writeLock().unlock(); } } @@ -561,7 +423,42 @@ public final class WiredNetwork implements IWiredNetwork public int compareTo( @Nonnull TransmitPoint o ) { // Objects with the same distance are not the same object, so we must add an additional layer of ordering. - return distance == o.distance ? Integer.compare( node.hashCode(), o.node.hashCode() ) : Double.compare( distance, o.distance ); + return distance == o.distance + ? Integer.compare( node.hashCode(), o.node.hashCode() ) + : Double.compare( distance, o.distance ); } } + + private static WiredNode checkNode( IWiredNode node ) + { + if( node instanceof WiredNode ) + { + return (WiredNode) node; + } + else + { + throw new IllegalArgumentException( "Unknown implementation of IWiredNode: " + node ); + } + } + + private static HashSet reachableNodes( WiredNode start ) + { + Queue enqueued = new ArrayDeque<>(); + HashSet reachable = new HashSet<>(); + + reachable.add( start ); + enqueued.add( start ); + + WiredNode node; + while( (node = enqueued.poll()) != null ) + { + for( WiredNode neighbour : node.neighbours ) + { + // Otherwise attempt to enqueue this neighbour as well. + if( reachable.add( neighbour ) ) enqueued.add( neighbour ); + } + } + + return reachable; + } } diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java index 03cd63820..c6426ca18 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.IPacketReceiver; @@ -20,12 +19,14 @@ import java.util.concurrent.locks.Lock; public final class WiredNode implements IWiredNode { - final IWiredElement element; - final HashSet neighbours = new HashSet<>(); - Map peripherals = Collections.emptyMap(); - volatile WiredNetwork network; private Set receivers; + final IWiredElement element; + Map peripherals = Collections.emptyMap(); + + final HashSet neighbours = new HashSet<>(); + volatile WiredNetwork network; + public WiredNode( IWiredElement element ) { this.element = element; @@ -35,19 +36,37 @@ public final class WiredNode implements IWiredNode @Override public synchronized void addReceiver( @Nonnull IPacketReceiver receiver ) { - if( receivers == null ) - { - receivers = new HashSet<>(); - } + if( receivers == null ) receivers = new HashSet<>(); receivers.add( receiver ); } @Override public synchronized void removeReceiver( @Nonnull IPacketReceiver receiver ) { - if( receivers != null ) + if( receivers != null ) receivers.remove( receiver ); + } + + synchronized void tryTransmit( Packet packet, double packetDistance, boolean packetInterdimensional, double range, boolean interdimensional ) + { + if( receivers == null ) return; + + for( IPacketReceiver receiver : receivers ) { - receivers.remove( receiver ); + if( !packetInterdimensional ) + { + double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical + if( interdimensional || receiver.isInterdimensional() || packetDistance < receiveRange ) + { + receiver.receiveSameDimension( packet, packetDistance + element.getPosition().distanceTo( receiver.getPosition() ) ); + } + } + else + { + if( interdimensional || receiver.isInterdimensional() ) + { + receiver.receiveDifferentDimension( packet ); + } + } } } @@ -61,7 +80,7 @@ public final class WiredNode implements IWiredNode public void transmitSameDimension( @Nonnull Packet packet, double range ) { Objects.requireNonNull( packet, "packet cannot be null" ); - if( !(packet.getSender() instanceof IWiredSender) || ((IWiredSender) packet.getSender()).getNode() != this ) + if( !(packet.sender() instanceof IWiredSender) || ((IWiredSender) packet.sender()).getNode() != this ) { throw new IllegalArgumentException( "Sender is not in the network" ); } @@ -73,8 +92,7 @@ public final class WiredNode implements IWiredNode } finally { - network.lock.readLock() - .unlock(); + network.lock.readLock().unlock(); } } @@ -82,7 +100,7 @@ public final class WiredNode implements IWiredNode public void transmitInterdimensional( @Nonnull Packet packet ) { Objects.requireNonNull( packet, "packet cannot be null" ); - if( !(packet.getSender() instanceof IWiredSender) || ((IWiredSender) packet.getSender()).getNode() != this ) + if( !(packet.sender() instanceof IWiredSender) || ((IWiredSender) packet.sender()).getNode() != this ) { throw new IllegalArgumentException( "Sender is not in the network" ); } @@ -94,54 +112,7 @@ public final class WiredNode implements IWiredNode } finally { - network.lock.readLock() - .unlock(); - } - } - - private void acquireReadLock() - { - WiredNetwork currentNetwork = network; - while( true ) - { - Lock lock = currentNetwork.lock.readLock(); - lock.lock(); - if( currentNetwork == network ) - { - return; - } - - - lock.unlock(); - } - } - - synchronized void tryTransmit( Packet packet, double packetDistance, boolean packetInterdimensional, double range, boolean interdimensional ) - { - if( receivers == null ) - { - return; - } - - for( IPacketReceiver receiver : receivers ) - { - if( !packetInterdimensional ) - { - double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical - if( interdimensional || receiver.isInterdimensional() || packetDistance < receiveRange ) - { - receiver.receiveSameDimension( packet, - packetDistance + element.getPosition() - .distanceTo( receiver.getPosition() ) ); - } - } - else - { - if( interdimensional || receiver.isInterdimensional() ) - { - receiver.receiveDifferentDimension( packet ); - } - } + network.lock.readLock().unlock(); } } @@ -162,7 +133,20 @@ public final class WiredNode implements IWiredNode @Override public String toString() { - return "WiredNode{@" + element.getPosition() + " (" + element.getClass() - .getSimpleName() + ")}"; + return "WiredNode{@" + element.getPosition() + " (" + element.getClass().getSimpleName() + ")}"; + } + + private void acquireReadLock() + { + WiredNetwork currentNetwork = network; + while( true ) + { + Lock lock = currentNetwork.lock.readLock(); + lock.lock(); + if( currentNetwork == network ) return; + + + lock.unlock(); + } } } diff --git a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua index 3f42b6510..83f4bb6ad 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua @@ -25,9 +25,17 @@ CHANNEL_BROADCAST = 65535 --- The channel used by the Rednet API to repeat messages. CHANNEL_REPEAT = 65533 +--- The number of channels rednet reserves for computer IDs. Computers with IDs +-- greater or equal to this limit wrap around to 0. +MAX_ID_CHANNELS = 65500 + local tReceivedMessages = {} -local tReceivedMessageTimeouts = {} local tHostnames = {} +local nClearTimer + +local function id_as_channel(id) + return (id or os.getComputerID()) % MAX_ID_CHANNELS +end --[[- Opens a modem with the given @{peripheral} name, allowing it to send and receive messages over rednet. @@ -47,7 +55,7 @@ function open(modem) if peripheral.getType(modem) ~= "modem" then error("No such modem: " .. modem, 2) end - peripheral.call(modem, "open", os.getComputerID()) + peripheral.call(modem, "open", id_as_channel()) peripheral.call(modem, "open", CHANNEL_BROADCAST) end @@ -64,7 +72,7 @@ function close(modem) if peripheral.getType(modem) ~= "modem" then error("No such modem: " .. modem, 2) end - peripheral.call(modem, "close", os.getComputerID()) + peripheral.call(modem, "close", id_as_channel()) peripheral.call(modem, "close", CHANNEL_BROADCAST) else -- Close all modems @@ -87,7 +95,7 @@ function isOpen(modem) if modem then -- Check if a specific modem is open if peripheral.getType(modem) == "modem" then - return peripheral.call(modem, "isOpen", os.getComputerID()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST) + return peripheral.call(modem, "isOpen", id_as_channel()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST) end else -- Check if any modem is open @@ -130,14 +138,15 @@ function send(nRecipient, message, sProtocol) -- We could do other things to guarantee uniqueness, but we really don't need to -- Store it to ensure we don't get our own messages back local nMessageID = math.random(1, 2147483647) - tReceivedMessages[nMessageID] = true - tReceivedMessageTimeouts[os.startTimer(30)] = nMessageID + tReceivedMessages[nMessageID] = os.clock() + 9.5 + if not nClearTimer then nClearTimer = os.startTimer(10) end -- Create the message - local nReplyChannel = os.getComputerID() + local nReplyChannel = id_as_channel() local tMessage = { nMessageID = nMessageID, nRecipient = nRecipient, + nSender = os.getComputerID(), message = message, sProtocol = sProtocol, } @@ -145,10 +154,14 @@ function send(nRecipient, message, sProtocol) local sent = false if nRecipient == os.getComputerID() then -- Loopback to ourselves - os.queueEvent("rednet_message", nReplyChannel, message, sProtocol) + os.queueEvent("rednet_message", os.getComputerID(), message, sProtocol) sent = true else -- Send on all open modems, to the target and to repeaters + if nRecipient ~= CHANNEL_BROADCAST then + nRecipient = id_as_channel(nRecipient) + end + for _, sModem in ipairs(peripheral.getNames()) do if isOpen(sModem) then peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage) @@ -390,13 +403,15 @@ function run() if sEvent == "modem_message" then -- Got a modem message, process it and add it to the rednet event queue local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4 - if isOpen(sModem) and (nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST) then + if nChannel == id_as_channel() or nChannel == CHANNEL_BROADCAST then if type(tMessage) == "table" and type(tMessage.nMessageID) == "number" and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID] + and ((tMessage.nRecipient and tMessage.nRecipient == os.getComputerID()) or nChannel == CHANNEL_BROADCAST) + and isOpen(sModem) then - tReceivedMessages[tMessage.nMessageID] = true - tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID - os.queueEvent("rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol) + tReceivedMessages[tMessage.nMessageID] = os.clock() + 9.5 + if not nClearTimer then nClearTimer = os.startTimer(10) end + os.queueEvent("rednet_message", tMessage.nSender or nReplyChannel, tMessage.message, tMessage.sProtocol) end end @@ -414,14 +429,15 @@ function run() end end - elseif sEvent == "timer" then + elseif sEvent == "timer" and p1 == nClearTimer then -- Got a timer event, use it to clear the event queue - local nTimer = p1 - local nMessage = tReceivedMessageTimeouts[nTimer] - if nMessage then - tReceivedMessageTimeouts[nTimer] = nil - tReceivedMessages[nMessage] = nil + nClearTimer = nil + local nNow, bHasMore = os.clock(), nil + for nMessageID, nDeadline in pairs(tReceivedMessages) do + if nDeadline <= nNow then tReceivedMessages[nMessageID] = nil + else bHasMore = true end end + nClearTimer = bHasMore and os.startTimer(10) end end end diff --git a/src/main/resources/data/computercraft/lua/rom/apis/window.lua b/src/main/resources/data/computercraft/lua/rom/apis/window.lua index feafa00c2..724cda155 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -265,6 +265,8 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then error("Arguments must be the same length", 2) end + sTextColor = sTextColor:lower() + sBackgroundColor = sBackgroundColor:lower() internalBlit(sText, sTextColor, sBackgroundColor) end diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.md similarity index 100% rename from src/main/resources/data/computercraft/lua/rom/help/changelog.txt rename to src/main/resources/data/computercraft/lua/rom/help/changelog.md diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md similarity index 100% rename from src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt rename to src/main/resources/data/computercraft/lua/rom/help/whatsnew.md diff --git a/src/main/resources/data/computercraft/lua/rom/programs/about.lua b/src/main/resources/data/computercraft/lua/rom/programs/about.lua new file mode 100644 index 000000000..37a0e2901 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/programs/about.lua @@ -0,0 +1,4 @@ +-- Prints information about CraftOS +term.setTextColor(colors.yellow) +print(os.version() .. " on " .. _HOST) +term.setTextColor(colors.white) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua index 57ab7b916..5a2e78b83 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua @@ -5,6 +5,8 @@ elseif date.month == 12 and date.day == 24 then print("Merry X-mas!") elseif date.month == 10 and date.day == 31 then print("OOoooOOOoooo! Spooky!") +elseif date.month == 4 and date.day == 28 then + print("Ed Balls") else local tMotd = {} diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua index dfd9ca907..c5ed89984 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua @@ -14,6 +14,10 @@ else print(#tModems .. " modems found.") end +local function idAsChannel(id) + return (id or os.getComputerID()) % rednet.MAX_ID_CHANNELS +end + local function open(nChannel) for n = 1, #tModems do local sModem = tModems[n] @@ -53,7 +57,7 @@ local ok, error = pcall(function() for n = 1, #tModems do local sOtherModem = tModems[n] peripheral.call(sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage) - peripheral.call(sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage) + peripheral.call(sOtherModem, "transmit", idAsChannel(tMessage.nRecipient), nReplyChannel, tMessage) end -- Log the event From 8983ecd03a6ea3c34d27110c39d0a1d9470c9747 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 27 Nov 2021 15:50:37 +0000 Subject: [PATCH 5/5] Reset more files --- src/main/java/dan200/computercraft/client/SoundManager.java | 2 +- .../java/dan200/computercraft/shared/TurtlePermissions.java | 2 +- .../computercraft/shared/command/builder/ArgCommand.java | 1 - .../shared/command/builder/CommandNodeBuilder.java | 1 - .../computercraft/shared/common/IBundledRedstoneBlock.java | 1 - .../java/dan200/computercraft/shared/common/ITerminal.java | 1 - .../computercraft/shared/computer/blocks/IComputerTile.java | 1 - .../shared/computer/core/ClientComputerRegistry.java | 1 - .../shared/data/BlockNamedEntityLootCondition.java | 1 - .../shared/data/ConstantLootConditionSerializer.java | 1 - .../computercraft/shared/data/HasComputerIdLootCondition.java | 1 - .../computercraft/shared/data/PlayerCreativeLootCondition.java | 1 - .../shared/network/client/ComputerClientMessage.java | 1 - .../shared/network/container/HeldItemContainerData.java | 1 - .../shared/network/container/ViewComputerContainerData.java | 1 - .../shared/peripheral/generic/SaturatedMethod.java | 3 +-- .../shared/peripheral/modem/wired/CableModemVariant.java | 1 - .../shared/pocket/peripherals/PocketModemPeripheral.java | 1 - .../dan200/computercraft/shared/turtle/blocks/ITurtleTile.java | 1 - .../shared/turtle/core/TurtleCommandQueueEntry.java | 1 - .../shared/turtle/core/TurtleTransferToCommand.java | 1 - .../dan200/computercraft/shared/turtle/items/ITurtleItem.java | 1 - .../dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java | 1 - .../dan200/computercraft/shared/util/DefaultInventory.java | 1 - .../computercraft/shared/util/DefaultSidedInventory.java | 1 - src/main/java/dan200/computercraft/shared/util/RecordUtil.java | 1 - .../java/dan200/computercraft/shared/util/ValidatingSlot.java | 1 - 27 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/SoundManager.java b/src/main/java/dan200/computercraft/client/SoundManager.java index e2fddf623..d4ccf7cac 100644 --- a/src/main/java/dan200/computercraft/client/SoundManager.java +++ b/src/main/java/dan200/computercraft/client/SoundManager.java @@ -60,7 +60,7 @@ public class SoundManager setPosition( position ); this.volume = volume; this.pitch = pitch; - attenuation = SoundInstance.Attenuation.LINEAR; + attenuation = Attenuation.LINEAR; } void setPosition( Vec3 position ) diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 38659c400..98e4cd135 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -16,7 +16,7 @@ public final class TurtlePermissions public static boolean isBlockEnterable( Level world, BlockPos pos, Player player ) { MinecraftServer server = world.getServer(); - return server == null || world.isClientSide || world instanceof ServerLevel && !server.isUnderSpawnProtection( (ServerLevel) world, pos, player ); + return server == null || world.isClientSide || (world instanceof ServerLevel && !server.isUnderSpawnProtection( (ServerLevel) world, pos, player )); } public static boolean isBlockEditable( Level world, BlockPos pos, Player player ) diff --git a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java index ea834c4c8..c478b67b5 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.Command; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java index dc10a5eea..f2e108727 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.tree.CommandNode; diff --git a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index a1dca6e4f..90478f3bb 100644 --- a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.core.BlockPos; diff --git a/src/main/java/dan200/computercraft/shared/common/ITerminal.java b/src/main/java/dan200/computercraft/shared/common/ITerminal.java index 2a6a9a9e0..48577e5da 100644 --- a/src/main/java/dan200/computercraft/shared/common/ITerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ITerminal.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java index ba3e4fc0d..40e0dca90 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java index 725a8c7a5..fa87eb642 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; public class ClientComputerRegistry extends ComputerRegistry diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index 03e534461..e25f4f891 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import net.minecraft.world.Nameable; diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index 8480a3a57..ea3ab1333 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import com.google.gson.JsonDeserializationContext; diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java index a2221e74b..4127ec6ef 100644 --- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import dan200.computercraft.shared.computer.blocks.IComputerTile; diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 006c8779a..3666ffbb6 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import net.minecraft.world.entity.Entity; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java index 1368866bc..d3349cdfc 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index 04f9a2af3..3650b2a52 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.common.ContainerHeldItem; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index 842783c1a..dd0c995f5 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java index eca38e63f..406d62466 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java @@ -44,9 +44,8 @@ final class SaturatedMethod public boolean equals( Object obj ) { if( obj == this ) return true; - if( !(obj instanceof SaturatedMethod) ) return false; + if( !(obj instanceof SaturatedMethod other) ) return false; - SaturatedMethod other = (SaturatedMethod) obj; return method == other.method && target.equals( other.target ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index 132cb0718..3c456ab4b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import net.minecraft.core.Direction; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index f31a7d14d..7ed7f6939 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 8ea8006f0..8076f0445 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java index 17f203329..dfa7d90d7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleCommand; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index e641cfd04..8f69559cf 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java index 92021a9e7..9a6cfce7c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index cdc91c422..744c04a8c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 6d5b07a86..f8af29947 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.world.Container; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index 47f92a51d..7a94909a6 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.core.Direction; diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index afe99a065..4e56e3bb5 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.shared.network.NetworkHandler; diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index 79e8c0cf1..42ca181d4 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.world.Container;