Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import dev.propulsionteam.computed.graph.LuaGraphScheduler;
import dev.propulsionteam.computed.lua.endpoint.BuiltinEndpointHost;
import dev.propulsionteam.computed.lua.endpoint.BuiltinWidget;
import dev.propulsionteam.computed.lua.endpoint.EndpointResult;
import dev.propulsionteam.computed.lua.endpoint.ServerEndpointExecutor;
import dev.propulsionteam.computed.menu.ComputerPeripheralMenu;
import dev.propulsionteam.computed.network.ComputerEditPolicy;
import dev.propulsionteam.computed.network.ComputedNetworking;
Expand All @@ -31,6 +33,9 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
Expand All @@ -53,7 +58,8 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;

public class ComputerBlockEntity extends BaseContainerBlockEntity implements BuiltinEndpointHost {
public class ComputerBlockEntity extends BaseContainerBlockEntity
implements BuiltinEndpointHost, ServerEndpointExecutor {
public static final int CONTAINER_SIZE = 9;
public static final String PROGRAM_TAG = "ComputedProgram";

Expand Down Expand Up @@ -338,7 +344,11 @@ public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider registries) {

@Override
public double worldTime() {
return level == null ? 0 : level.getDayTime();
if (!(level instanceof ServerLevel serverLevel) || isRemoved()) {
return 0;
}
requireServerThread(serverLevel);
return serverLevel.getDayTime();
}

@Override
Expand All @@ -357,42 +367,85 @@ public double[] rotation() {

@Override
public int redstoneInput(String face) {
if (!(level instanceof ServerLevel serverLevel) || isRemoved()) {
return 0;
}
requireServerThread(serverLevel);
Direction worldFace = worldFace(face);
if (worldFace == null || level == null || level.isClientSide) {
if (worldFace == null) {
return 0;
}
BlockPos neighbor = worldPosition.relative(worldFace);
return level.getSignal(neighbor, worldFace);
return serverLevel.getSignal(neighbor, worldFace);
}

@Override
public int comparatorInput(String face) {
if (!(level instanceof ServerLevel serverLevel) || isRemoved()) {
return 0;
}
requireServerThread(serverLevel);
Direction worldFace = worldFace(face);
if (worldFace == null || level == null || level.isClientSide) {
if (worldFace == null) {
return 0;
}
BlockPos neighbor = worldPosition.relative(worldFace);
BlockState target = level.getBlockState(neighbor);
BlockState target = serverLevel.getBlockState(neighbor);
return target.hasAnalogOutputSignal()
? target.getAnalogOutputSignal(level, neighbor)
: level.getSignal(neighbor, worldFace);
? target.getAnalogOutputSignal(serverLevel, neighbor)
: serverLevel.getSignal(neighbor, worldFace);
}

@Override
public boolean blockPresent(String face) {
if (!(level instanceof ServerLevel serverLevel) || isRemoved()) {
return false;
}
requireServerThread(serverLevel);
Direction worldFace = worldFace(face);
return worldFace != null
&& level != null
&& !level.isClientSide
&& !level.getBlockState(worldPosition.relative(worldFace)).isAir();
&& !serverLevel.getBlockState(worldPosition.relative(worldFace)).isAir();
}

@Override
public void redstoneOutput(String face, int power) {
Level currentLevel = level;
if (!(currentLevel instanceof ServerLevel serverLevel) || isRemoved()) {
return;
}

MinecraftServer server = serverLevel.getServer();
LuaGraphScheduler expectedScheduler = scheduler;
if (!server.isSameThread()) {
server.execute(() -> applyRedstoneOutput(
serverLevel,
expectedScheduler,
face,
power));
return;
}

applyRedstoneOutput(serverLevel, expectedScheduler, face, power);
}

private void applyRedstoneOutput(
ServerLevel expectedLevel,
LuaGraphScheduler expectedScheduler,
String face,
int power) {
requireServerThread(expectedLevel);
if (isRemoved()
|| level != expectedLevel
|| scheduler != expectedScheduler
|| expectedLevel.getBlockEntity(worldPosition) != this) {
return;
}

Direction worldFace = worldFace(face);
if (worldFace == null || level == null || level.isClientSide) {
if (worldFace == null) {
return;
}

int clamped = net.minecraft.util.Mth.clamp(power, 0, 15);
if (emittedRedstone[worldFace.ordinal()] == clamped) {
return;
Expand All @@ -412,16 +465,10 @@ private void flushRedstoneUpdate() {

@Override
public void showWidgets(String target, List<BuiltinWidget> definitions) {
if (level == null || level.isClientSide) {
return;
}
MinecraftServer server = level.getServer();
if (server != null && !server.isSameThread()) {
String queuedTarget = target;
List<BuiltinWidget> queuedDefinitions = List.copyOf(definitions);
server.execute(() -> applyWidgets(queuedTarget, queuedDefinitions));
if (!(level instanceof ServerLevel serverLevel) || isRemoved()) {
return;
}
requireServerThread(serverLevel);
applyWidgets(target, definitions);
}

Expand Down Expand Up @@ -454,12 +501,14 @@ private void applyWidgets(String target, List<BuiltinWidget> definitions) {
public void runCommand(String commandText) {
if (commandText == null
|| commandText.isBlank()
|| !(level instanceof ServerLevel serverLevel)) {
|| !(level instanceof ServerLevel serverLevel)
|| isRemoved()) {
return;
}
requireServerThread(serverLevel);
MinecraftServer server = serverLevel.getServer();
String command = commandText.startsWith("/") ? commandText.substring(1) : commandText;
if (server == null || command.isBlank()) {
if (command.isBlank()) {
return;
}
Vec3 center = Vec3.atCenterOf(worldPosition);
Expand All @@ -471,6 +520,41 @@ public void runCommand(String commandText) {
server.getCommands().performPrefixedCommand(source, command);
}

@Override
public CompletionStage<EndpointResult> submitServerEndpoint(
Callable<EndpointResult> endpointCall) {
if (!(level instanceof ServerLevel expectedLevel) || isRemoved()) {
return CompletableFuture.failedFuture(
new IllegalStateException("Computer is not available"));
}

MinecraftServer server = expectedLevel.getServer();
LuaGraphScheduler expectedScheduler = scheduler;
CompletableFuture<EndpointResult> result = new CompletableFuture<>();
try {
server.execute(() -> {
if (isRemoved()
|| level != expectedLevel
|| scheduler != expectedScheduler
|| expectedLevel.getBlockEntity(worldPosition) != this) {
result.completeExceptionally(
new IllegalStateException(
"Computer or program changed before endpoint execution"));
return;
}

try {
result.complete(endpointCall.call());
} catch (Exception exception) {
result.completeExceptionally(exception);
}
});
} catch (RuntimeException exception) {
result.completeExceptionally(exception);
}
return result;
}

private LuaGraphScheduler ensureScheduler() {
if (scheduler == null) {
scheduler = new LuaGraphScheduler(program, getOrCreateUuid(), this);
Expand Down Expand Up @@ -562,9 +646,19 @@ private static UUID stableGraphId(BlockPos pos) {
}

public Direction worldFaceForEndpoint(String name) {
if (level instanceof ServerLevel serverLevel) {
requireServerThread(serverLevel);
}
return worldFace(name);
}

private static void requireServerThread(ServerLevel serverLevel) {
if (!serverLevel.getServer().isSameThread()) {
throw new IllegalStateException(
"Computer world access attempted outside the server thread");
}
}

private Direction worldFace(String name) {
if (name == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private static void registerEndpoints() {
ComputedEndpoints.register("computercraft:peripheral", endpoint -> endpoint.method(
"methods",
EndpointSignature.of(List.of(), List.of(EndpointType.TABLE)),
EndpointPolicy.computerThread(false, false),
EndpointPolicy.serverThread(false, false),
ComputerCraftIntegration::peripheralMethods,
null,
"Lists methods exposed by the adjacent CC peripheral.")
Expand All @@ -116,11 +116,7 @@ private static void registerEndpoints() {
List.of(EndpointType.STRING),
List.of(EndpointType.TABLE),
true),
new EndpointPolicy(
EndpointPolicy.ExecutionSide.SERVER_THREAD,
true,
true,
false),
EndpointPolicy.serverThread(true, false),
ComputerCraftIntegration::callPeripheral,
null,
"Calls an adjacent CC peripheral method and resumes yielded results."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ public static void register() {
ComputedEndpoints.register("create:kinetic", endpoint -> endpoint.method(
"speed",
EndpointSignature.of(List.of(), List.of(EndpointType.NUMBER)),
EndpointPolicy.computerThread(false, true),
EndpointPolicy.serverThread(false, true),
invocation -> number(kinetic(invocation, Metric.SPEED)),
ignored -> number(0),
"Returns the adjacent Create kinetic speed.")
.method(
"stress",
EndpointSignature.of(List.of(), List.of(EndpointType.NUMBER)),
EndpointPolicy.computerThread(false, true),
EndpointPolicy.serverThread(false, true),
invocation -> number(kinetic(invocation, Metric.STRESS)),
ignored -> number(0),
"Returns the adjacent Create kinetic stress.")
.method(
"capacity",
EndpointSignature.of(List.of(), List.of(EndpointType.NUMBER)),
EndpointPolicy.computerThread(false, true),
EndpointPolicy.serverThread(false, true),
invocation -> number(kinetic(invocation, Metric.CAPACITY)),
ignored -> number(0),
"Returns the adjacent Create kinetic capacity."));
Expand All @@ -50,7 +50,7 @@ public static void register() {
EndpointSignature.of(
List.of(EndpointType.STRING, EndpointType.STRING),
List.of(EndpointType.NUMBER)),
EndpointPolicy.computerThread(false, false),
EndpointPolicy.serverThread(false, false),
CreateIntegration::receive,
null,
"Reads a Create redstone-link frequency pair.")
Expand All @@ -59,7 +59,7 @@ public static void register() {
EndpointSignature.of(
List.of(EndpointType.STRING, EndpointType.STRING, EndpointType.NUMBER),
List.of()),
EndpointPolicy.computerThread(true, false),
EndpointPolicy.serverThread(true, false),
CreateIntegration::transmit,
null,
"Writes a Create redstone-link frequency pair."));
Expand Down
Loading
Loading