1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-26 08:56:54 +00:00

Merge branch 'mc-1.20.x' into mc-1.21.x

This commit is contained in:
Jonathan Coates 2024-06-22 22:33:18 +01:00
commit 28f75a0687
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
24 changed files with 169 additions and 245 deletions

View File

@ -24,7 +24,6 @@ import dan200.computercraft.shared.command.CommandComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerContext; import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu; import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
import dan200.computercraft.shared.media.items.DiskItem; import dan200.computercraft.shared.media.items.DiskItem;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -101,15 +100,12 @@ public final class ClientRegistry {
public static void registerMenuScreens(RegisterMenuScreen register) { public static void registerMenuScreens(RegisterMenuScreen register) {
register.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new); register.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
register.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), ComputerScreen::new);
register.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new); register.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
register.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new); register.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
register.register(ModRegistry.Menus.PRINTER.get(), PrinterScreen::new); register.register(ModRegistry.Menus.PRINTER.get(), PrinterScreen::new);
register.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new); register.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new);
register.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new); register.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new);
register.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
} }
public interface RegisterMenuScreen { public interface RegisterMenuScreen {

View File

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.integration.jei; package dan200.computercraft.client.integration.jei;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;

View File

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.integration.jei; package dan200.computercraft.client.integration.jei;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.integration.RecipeModHelpers; import dan200.computercraft.shared.integration.RecipeModHelpers;

View File

@ -27,12 +27,10 @@ import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
import dan200.computercraft.shared.common.HeldItemMenu; import dan200.computercraft.shared.common.HeldItemMenu;
import dan200.computercraft.shared.computer.blocks.CommandComputerBlock; import dan200.computercraft.shared.computer.blocks.CommandComputerBlock;
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity;
import dan200.computercraft.shared.computer.blocks.ComputerBlock; import dan200.computercraft.shared.computer.blocks.ComputerBlock;
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity; import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
import dan200.computercraft.shared.computer.items.AbstractComputerItem; import dan200.computercraft.shared.computer.items.AbstractComputerItem;
import dan200.computercraft.shared.computer.items.CommandComputerItem; import dan200.computercraft.shared.computer.items.CommandComputerItem;
import dan200.computercraft.shared.computer.items.ComputerItem; import dan200.computercraft.shared.computer.items.ComputerItem;
@ -155,8 +153,7 @@ public final class ModRegistry {
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL)); () -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced", public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED)); () -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
public static final RegistryEntry<ComputerBlock<CommandComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
() -> new CommandComputerBlock<>(computerProperties().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND)); () -> new CommandComputerBlock<>(computerProperties().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal", public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
@ -199,8 +196,8 @@ public final class ModRegistry {
ofBlock(Blocks.COMPUTER_NORMAL, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_NORMAL.get(), p, s, ComputerFamily.NORMAL)); ofBlock(Blocks.COMPUTER_NORMAL, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_NORMAL.get(), p, s, ComputerFamily.NORMAL));
public static final RegistryEntry<BlockEntityType<ComputerBlockEntity>> COMPUTER_ADVANCED = public static final RegistryEntry<BlockEntityType<ComputerBlockEntity>> COMPUTER_ADVANCED =
ofBlock(Blocks.COMPUTER_ADVANCED, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_ADVANCED.get(), p, s, ComputerFamily.ADVANCED)); ofBlock(Blocks.COMPUTER_ADVANCED, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_ADVANCED.get(), p, s, ComputerFamily.ADVANCED));
public static final RegistryEntry<BlockEntityType<CommandComputerBlockEntity>> COMPUTER_COMMAND = public static final RegistryEntry<BlockEntityType<ComputerBlockEntity>> COMPUTER_COMMAND =
ofBlock(Blocks.COMPUTER_COMMAND, (p, s) -> new CommandComputerBlockEntity(BlockEntities.COMPUTER_COMMAND.get(), p, s)); ofBlock(Blocks.COMPUTER_COMMAND, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_COMMAND.get(), p, s, ComputerFamily.COMMAND));
public static final RegistryEntry<BlockEntityType<TurtleBlockEntity>> TURTLE_NORMAL = public static final RegistryEntry<BlockEntityType<TurtleBlockEntity>> TURTLE_NORMAL =
ofBlock(Blocks.TURTLE_NORMAL, (p, s) -> new TurtleBlockEntity(BlockEntities.TURTLE_NORMAL.get(), p, s, () -> Config.turtleFuelLimit, ComputerFamily.NORMAL)); ofBlock(Blocks.TURTLE_NORMAL, (p, s) -> new TurtleBlockEntity(BlockEntities.TURTLE_NORMAL.get(), p, s, () -> Config.turtleFuelLimit, ComputerFamily.NORMAL));
@ -413,9 +410,6 @@ public final class ModRegistry {
public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> COMPUTER = REGISTRY.register("computer", public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> COMPUTER = REGISTRY.register("computer",
() -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data))); () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data)));
public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> POCKET_COMPUTER = REGISTRY.register("pocket_computer",
() -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER.get(), id, inv, data)));
public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> POCKET_COMPUTER_NO_TERM = REGISTRY.register("pocket_computer_no_term", public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> POCKET_COMPUTER_NO_TERM = REGISTRY.register("pocket_computer_no_term",
() -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER_NO_TERM.get(), id, inv, data))); () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER_NO_TERM.get(), id, inv, data)));
@ -433,9 +427,6 @@ public final class ModRegistry {
HeldItemContainerData.STREAM_CODEC, HeldItemContainerData.STREAM_CODEC,
(id, inventory, data) -> new HeldItemMenu(Menus.PRINTOUT.get(), id, inventory.player, data.hand()) (id, inventory, data) -> new HeldItemMenu(Menus.PRINTOUT.get(), id, inventory.player, data.hand())
)); ));
public static final RegistryEntry<MenuType<ViewComputerMenu>> VIEW_COMPUTER = REGISTRY.register("view_computer",
() -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, ViewComputerMenu::new));
} }
static class ArgumentTypes { static class ArgumentTypes {

View File

@ -18,7 +18,7 @@ import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.core.ServerContext; import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.metrics.basic.Aggregate; import dan200.computercraft.shared.computer.metrics.basic.Aggregate;
import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric; import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric;
import dan200.computercraft.shared.computer.metrics.basic.BasicComputerMetricsObserver; import dan200.computercraft.shared.computer.metrics.basic.BasicComputerMetricsObserver;
@ -268,7 +268,7 @@ public final class CommandComputerCraft {
@Override @Override
public AbstractContainerMenu createMenu(int id, Inventory player, Player entity) { public AbstractContainerMenu createMenu(int id, Inventory player, Player entity) {
return new ViewComputerMenu(id, player, computer); return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, player, p -> true, computer);
} }
}); });
return 1; return 1;

View File

@ -10,15 +10,19 @@ import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.api.detail.VanillaDetailRegistries; import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.lua.*; import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.Logging; import dan200.computercraft.core.Logging;
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.util.NBTUtil; import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,9 +35,10 @@ import java.util.*;
public class CommandAPI implements ILuaAPI { public class CommandAPI implements ILuaAPI {
private static final Logger LOG = LoggerFactory.getLogger(CommandAPI.class); private static final Logger LOG = LoggerFactory.getLogger(CommandAPI.class);
private final CommandComputerBlockEntity computer; private final ServerComputer computer;
private final OutputReceiver receiver = new OutputReceiver();
public CommandAPI(CommandComputerBlockEntity computer) { public CommandAPI(ServerComputer computer) {
this.computer = computer; this.computer = computer;
} }
@ -48,16 +53,15 @@ public class CommandAPI implements ILuaAPI {
private Object[] doCommand(String command) { private Object[] doCommand(String command) {
var server = computer.getLevel().getServer(); var server = computer.getLevel().getServer();
if (server == null || !server.isCommandBlockEnabled()) { if (!server.isCommandBlockEnabled()) {
return new Object[]{ false, createOutput("Command blocks disabled by server") }; return new Object[]{ false, createOutput("Command blocks disabled by server") };
} }
var commandManager = server.getCommands(); var commandManager = server.getCommands();
var receiver = computer.getReceiver();
try { try {
receiver.clearOutput(); receiver.clearOutput();
var state = new CommandState(); var state = new CommandState();
var source = computer.getSource().withCallback((success, x) -> { var source = getSource().withCallback((success, x) -> {
if (success) state.successes++; if (success) state.successes++;
}); });
commandManager.performPrefixedCommand(source, command); commandManager.performPrefixedCommand(source, command);
@ -142,7 +146,6 @@ public class CommandAPI implements ILuaAPI {
public final List<String> list(IArguments args) throws LuaException { public final List<String> list(IArguments args) throws LuaException {
var server = computer.getLevel().getServer(); var server = computer.getLevel().getServer();
if (server == null) return List.of();
CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot(); CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot();
for (var j = 0; j < args.count(); j++) { for (var j = 0; j < args.count(); j++) {
var name = args.getString(j); var name = args.getString(j);
@ -169,7 +172,7 @@ public class CommandAPI implements ILuaAPI {
@LuaFunction @LuaFunction
public final Object[] getBlockPosition() { public final Object[] getBlockPosition() {
// This is probably safe to do on the Lua thread. Probably. // This is probably safe to do on the Lua thread. Probably.
var pos = computer.getBlockPos(); var pos = computer.getPosition();
return new Object[]{ pos.getX(), pos.getY(), pos.getZ() }; return new Object[]{ pos.getX(), pos.getY(), pos.getZ() };
} }
@ -194,7 +197,6 @@ public class CommandAPI implements ILuaAPI {
* @throws LuaException If trying to get information about more than 4096 blocks. * @throws LuaException If trying to get information about more than 4096 blocks.
* @cc.since 1.76 * @cc.since 1.76
* @cc.changed 1.99 Added {@code dimension} argument. * @cc.changed 1.99 Added {@code dimension} argument.
*
* @cc.usage Print out all blocks in a cube around the computer. * @cc.usage Print out all blocks in a cube around the computer.
* *
* <pre>{@code * <pre>{@code
@ -228,7 +230,7 @@ public class CommandAPI implements ILuaAPI {
Math.max(minY, maxY), Math.max(minY, maxY),
Math.max(minZ, maxZ) Math.max(minZ, maxZ)
); );
if (world == null || !world.isInWorldBounds(min) || !world.isInWorldBounds(max)) { if (!world.isInWorldBounds(min) || !world.isInWorldBounds(max)) {
throw new LuaException("Co-ordinates out of range"); throw new LuaException("Co-ordinates out of range");
} }
@ -273,10 +275,9 @@ public class CommandAPI implements ILuaAPI {
} }
private Level getLevel(Optional<String> id) throws LuaException { private Level getLevel(Optional<String> id) throws LuaException {
var currentLevel = (ServerLevel) computer.getLevel(); var currentLevel = computer.getLevel();
if (currentLevel == null) throw new LuaException("No world exists");
if (!id.isPresent()) return currentLevel; if (id.isEmpty()) return currentLevel;
var dimensionId = ResourceLocation.tryParse(id.get()); var dimensionId = ResourceLocation.tryParse(id.get());
if (dimensionId == null) throw new LuaException("Invalid dimension name"); if (dimensionId == null) throw new LuaException("Invalid dimension name");
@ -286,4 +287,52 @@ public class CommandAPI implements ILuaAPI {
return level; return level;
} }
private CommandSourceStack getSource() {
var name = "@";
var label = computer.getLabel();
if (label != null) name = label;
return new CommandSourceStack(receiver,
Vec3.atCenterOf(computer.getPosition()), Vec2.ZERO,
computer.getLevel(), 2,
name, Component.literal(name),
computer.getLevel().getServer(), null
);
}
/**
* A {@link CommandSource} that consumes output messages and stores them to a list.
*/
private final class OutputReceiver implements CommandSource {
private final List<String> output = new ArrayList<>();
void clearOutput() {
output.clear();
}
List<String> copyOutput() {
return List.copyOf(output);
}
@Override
public void sendSystemMessage(Component textComponent) {
output.add(textComponent.getString());
}
@Override
public boolean acceptsSuccess() {
return true;
}
@Override
public boolean acceptsFailure() {
return true;
}
@Override
public boolean shouldInformAdmins() {
return computer.getLevel().getGameRules().getBoolean(GameRules.RULE_COMMANDBLOCKOUTPUT);
}
}
} }

View File

@ -82,7 +82,8 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
} }
public boolean isUsable(Player player) { public boolean isUsable(Player player) {
return BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName()) return getFamily().checkUsable(player)
&& BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
&& Container.stillValidBlockEntity(this, player, getInteractRange()); && Container.stillValidBlockEntity(this, player, getInteractRange());
} }

View File

@ -18,7 +18,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
* @param <T> The type of the computer block entity. * @param <T> The type of the computer block entity.
* @see dan200.computercraft.shared.computer.items.CommandComputerItem * @see dan200.computercraft.shared.computer.items.CommandComputerItem
*/ */
public class CommandComputerBlock<T extends CommandComputerBlockEntity> extends ComputerBlock<T> implements GameMasterBlock { public class CommandComputerBlock<T extends ComputerBlockEntity> extends ComputerBlock<T> implements GameMasterBlock {
private static final MapCodec<CommandComputerBlock<?>> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( private static final MapCodec<CommandComputerBlock<?>> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
BlockCodecs.propertiesCodec(), BlockCodecs.propertiesCodec(),
BlockCodecs.blockEntityCodec(x -> x.type) BlockCodecs.blockEntityCodec(x -> x.type)

View File

@ -1,114 +0,0 @@
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.computer.apis.CommandAPI;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.config.Config;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
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 java.util.ArrayList;
import java.util.List;
public class CommandComputerBlockEntity extends ComputerBlockEntity {
public class CommandReceiver implements CommandSource {
private final List<String> output = new ArrayList<>();
public void clearOutput() {
output.clear();
}
public List<String> copyOutput() {
return new ArrayList<>(output);
}
@Override
public void sendSystemMessage(Component textComponent) {
output.add(textComponent.getString());
}
@Override
public boolean acceptsSuccess() {
return true;
}
@Override
public boolean acceptsFailure() {
return true;
}
@Override
public boolean shouldInformAdmins() {
return getLevel().getGameRules().getBoolean(GameRules.RULE_COMMANDBLOCKOUTPUT);
}
}
private final CommandReceiver receiver;
public CommandComputerBlockEntity(BlockEntityType<? extends ComputerBlockEntity> type, BlockPos pos, BlockState state) {
super(type, pos, state, ComputerFamily.COMMAND);
receiver = new CommandReceiver();
}
public CommandReceiver getReceiver() {
return receiver;
}
public CommandSourceStack getSource() {
var computer = getServerComputer();
var name = "@";
if (computer != null) {
var label = computer.getLabel();
if (label != null) name = label;
}
return new CommandSourceStack(receiver,
Vec3.atCenterOf(worldPosition), Vec2.ZERO,
(ServerLevel) getLevel(), 2,
name, Component.literal(name),
getLevel().getServer(), null
);
}
@Override
protected ServerComputer createComputer(int id) {
var computer = super.createComputer(id);
computer.addAPI(new CommandAPI(this));
return computer;
}
@Override
public boolean isUsable(Player player) {
return isCommandUsable(player) && super.isUsable(player);
}
public static boolean isCommandUsable(Player player) {
var server = player.getServer();
if (server == null || !server.isCommandBlockEnabled()) {
player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
return false;
} else if (!canUseCommandBlock(player)) {
player.displayClientMessage(Component.translatable("advMode.notAllowed"), true);
return false;
}
return true;
}
private static boolean canUseCommandBlock(Player player) {
return Config.commandRequireCreative ? player.canUseGameMasterBlocks() : player.hasPermissions(2);
}
}

View File

@ -67,7 +67,7 @@ public class ComputerBlockEntity extends AbstractComputerBlockEntity {
@Nullable @Nullable
@Override @Override
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) { public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily()); return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer());
} }
public IPeripheral peripheral() { public IPeripheral peripheral() {

View File

@ -4,8 +4,45 @@
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.shared.config.Config;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
public enum ComputerFamily { public enum ComputerFamily {
NORMAL, NORMAL,
ADVANCED, ADVANCED,
COMMAND, COMMAND;
/**
* Check whether computers with this family can be used by the provided player.
* <p>
* This method is not pure. On failure, the method may send a message to the player telling them why they cannot
* interact with the computer.
*
* @param player The player trying to use a computer.
* @return Whether this computer family can be used.
*/
public boolean checkUsable(Player player) {
return switch (this) {
case NORMAL, ADVANCED -> true;
case COMMAND -> checkCommandUsable(player);
};
}
private static boolean checkCommandUsable(Player player) {
var server = player.getServer();
if (server == null || !server.isCommandBlockEnabled()) {
player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
return false;
} else if (!canUseCommandBlock(player)) {
player.displayClientMessage(Component.translatable("advMode.notAllowed"), true);
return false;
}
return true;
}
private static boolean canUseCommandBlock(Player player) {
return Config.commandRequireCreative ? player.canUseGameMasterBlocks() : player.hasPermissions(2);
}
} }

View File

@ -8,11 +8,12 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.WritableMount; import dan200.computercraft.api.filesystem.WritableMount;
import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.api.peripheral.WorkMonitor;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerEnvironment; import dan200.computercraft.core.computer.ComputerEnvironment;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.core.metrics.MetricsObserver;
import dan200.computercraft.shared.computer.apis.CommandAPI;
import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.computer.menu.ComputerMenu;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal; import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
import dan200.computercraft.shared.computer.terminal.TerminalState; import dan200.computercraft.shared.computer.terminal.TerminalState;
@ -23,6 +24,7 @@ import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
import dan200.computercraft.shared.network.server.ServerNetworking; import dan200.computercraft.shared.network.server.ServerNetworking;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -58,6 +60,8 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
computer = new Computer(context.computerContext(), this, terminal, computerID); computer = new Computer(context.computerContext(), this, terminal, computerID);
computer.setLabel(label); computer.setLabel(label);
if (family == ComputerFamily.COMMAND) addAPI(new CommandAPI(this));
} }
public ComputerFamily getFamily() { public ComputerFamily getFamily() {
@ -68,32 +72,20 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
return level; return level;
} }
public void setLevel(ServerLevel level) {
this.level = level;
}
public BlockPos getPosition() { public BlockPos getPosition() {
return position; return position;
} }
public void setPosition(BlockPos pos) { public void setPosition(ServerLevel level, BlockPos pos) {
position = new BlockPos(pos); this.level = level;
} position = pos.immutable();
public IAPIEnvironment getAPIEnvironment() {
return computer.getAPIEnvironment();
}
public Computer getComputer() {
return computer;
} }
protected void markTerminalChanged() { protected void markTerminalChanged() {
terminalChanged.set(true); terminalChanged.set(true);
} }
protected void tickServer() {
public void tickServer() {
ticksSincePing++; ticksSincePing++;
computer.tick(); computer.tick();
if (terminalChanged.getAndSet(false)) onTerminalChanged(); if (terminalChanged.getAndSet(false)) onTerminalChanged();
@ -111,10 +103,15 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
ticksSincePing = 0; ticksSincePing = 0;
} }
public boolean hasTimedOut() { boolean hasTimedOut() {
return ticksSincePing > 100; return ticksSincePing > 100;
} }
/**
* Get a bitmask returning which sides on the computer have changed, resetting the internal state.
*
* @return What sides on the computer have changed.
*/
public int pollAndResetChanges() { public int pollAndResetChanges() {
return computer.pollAndResetChanges(); return computer.pollAndResetChanges();
} }
@ -133,6 +130,17 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
ServerContext.get(level.getServer()).registry().remove(this); ServerContext.get(level.getServer()).registry().remove(this);
} }
/**
* Check whether this computer is usable by a player.
*
* @param player The player trying to use this computer.
* @return Whether this computer can be used.
*/
public final boolean checkUsable(Player player) {
return ServerContext.get(level.getServer()).registry().get(instanceUUID) == this
&& getFamily().checkUsable(player);
}
private void sendToAllInteracting(Function<AbstractContainerMenu, NetworkMessage<ClientNetworkContext>> createPacket) { private void sendToAllInteracting(Function<AbstractContainerMenu, NetworkMessage<ClientNetworkContext>> createPacket) {
var server = level.getServer(); var server = level.getServer();
@ -169,25 +177,21 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
@Override @Override
public void turnOn() { public void turnOn() {
// Turn on
computer.turnOn(); computer.turnOn();
} }
@Override @Override
public void shutdown() { public void shutdown() {
// Shutdown
computer.shutdown(); computer.shutdown();
} }
@Override @Override
public void reboot() { public void reboot() {
// Reboot
computer.reboot(); computer.reboot();
} }
@Override @Override
public void queueEvent(String event, @Nullable Object[] arguments) { public void queueEvent(String event, @Nullable Object[] arguments) {
// Queue event
computer.queueEvent(event, arguments); computer.queueEvent(event, arguments);
} }
@ -239,6 +243,10 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
return metrics; return metrics;
} }
public WorkMonitor getMainThreadMonitor() {
return computer.getMainThreadMonitor();
}
@Override @Override
public @Nullable WritableMount createRootMount() { public @Nullable WritableMount createRootMount() {
return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit); return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit);

View File

@ -59,7 +59,7 @@ public abstract class AbstractComputerMenu extends AbstractContainerMenu impleme
@Override @Override
public boolean stillValid(Player player) { public boolean stillValid(Player player) {
return canUse.test(player); return (computer == null || computer.checkUsable(player)) && canUse.test(player);
} }
public ComputerFamily getFamily() { public ComputerFamily getFamily() {

View File

@ -4,7 +4,6 @@
package dan200.computercraft.shared.computer.inventory; package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.container.InvisibleSlot; import dan200.computercraft.shared.container.InvisibleSlot;
import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ComputerContainerData;
@ -23,9 +22,9 @@ import java.util.function.Predicate;
public class ComputerMenuWithoutInventory extends AbstractComputerMenu { public class ComputerMenuWithoutInventory extends AbstractComputerMenu {
public ComputerMenuWithoutInventory( public ComputerMenuWithoutInventory(
MenuType<? extends AbstractComputerMenu> type, int id, Inventory player, Predicate<Player> canUse, MenuType<? extends AbstractComputerMenu> type, int id, Inventory player, Predicate<Player> canUse,
ServerComputer computer, ComputerFamily family ServerComputer computer
) { ) {
super(type, id, canUse, family, computer, null); super(type, id, canUse, computer.getFamily(), computer, null);
addSlots(player); addSlots(player);
} }

View File

@ -1,39 +0,0 @@
// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.network.container.ComputerContainerData;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
public class ViewComputerMenu extends ComputerMenuWithoutInventory {
public ViewComputerMenu(int id, Inventory player, ServerComputer computer) {
super(ModRegistry.Menus.VIEW_COMPUTER.get(), id, player, p -> canInteractWith(computer, p), computer, computer.getFamily());
}
public ViewComputerMenu(int id, Inventory player, ComputerContainerData data) {
super(ModRegistry.Menus.VIEW_COMPUTER.get(), id, player, data);
}
private static boolean canInteractWith(ServerComputer computer, Player player) {
// If this computer no longer exists then discard it.
if (ServerContext.get(computer.getLevel().getServer()).registry().get(computer.getInstanceUUID()) != computer) {
return false;
}
// If we're a command computer then ensure we're in creative
if (computer.getFamily() == ComputerFamily.COMMAND && !CommandComputerBlockEntity.isCommandUsable(player)) {
return false;
}
return true;
}
}

View File

@ -138,10 +138,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
} }
public synchronized void updateValues(@Nullable Entity entity, ItemStack stack, @Nullable IPocketUpgrade upgrade) { public synchronized void updateValues(@Nullable Entity entity, ItemStack stack, @Nullable IPocketUpgrade upgrade) {
if (entity != null) { if (entity != null) setPosition((ServerLevel) entity.level(), entity.blockPosition());
setLevel((ServerLevel) entity.getCommandSenderWorld());
setPosition(entity.blockPosition());
}
// If a new entity has picked it up then rebroadcast the terminal to them // If a new entity has picked it up then rebroadcast the terminal to them
if (entity != this.entity && entity instanceof ServerPlayer) markTerminalChanged(); if (entity != this.entity && entity instanceof ServerPlayer) markTerminalChanged();
@ -156,7 +153,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
} }
@Override @Override
public void tickServer() { protected void tickServer() {
super.tickServer(); super.tickServer();
// Find any players which have gone missing and remove them from the tracking list. // Find any players which have gone missing and remove them from the tracking list.

View File

@ -45,12 +45,12 @@ public class PocketComputerMenuProvider implements MenuProvider {
@Override @Override
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player entity) { public AbstractContainerMenu createMenu(int id, Inventory inventory, Player entity) {
return new ComputerMenuWithoutInventory( return new ComputerMenuWithoutInventory(
isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.POCKET_COMPUTER.get(), id, inventory, isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.COMPUTER.get(), id, inventory,
p -> { p -> {
var stack = p.getItemInHand(hand); var stack = p.getItemInHand(hand);
return stack.getItem() == item && PocketComputerItem.getServerComputer(assertNonNull(entity.level().getServer()), stack) == computer; return stack.getItem() == item && PocketComputerItem.getServerComputer(assertNonNull(entity.level().getServer()), stack) == computer;
}, },
computer, item.getFamily() computer
); );
} }
} }

View File

@ -53,10 +53,9 @@ public class PocketComputerItem extends Item implements IMedia {
this.family = family; this.family = family;
} }
private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerComputer computer) { private boolean tick(ItemStack stack, Entity entity, PocketServerComputer computer) {
var upgrade = getUpgrade(stack); var upgrade = getUpgrade(stack);
computer.setLevel((ServerLevel) world);
computer.updateValues(entity, stack, upgrade); computer.updateValues(entity, stack, upgrade);
var changed = false; var changed = false;
@ -87,7 +86,7 @@ public class PocketComputerItem extends Item implements IMedia {
var computer = createServerComputer((ServerLevel) world, entity, inventory, stack); var computer = createServerComputer((ServerLevel) world, entity, inventory, stack);
computer.keepAlive(); computer.keepAlive();
var changed = tick(stack, world, entity, computer); var changed = tick(stack, entity, computer);
if (changed && inventory != null) inventory.setChanged(); if (changed && inventory != null) inventory.setChanged();
} }
@ -97,7 +96,7 @@ public class PocketComputerItem extends Item implements IMedia {
if (level.isClientSide || level.getServer() == null) return false; if (level.isClientSide || level.getServer() == null) return false;
var computer = getServerComputer(level.getServer(), stack); var computer = getServerComputer(level.getServer(), stack);
if (computer != null && tick(stack, entity.level(), entity, computer)) entity.setItem(stack.copy()); if (computer != null && tick(stack, entity, computer)) entity.setItem(stack.copy());
return false; return false;
} }
@ -175,7 +174,7 @@ public class PocketComputerItem extends Item implements IMedia {
if (inventory != null) inventory.setChanged(); if (inventory != null) inventory.setChanged();
} }
computer.setLevel(level);
return computer; return computer;
} }

View File

@ -25,7 +25,7 @@ public class PocketModemPeripheral extends WirelessModemPeripheral {
void setLocation(IPocketAccess access) { void setLocation(IPocketAccess access) {
var entity = access.getEntity(); var entity = access.getEntity();
if (entity != null) { if (entity != null) {
level = entity.getCommandSenderWorld(); level = entity.level();
position = entity.getEyePosition(1); position = entity.getEyePosition(1);
} }
} }

View File

@ -9,8 +9,9 @@ import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.turtle.TurtleCommand; import dan200.computercraft.api.turtle.TurtleCommand;
import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.metrics.Metrics; import dan200.computercraft.core.metrics.Metrics;
import dan200.computercraft.core.metrics.MetricsObserver;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods; import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
import dan200.computercraft.shared.turtle.core.*; import dan200.computercraft.shared.turtle.core.*;
@ -64,11 +65,11 @@ import java.util.Optional;
* @cc.since 1.3 * @cc.since 1.3
*/ */
public class TurtleAPI implements ILuaAPI { public class TurtleAPI implements ILuaAPI {
private final IAPIEnvironment environment; private final MetricsObserver metrics;
private final TurtleAccessInternal turtle; private final TurtleAccessInternal turtle;
public TurtleAPI(IAPIEnvironment environment, TurtleAccessInternal turtle) { public TurtleAPI(ServerComputer computer, TurtleAccessInternal turtle) {
this.environment = environment; this.metrics = computer.getMetrics();
this.turtle = turtle; this.turtle = turtle;
} }
@ -78,7 +79,7 @@ public class TurtleAPI implements ILuaAPI {
} }
private MethodResult trackCommand(TurtleCommand command) { private MethodResult trackCommand(TurtleCommand command) {
environment.observe(Metrics.TURTLE_OPS); metrics.observe(Metrics.TURTLE_OPS);
return turtle.executeCommand(command); return turtle.executeCommand(command);
} }
@ -169,7 +170,7 @@ public class TurtleAPI implements ILuaAPI {
*/ */
@LuaFunction @LuaFunction
public final MethodResult dig(Optional<TurtleSide> side) { public final MethodResult dig(Optional<TurtleSide> side) {
environment.observe(Metrics.TURTLE_OPS); metrics.observe(Metrics.TURTLE_OPS);
return trackCommand(TurtleToolCommand.dig(InteractDirection.FORWARD, side.orElse(null))); return trackCommand(TurtleToolCommand.dig(InteractDirection.FORWARD, side.orElse(null)));
} }
@ -184,7 +185,7 @@ public class TurtleAPI implements ILuaAPI {
*/ */
@LuaFunction @LuaFunction
public final MethodResult digUp(Optional<TurtleSide> side) { public final MethodResult digUp(Optional<TurtleSide> side) {
environment.observe(Metrics.TURTLE_OPS); metrics.observe(Metrics.TURTLE_OPS);
return trackCommand(TurtleToolCommand.dig(InteractDirection.UP, side.orElse(null))); return trackCommand(TurtleToolCommand.dig(InteractDirection.UP, side.orElse(null)));
} }
@ -199,7 +200,7 @@ public class TurtleAPI implements ILuaAPI {
*/ */
@LuaFunction @LuaFunction
public final MethodResult digDown(Optional<TurtleSide> side) { public final MethodResult digDown(Optional<TurtleSide> side) {
environment.observe(Metrics.TURTLE_OPS); metrics.observe(Metrics.TURTLE_OPS);
return trackCommand(TurtleToolCommand.dig(InteractDirection.DOWN, side.orElse(null))); return trackCommand(TurtleToolCommand.dig(InteractDirection.DOWN, side.orElse(null)));
} }

View File

@ -84,7 +84,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
getFamily(), Config.turtleTermWidth, getFamily(), Config.turtleTermWidth,
Config.turtleTermHeight Config.turtleTermHeight
); );
computer.addAPI(new TurtleAPI(computer.getAPIEnvironment(), brain)); computer.addAPI(new TurtleAPI(computer, brain));
brain.setupComputer(computer); brain.setupComputer(computer);
return computer; return computer;
} }

View File

@ -266,8 +266,7 @@ public class TurtleBrain implements TurtleAccessInternal {
newTurtle.transferStateFrom(oldOwner); newTurtle.transferStateFrom(oldOwner);
var computer = newTurtle.createServerComputer(); var computer = newTurtle.createServerComputer();
computer.setLevel((ServerLevel) world); computer.setPosition((ServerLevel) world, pos);
computer.setPosition(pos);
// Remove the old turtle // Remove the old turtle
oldWorld.removeBlock(oldPos, false); oldWorld.removeBlock(oldPos, false);
@ -586,7 +585,7 @@ public class TurtleBrain implements TurtleAccessInternal {
// If we've got a computer, ensure that we're allowed to perform work. // If we've got a computer, ensure that we're allowed to perform work.
var computer = owner.getServerComputer(); var computer = owner.getServerComputer();
if (computer != null && !computer.getComputer().getMainThreadMonitor().canWork()) return; if (computer != null && !computer.getMainThreadMonitor().canWork()) return;
// Pull a new command // Pull a new command
var nextCommand = commandQueue.poll(); var nextCommand = commandQueue.poll();
@ -599,7 +598,7 @@ public class TurtleBrain implements TurtleAccessInternal {
// Dispatch the callback // Dispatch the callback
if (computer == null) return; if (computer == null) return;
computer.getComputer().getMainThreadMonitor().trackWork(end - start, TimeUnit.NANOSECONDS); computer.getMainThreadMonitor().trackWork(end - start, TimeUnit.NANOSECONDS);
var callbackID = nextCommand.callbackID(); var callbackID = nextCommand.callbackID();
if (callbackID < 0) return; if (callbackID < 0) return;

View File

@ -60,7 +60,7 @@ public final class TurtlePlayer {
var player = brain.cachedPlayer; var player = brain.cachedPlayer;
if (player == null || player.player.getGameProfile() != getProfile(access.getOwningPlayer()) if (player == null || player.player.getGameProfile() != getProfile(access.getOwningPlayer())
|| player.player.getCommandSenderWorld() != access.getLevel()) { || player.player.level() != access.getLevel()) {
player = brain.cachedPlayer = create(brain); player = brain.cachedPlayer = create(brain);
} else { } else {
player.setState(access); player.setState(access);

View File

@ -27,7 +27,7 @@
"dan200.computercraft.data.FabricDataGenerators" "dan200.computercraft.data.FabricDataGenerators"
], ],
"jei_mod_plugin": [ "jei_mod_plugin": [
"dan200.computercraft.shared.integration.jei.JEIComputerCraft" "dan200.computercraft.client.integration.jei.JEIComputerCraft"
], ],
"rei_client": [ "rei_client": [
"dan200.computercraft.client.integration.rei.REIComputerCraft" "dan200.computercraft.client.integration.rei.REIComputerCraft"