This commit is contained in:
2026-03-12 11:59:28 -07:00
parent 4b3aa6e9b1
commit d36d84d188
21 changed files with 769 additions and 54 deletions

View File

@@ -28,7 +28,13 @@ public class Blocks {
//quantum processor
public static final Block QUANTUM_PROCESSOR_BLOCK = registerBlock("quantum_processor",new QuantumProcessorBlock(AbstractBlock.Settings.create()));
public static final Block BRAIN_SCANNER_BLOCK = registerBlock("brain_scanner",new BrainScannerBlock(AbstractBlock.Settings.create()));
public static final Block HYPERSPACE_NEURAL_TENSOR_PROCESSOR_BLOCK = registerBlock("hyperspace_neural_tensor_processor",new HyperSpaceNeuralTensorProcessorBlock(AbstractBlock.Settings.create()));
public static void register() {
registerBlockItem("quantum_processor", QUANTUM_PROCESSOR_BLOCK);
registerBlockItem("brain_scanner", BRAIN_SCANNER_BLOCK);
registerBlockItem("hyperspace_neural_tensor_processor", HYPERSPACE_NEURAL_TENSOR_PROCESSOR_BLOCK);
}
}

View File

@@ -0,0 +1,35 @@
package org.ruffles.simulatedworlds.Blocks;
import com.mojang.serialization.MapCodec;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
import org.jetbrains.annotations.Nullable;
import org.ruffles.simulatedworlds.Entities.BlockEntities;
import org.ruffles.simulatedworlds.Entities.BrainScannerEntity;
import org.ruffles.simulatedworlds.Entities.HyperSpaceNeuralTensorProcessorEntity;
import org.ruffles.simulatedworlds.Entities.QuantumProcessorBlockEntity;
public class BrainScannerBlock extends BlockWithEntity {
protected BrainScannerBlock(Settings settings) {
super(settings);
}
@Override
protected MapCodec<? extends BlockWithEntity> getCodec() {
return null;
}
@Override
protected BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}
@Override
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BrainScannerEntity(pos,state);
}
}

View File

@@ -0,0 +1,46 @@
package org.ruffles.simulatedworlds.Blocks;
import com.mojang.serialization.MapCodec;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
import org.jetbrains.annotations.Nullable;
import org.ruffles.simulatedworlds.Entities.BlockEntities;
import org.ruffles.simulatedworlds.Entities.HyperSpaceNeuralTensorProcessorEntity;
import org.ruffles.simulatedworlds.Entities.QuantumProcessorBlockEntity;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.SimulationManager;
import java.util.Optional;
public class HyperSpaceNeuralTensorProcessorBlock extends BlockWithEntity {
protected HyperSpaceNeuralTensorProcessorBlock(Settings settings) {
super(settings);
}
@Override
protected MapCodec<? extends BlockWithEntity> getCodec() {
return null;
}
@Override
protected BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}
@Override
public void onBroken(WorldAccess world, BlockPos pos, BlockState state) {
super.onBroken(world, pos, state);
Optional<HyperSpaceNeuralTensorProcessorEntity> entity = world.getBlockEntity(pos, BlockEntities.HYPERSPACE_NEURAL_TENSOR_PROCESSOR_ENTITY);
entity.ifPresent(hyperSpaceNeuralTensorProcessorEntity -> SimulationManager.detachPlayer(hyperSpaceNeuralTensorProcessorEntity.player_hash));
}
@Override
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new HyperSpaceNeuralTensorProcessorEntity(pos,state);
}
}

View File

@@ -3,30 +3,60 @@ package org.ruffles.simulatedworlds.DataClasses;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.server.network.ServerPlayerEntity;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.Simulatedworlds;
import java.util.Optional;
import java.util.UUID;
import static java.util.Optional.empty;
import static org.ruffles.simulatedworlds.Simulatedworlds.LOGGER;
public class PlayerData {
private UUID playerUUID;
private long seed;
private Optional<UUID> uploadID = empty();
private Optional<UUID> simid = empty();
public PlayerData() {}
public PlayerData(PlayerEntity player) {
public PlayerData(PlayerEntity player, long seed) {
playerUUID = player.getGameProfile().getId();
this.seed = seed;
}
public NbtCompound writeNbt(NbtCompound nbt) {
nbt.putUuid("user_uuid", playerUUID);
nbt.putLong("user_seed",seed);
uploadID.ifPresent(uuid -> nbt.putUuid("upload_uuid", uuid));
simid.ifPresent(uuid -> nbt.putUuid("sim_uuid", uuid));
return nbt;
}
public void readNbt(NbtCompound nbt) {
playerUUID = nbt.getUuid("user_uuid");
uploadID = Optional.ofNullable(nbt.getUuid("upload_uuid"));
LOGGER.info("registered player with UUID: {}", playerUUID);
seed = nbt.getLong("user_seed");
if (nbt.containsUuid("upload_uuid")) {
uploadID = Optional.of(nbt.getUuid("upload_uuid"));
} else {
uploadID = Optional.empty();
}
if (nbt.containsUuid("sim_uuid")) {
uploadID = Optional.of(nbt.getUuid("sim_uuid"));
} else {
uploadID = Optional.empty();
}
}
public UUID getSimID() {
return simid.orElse(null);
}
public void setSimID(UUID simid) {
this.simid=Optional.ofNullable(simid);
PersistedBrainData.get().markDirty();
}
public static PlayerData fromNbt(NbtCompound nbt) {
@@ -37,6 +67,15 @@ public class PlayerData {
public void setUploadID(UUID uploadID) {
this.uploadID = Optional.of(uploadID);
PersistedBrainData.get().markDirty();
}
public ServerPlayerEntity getPlayer() {
return Simulatedworlds.SERVER.getPlayerManager().getPlayer(playerUUID);
}
public UUID getPlayerUUID() {
return playerUUID;
}
public Optional<UUID> getUploadID() {
@@ -45,5 +84,10 @@ public class PlayerData {
public void clearUploadID() {
this.uploadID = empty();
PersistedBrainData.get().markDirty();
}
public long getSeed() {
return seed;
}
}

View File

@@ -0,0 +1,61 @@
package org.ruffles.simulatedworlds.DataClasses;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.visitor.NbtElementVisitor;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedSimulationData;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import static org.ruffles.simulatedworlds.Simulatedworlds.LOGGER;
public class SimulationData {
private static HashMap<UUID,NbtCompound> playerData;
private static UUID simid;
public SimulationData() {
playerData = new HashMap<>();
simid = UUID.randomUUID();
}
public NbtCompound writeNbt(NbtCompound nbt) {
nbt.putUuid("simid", simid);
NbtCompound playerDataCompound = new NbtCompound();
for (Map.Entry<UUID, NbtCompound> entry : playerData.entrySet()) {
playerDataCompound.put(entry.getKey().toString(),entry.getValue());
}
nbt.put("player_data",playerDataCompound);
return nbt;
}
public void readNbt(NbtCompound nbt) {
if (nbt.containsUuid("simid")) {
simid = nbt.getUuid("simid");
}
if (nbt.contains("player_data", NbtElement.COMPOUND_TYPE)) {
NbtCompound playerDataCompound = nbt.getCompound("player_data");
for (String key : playerDataCompound.getKeys()) {
playerData.put(UUID.fromString(key),playerDataCompound.getCompound(key));
}
}
}
public void setPlayerData(UUID player_uuid, NbtCompound data) {
playerData.put(player_uuid,data);
PersistedSimulationData.get().markDirty();
}
public NbtCompound getPlayerData(UUID player_uuid) {
return playerData.get(player_uuid);
}
public static SimulationData fromNbt(NbtCompound nbt) {
SimulationData simulationData = new SimulationData();
simulationData.readNbt(nbt);
return simulationData;
}
}

View File

@@ -10,9 +10,14 @@ import org.ruffles.simulatedworlds.Blocks.Blocks;
import org.ruffles.simulatedworlds.Simulatedworlds;
public class BlockEntities {
public static final BlockEntityType<QuantumProcessorBlockEntity> QUANTUM_PROCESSOR_BLOCK_ENTITY =
public static final BlockEntityType<QuantumProcessorBlockEntity> QUANTUM_PROCESSOR_BLOCK_ENTITY =
register("quantum_processor", QuantumProcessorBlockEntity::new, Blocks.QUANTUM_PROCESSOR_BLOCK);
public static final BlockEntityType<HyperSpaceNeuralTensorProcessorEntity> HYPERSPACE_NEURAL_TENSOR_PROCESSOR_ENTITY =
register("hyperspace_neural_tensor_processor", HyperSpaceNeuralTensorProcessorEntity::new, Blocks.HYPERSPACE_NEURAL_TENSOR_PROCESSOR_BLOCK);
public static final BlockEntityType<BrainScannerEntity> BRAIN_SCANNER_ENTITY =
register("brain_scanner", BrainScannerEntity::new, Blocks.BRAIN_SCANNER_BLOCK);
private static <T extends BlockEntity> BlockEntityType<T> register(String name,
BlockEntityType.BlockEntityFactory<? extends T> entityFactory,
Block... blocks) {

View File

@@ -0,0 +1,11 @@
package org.ruffles.simulatedworlds.Entities;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
public class BrainScannerEntity extends BlockEntity {
public BrainScannerEntity(BlockPos pos, BlockState state) {
super(BlockEntities.BRAIN_SCANNER_ENTITY, pos, state);
}
}

View File

@@ -0,0 +1,41 @@
package org.ruffles.simulatedworlds.Entities;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.math.BlockPos;
import org.ruffles.simulatedworlds.Simulatedworlds;
import java.util.UUID;
public class HyperSpaceNeuralTensorProcessorEntity extends BlockEntity {
public HyperSpaceNeuralTensorProcessorEntity(BlockPos pos, BlockState state) {
super(BlockEntities.HYPERSPACE_NEURAL_TENSOR_PROCESSOR_ENTITY, pos, state);
block_uuid = UUID.randomUUID();
}
public String player_hash;
public UUID block_uuid;
@Override
protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
if (nbt.contains("player_hash", NbtElement.STRING_TYPE)) {
player_hash = nbt.getString("player_hash");
Simulatedworlds.LOGGER.info("HyperSpaceNeuralTensorProcessor registered: {}",player_hash);
}
if (nbt.contains("block_uuid", NbtElement.INT_ARRAY_TYPE)) {
block_uuid = nbt.getUuid("block_uuid");
}
super.readNbt(nbt, registryLookup);
}
@Override
protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
super.writeNbt(nbt, registryLookup);
if (player_hash != null) {
nbt.putUuid("block_uuid",block_uuid);
nbt.putString("player_hash",player_hash);
}
}
}

View File

@@ -3,10 +3,39 @@ package org.ruffles.simulatedworlds.Entities;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.math.BlockPos;
import org.ruffles.simulatedworlds.PersistentStates.PersistedSimulationData;
import org.ruffles.simulatedworlds.SimulationManager;
import java.util.UUID;
public class QuantumProcessorBlockEntity extends BlockEntity {
public QuantumProcessorBlockEntity( BlockPos pos, BlockState state) {
super(BlockEntities.QUANTUM_PROCESSOR_BLOCK_ENTITY, pos, state);
simid = UUID.randomUUID();
}
public UUID simid;
@Override
protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
nbt.putUuid("sim_uuid",simid);
super.writeNbt(nbt, registryLookup);
}
@Override
protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
if (nbt.containsUuid("sim_uuid")) {
simid = nbt.getUuid("sim_uuid");
}
super.readNbt(nbt, registryLookup);
}
public void registerSim() {
if (!PersistedSimulationData.get().simulationExists(simid)) {
PersistedSimulationData.get().registerSimulation(simid);
}
}
}

View File

@@ -0,0 +1,30 @@
package org.ruffles.simulatedworlds.Mixins;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.network.ServerPlayerEntity;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import org.ruffles.simulatedworlds.DataClasses.SimulationData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedSimulationData;
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.CallbackInfoReturnable;
@Mixin(Entity.class)
public class PlayerMixin {
@Inject(at = @At("RETURN"),method = "writeNbt")
public void writeNbt(NbtCompound nbt, CallbackInfoReturnable<NbtCompound> cir) {
Entity entity = (Entity)(Object) this;
if (entity instanceof ServerPlayerEntity player) {
PlayerData playerData = PersistedBrainData.get().getPlayerFromUUID(player.getUuid());
if (playerData != null && playerData.getSimID() != null) {
SimulationData simdata = PersistedSimulationData.get().getSimData(playerData.getSimID());
simdata.setPlayerData(player.getUuid(), cir.getReturnValue());
PersistedSimulationData.get().markDirty();
}
}
}
}

View File

@@ -0,0 +1,72 @@
package org.ruffles.simulatedworlds.Peripherals;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.LuaValues;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.util.LuaUtil;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.Box;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import org.ruffles.simulatedworlds.Entities.BrainScannerEntity;
import org.ruffles.simulatedworlds.SimulationManager;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
public class BrainScannerPeripheral implements IPeripheral {
private final BrainScannerEntity brainScanner;
private Supplier<Optional<Byte>> playerBrain;
private int scanned = 0;
public BrainScannerPeripheral(BrainScannerEntity brainScanner) {
this.brainScanner = brainScanner;
}
@Override
public @NotNull String getType() {
return "brain_scanner";
}
@LuaFunction
public final MethodResult start_scan() {
if (brainScanner.getWorld() == null) { return MethodResult.of(false); }
List<PlayerEntity> players = brainScanner.getWorld().getEntitiesByClass(PlayerEntity.class, Box.enclosing(brainScanner.getPos().down(),brainScanner.getPos().down().down()),(e) -> true);
if (players.size() == 1) {
scanned = 0;
playerBrain = SimulationManager.scanPlayer(players.getFirst());
return MethodResult.of(true);
}
return MethodResult.of(false);
}
@LuaFunction
public final MethodResult stop_scan() {
if (scanned > 500) {
return MethodResult.of(false, "Unable to Stop, Stopping would cause permanent brain damage.");
} else {
return MethodResult.of(true);
}
}
@LuaFunction
public final MethodResult scan_byte() {
if (playerBrain != null) {
Optional<Byte> data = playerBrain.get();
if (data.isPresent()) {
scanned += 1;
return MethodResult.of(((double)data.get())+128);
} else {
playerBrain = null;
}
}
return MethodResult.of();
}
@Override
public boolean equals(@Nullable IPeripheral other) {
return other instanceof BrainScannerPeripheral o && brainScanner == o.brainScanner;
}
}

View File

@@ -0,0 +1,115 @@
package org.ruffles.simulatedworlds.Peripherals;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import org.ruffles.simulatedworlds.Entities.HyperSpaceNeuralTensorProcessorEntity;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.SimulationManager;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.UUID;
import static org.ruffles.simulatedworlds.Simulatedworlds.LOGGER;
public class HyperSpaceNeuralTensorProcessorPeripheral implements IPeripheral {
private final HyperSpaceNeuralTensorProcessorEntity hyperSpaceNeuralTensorProcessor;
private MessageDigest hasher;
public HyperSpaceNeuralTensorProcessorPeripheral(HyperSpaceNeuralTensorProcessorEntity hyperSpaceNeuralTensorProcessor) {
this.hyperSpaceNeuralTensorProcessor = hyperSpaceNeuralTensorProcessor;
}
@Override
public @NotNull String getType() {
return "hyperspace_neural_tensor_processor";
}
@LuaFunction
public final MethodResult start_upload() {
if (hasher != null) {return MethodResult.of(false, "Already uploading.");}
if (hyperSpaceNeuralTensorProcessor.player_hash != null) {return MethodResult.of(false, "Player already exists in processor.");}
hasher = SimulationManager.hash();
return MethodResult.of(hasher != null);
}
@LuaFunction
public final boolean has_player() {
return hyperSpaceNeuralTensorProcessor.player_hash != null;
}
@LuaFunction
public final boolean clear_player() {
if (hyperSpaceNeuralTensorProcessor.player_hash != null) {
hyperSpaceNeuralTensorProcessor.player_hash = null;
return true;
}
return false;
}
@LuaFunction
public final boolean is_uploading() {
return hasher != null;
}
@LuaFunction
public final boolean upload_byte(double brain_byte) throws LuaException {
if (hasher == null) {return false;}
brain_byte = Math.round(brain_byte);
if (!(brain_byte <= 255 && brain_byte >= 0)) {throw new LuaException("Number out of bound expected 0<=number<=255 but got"+brain_byte);}
hasher.update((byte) (brain_byte-128));
return true;
}
@LuaFunction
public final boolean end_upload() {
LOGGER.info("uploading player...");
if (hasher == null) {return false;}
String hash = new String(hasher.digest());
LOGGER.info("attempted upload with hash: {}", hash);
if (!SimulationManager.isPlayerHash(hash)) { return false; }
hyperSpaceNeuralTensorProcessor.player_hash = hash;
SimulationManager.uploadPlayer(hyperSpaceNeuralTensorProcessor.block_uuid,hash);
hasher = null;
return true;
}
@LuaFunction
public final MethodResult get_player_name() {
if (hyperSpaceNeuralTensorProcessor.player_hash != null) {
PlayerData pd = PersistedBrainData.get().getPlayer(hyperSpaceNeuralTensorProcessor.player_hash);
if (pd != null) {
ServerPlayerEntity player = pd.getPlayer();
if (player != null && player.getDisplayName() != null) {
try {
return MethodResult.of(player.getDisplayName().getString());
} catch (Exception e) {
return MethodResult.of(null, e.getMessage());
}
}
}
}
return MethodResult.of();
}
@LuaFunction
public final MethodResult send_player_to_sim(String otp) {
if (SimulationManager.otpValid(otp)){
SimulationManager.addPlayerToSimOtp(otp,hyperSpaceNeuralTensorProcessor.player_hash);
return MethodResult.of(true);
}
return MethodResult.of(false, "OTP is invalid");
}
@Override
public boolean equals(@Nullable IPeripheral other) {
return other instanceof HyperSpaceNeuralTensorProcessorPeripheral o && hyperSpaceNeuralTensorProcessor == o.hyperSpaceNeuralTensorProcessor;
}
}

View File

@@ -6,5 +6,7 @@ import org.ruffles.simulatedworlds.Entities.BlockEntities;
public class Peripherals {
public static void register() {
PeripheralLookup.get().registerForBlockEntity((f, s) -> new QuantumProcessorPeripheral(f), BlockEntities.QUANTUM_PROCESSOR_BLOCK_ENTITY);
PeripheralLookup.get().registerForBlockEntity((f, s) -> new HyperSpaceNeuralTensorProcessorPeripheral(f), BlockEntities.HYPERSPACE_NEURAL_TENSOR_PROCESSOR_ENTITY);
PeripheralLookup.get().registerForBlockEntity((f, s) -> new BrainScannerPeripheral(f), BlockEntities.BRAIN_SCANNER_ENTITY);
}
}

View File

@@ -5,6 +5,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import org.ruffles.simulatedworlds.Entities.QuantumProcessorBlockEntity;
import org.ruffles.simulatedworlds.SimulationManager;
public class QuantumProcessorPeripheral implements IPeripheral {
private final QuantumProcessorBlockEntity quantumProcessor;
@@ -19,8 +20,9 @@ public class QuantumProcessorPeripheral implements IPeripheral {
}
@LuaFunction
public final String ping() {
return "pong";
public final String get_otp() {
quantumProcessor.registerSim();
return SimulationManager.createOtp(quantumProcessor.simid);
}
@Override

View File

@@ -9,20 +9,22 @@ import org.jetbrains.annotations.Nullable;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static org.ruffles.simulatedworlds.Simulatedworlds.SERVER;
public class PersistedBrainData extends PersistentState {
private HashMap<String, PlayerData> players = new HashMap<>();
private final HashMap<String, PlayerData> players = new HashMap<>();
public PersistedBrainData() {}
@Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
for (String s : players.keySet()) {
NbtCompound pd = new NbtCompound();
players.get(s).writeNbt(pd);
pd = players.get(s).writeNbt(pd);
nbt.put(s, pd);
}
return null;
return nbt;
}
public static PersistedBrainData fromNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) {
@@ -34,12 +36,22 @@ public class PersistedBrainData extends PersistentState {
}
public void setPlayer(String k, PlayerData pd) {
players.put(k,pd);
markDirty();
}
public @Nullable PlayerData getPlayer(String k) {
return players.get(k);
}
public @Nullable PlayerData getPlayerFromUUID(UUID uuid) {
for (Map.Entry<String, PlayerData> player : players.entrySet()) {
if (player.getValue().getPlayerUUID() == uuid) {
return player.getValue();
}
}
return null;
}
// The "type descriptor" PersistentStateManager uses to construct/load your state
public static final Type<PersistedBrainData> TYPE =
new Type<>(PersistedBrainData::new, PersistedBrainData::fromNbt, DataFixTypes.LEVEL);

View File

@@ -8,20 +8,25 @@ import net.minecraft.nbt.NbtList;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.PersistentState;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import org.ruffles.simulatedworlds.DataClasses.SimulationData;
import org.ruffles.simulatedworlds.Simulatedworlds;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import static org.ruffles.simulatedworlds.Simulatedworlds.SERVER;
public class PersistedSimulationData extends PersistentState {
private final HashSet<UUID> simulations = new HashSet<>();
private final HashMap<UUID, SimulationData> simulations = new HashMap<>();
public PersistedSimulationData() {}
@Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
NbtList simulationIDs = new NbtList();
for (UUID id : simulations) {
simulationIDs.add(NbtHelper.fromUuid(id));
NbtCompound simulationIDs = new NbtCompound();
for (Map.Entry<UUID, SimulationData> entry : simulations.entrySet()) {
simulationIDs.put(entry.getKey().toString(),entry.getValue().writeNbt(new NbtCompound()));
}
nbt.put("simulations", simulationIDs);
return nbt;
@@ -29,24 +34,25 @@ public class PersistedSimulationData extends PersistentState {
public static PersistedSimulationData fromNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) {
PersistedSimulationData s = new PersistedSimulationData();
NbtList simulationIDs = nbt.getList("simulations", NbtElement.INT_ARRAY_TYPE);
for (NbtElement simulationID : simulationIDs) {
s.simulations.add(NbtHelper.toUuid(simulationID));
if (nbt.contains("simulations",NbtElement.COMPOUND_TYPE)) {
NbtCompound simulationIDs = nbt.getCompound("simulations");
for (String key : simulationIDs.getKeys()) {
s.simulations.put(UUID.fromString(key),SimulationData.fromNbt(simulationIDs.getCompound(key)));
}
}
return s;
}
public boolean simulationExists(UUID simID) {
return simulations.contains(simID);
return simulations.containsKey(simID);
}
public UUID registerSimulation() {
UUID candidateUuid = UUID.randomUUID();
while (simulations.contains(candidateUuid)) {
candidateUuid = UUID.randomUUID();
}
simulations.add(candidateUuid);
return candidateUuid;
public void registerSimulation(UUID simID) {
simulations.put(simID, new SimulationData());
}
public SimulationData getSimData(UUID simdata) {
return simulations.get(simdata);
}
// The "type descriptor" PersistentStateManager uses to construct/load your state

View File

@@ -1,23 +1,123 @@
package org.ruffles.simulatedworlds;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import org.ruffles.simulatedworlds.Blocks.Blocks;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import org.ruffles.simulatedworlds.DataClasses.SimulationData;
import org.ruffles.simulatedworlds.Peripherals.Peripherals;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedSimulationData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qouteall.dimlib.DimLibEntry;
import qouteall.dimlib.DimLibUtil;
import qouteall.dimlib.DimensionTemplate;
import java.util.*;
public class Simulatedworlds implements ModInitializer {
public static String MOD_ID = "simulatedworlds";
public static Logger LOGGER = LoggerFactory.getLogger("SimulatedWorlds");
public static MinecraftServer SERVER;
public static ServerWorld LIMBO;
@Override
public void onInitialize() {
Blocks.register();
LOGGER.info("finished registering blocks..");
Peripherals.register();
LOGGER.info("finished registering peripherals..");
ServerLifecycleEvents.SERVER_STARTED.register(server -> SERVER = server);
ServerLifecycleEvents.SERVER_STOPPED.register(server -> SERVER = null);
ServerLifecycleEvents.SERVER_STARTED.register(server -> {SERVER = server; LIMBO = SERVER.getWorld(RegistryKey.of(RegistryKeys.WORLD, Identifier.of(MOD_ID,"limbo")));});
ServerLifecycleEvents.SERVER_STOPPED.register(server -> {SERVER = null; LIMBO=null;});
ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> {
UUID playeruuid = newPlayer.getUuid();
Random random = new Random();
random.setSeed(newPlayer.getUuid().getLeastSignificantBits()+newPlayer.getUuid().getMostSignificantBits());
if (SimulationManager.isPlayerUploaded(playeruuid)) {
newPlayer.teleport(LIMBO,((double) random.nextInt(-3000,3000))*10000,10_000,((double) random.nextInt(-3000,3000))*10000,0,0);
}
});
ServerPlayerEvents.LEAVE.register(SimulationManager::saveDataForPlayer);
ServerTickEvents.START_WORLD_TICK.register(serverWorld -> {
if (serverWorld == LIMBO) {
for (ServerPlayerEntity player : LIMBO.getPlayers()) {
if (player.getY() < 100) {
Random random = new Random();
random.setSeed(player.getUuid().getLeastSignificantBits()+player.getUuid().getMostSignificantBits());
player.teleport(LIMBO,((double) random.nextInt(-3000,3000))*10000,10_000,((double) random.nextInt(-3000,3000))*10000,player.getYaw(),player.getPitch());
}
}
}
List<ServerPlayerEntity> players = new ArrayList<>(serverWorld.getPlayers());
for (ServerPlayerEntity player : players) {
Identifier worldId = serverWorld.getRegistryKey().getValue();
PlayerData data = PersistedBrainData.get().getPlayerFromUUID(player.getUuid());
if (data != null && data.getSimID() != null && player.isAlive()) {
Identifier expectedWorldId = Identifier.of(MOD_ID, data.getSimID().toString());
if (!expectedWorldId.equals(worldId)) {
ServerWorld targetWorld = SimulationManager.getOrCreateSimulation(data.getSimID());
player.teleport(targetWorld, 0, 100, 0, Set.of(), player.getYaw(), player.getPitch());
if (PersistedSimulationData.get().simulationExists(data.getSimID())) {
SimulationData simData = PersistedSimulationData.get().getSimData(data.getSimID());
NbtCompound playerNbt =
Objects.requireNonNullElseGet(simData.getPlayerData(player.getUuid()), NbtCompound::new);
player.readNbt(playerNbt);
SimulationManager.saveDataForPlayer(player);
}
}
}
}
ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((msg, player, params) -> {
Text text = msg.getContent();
if (Objects.equals(player.getWorld().getRegistryKey().getValue().getNamespace(), MOD_ID)) {
for (PlayerEntity playerEntity : player.getWorld().getPlayers()) {
playerEntity.sendMessage(Text.of("<"+player.getName().getString()+"> "+text.getString()));
}
} else {
for (ServerWorld world : SERVER.getWorlds()) {
if (!Objects.equals(world.getRegistryKey().getValue().getNamespace(), MOD_ID)) {
for (PlayerEntity playerEntity : world.getPlayers()) {
playerEntity.sendMessage(Text.of("<"+player.getName().getString()+"> "+text.getString()));
}
}
}
}
return false;
});
});
}
}

View File

@@ -1,53 +1,153 @@
package org.ruffles.simulatedworlds;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.random.Random;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.world.dimension.DimensionOptions;
import org.jetbrains.annotations.Nullable;
import org.ruffles.simulatedworlds.DataClasses.PlayerData;
import org.ruffles.simulatedworlds.DataClasses.SimulationData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedBrainData;
import org.ruffles.simulatedworlds.PersistentStates.PersistedSimulationData;
import qouteall.dimlib.DimensionTemplate;
import qouteall.dimlib.api.DimensionAPI;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import static org.ruffles.simulatedworlds.Simulatedworlds.LOGGER;
import static org.ruffles.simulatedworlds.Simulatedworlds.*;
public class SimulationManager {
public static int brain_data_size = 1000000;
public static @Nullable String hash(String str) {
public static HashMap<String,UUID> otp_map = new HashMap<>();
public static int brain_data_size = 300_000;
public static @Nullable MessageDigest hash() {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(str.getBytes(StandardCharsets.UTF_8));
return new String(digest, StandardCharsets.UTF_8);
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
LOGGER.error("hashing algorithm does not exist", e);
return null;
}
}
public static @Nullable String scanPlayer(PlayerEntity player) {
public static @Nullable Supplier<Optional<Byte>> scanPlayer(PlayerEntity player) {
SecureRandom random = new SecureRandom();
byte[] player_brain_data = new byte[brain_data_size];
random.nextBytes(player_brain_data);
String string = new String(player_brain_data, StandardCharsets.UTF_8);
String hash = hash(string);
if (hash != null) {
PersistedBrainData.get().setPlayer(hash, new PlayerData(player));
return string;
}
return null;
long seed = random.nextLong();
random.setSeed(seed);
AtomicInteger count = new AtomicInteger(brain_data_size);
MessageDigest md = hash();
if (md == null) {return null;}
return () -> {
byte[] bite = new byte[1];
random.nextBytes(bite);
if (count.get() == 0) {
return Optional.empty();
} else if (count.get() == 1) {
md.update(bite);
String hash = new String(md.digest());
LOGGER.info("made a player with hash {}", hash);
PersistedBrainData.get().setPlayer(hash,new PlayerData(player,seed));
player.kill();
count.addAndGet(-1);
} else {
md.update(bite);
count.addAndGet(-1);
}
return Optional.of(bite[0]);
};
}
public static void uploadPlayer(UUID blockUUID, String brainData) {
PlayerData data = PersistedBrainData.get().getPlayer(hash(brainData));
public static boolean isPlayerHash(String hash) {
return PersistedBrainData.get().getPlayer(hash) != null;
}
public static void uploadPlayer(UUID blockUUID, String brainDataHash) {
PlayerData data = PersistedBrainData.get().getPlayer(brainDataHash);
if (data != null) {
data.setUploadID(blockUUID);
}
}
public static void detachPlayer(String brainData) {
PlayerData data = PersistedBrainData.get().getPlayer(hash(brainData));
public static boolean isPlayerUploaded(UUID playeruuid) {
return PersistedBrainData.get().getPlayerFromUUID(playeruuid) != null;
}
public static boolean playerInHSNTPU(String brainDataHash) {
PlayerData data = PersistedBrainData.get().getPlayer(brainDataHash);
if (data != null) {
return data.getUploadID().isPresent();
}
return false;
}
public static void detachPlayer(String brainDataHash) {
PlayerData data = PersistedBrainData.get().getPlayer(brainDataHash);
if (data != null) {
data.clearUploadID();
}
}
public static String createOtp(UUID simid) {
Random random = new Random();
String generatedString = null;
while (generatedString == null || otp_map.containsKey(generatedString)) {
int leftLimit = 48; // numeral '0'
int rightLimit = 122; // letter 'z'
int targetStringLength = 10;
generatedString = random.ints(leftLimit, rightLimit + 1)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(targetStringLength)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
}
otp_map.put(generatedString,simid);
return generatedString;
}
public static boolean otpValid(String otp) {
return otp_map.containsKey(otp);
}
public static void addPlayerToSimOtp(String otp, String brainDataHash) {
UUID id = otp_map.get(otp);
if (id != null) {
addPlayerToSim(id,brainDataHash);
}
}
public static void saveDataForPlayer(ServerPlayerEntity player) {
PlayerData playerData = PersistedBrainData.get().getPlayerFromUUID(player.getUuid());
if (playerData != null && playerData.getSimID() != null) {
SimulationData simdata = PersistedSimulationData.get().getSimData(playerData.getSimID());
simdata.setPlayerData(player.getUuid(),player.writeNbt(new NbtCompound()));
PersistedSimulationData.get().markDirty();
}
}
public static void addPlayerToSim(UUID simid, String brainDataHash) {
if (brainDataHash != null) {
PlayerData playerData = PersistedBrainData.get().getPlayer(brainDataHash);
if (playerData != null) {
playerData.setSimID(simid);
}
}
}
public static ServerWorld getOrCreateSimulation(UUID simid) {
ServerWorld sim = SERVER.getWorld(RegistryKey.of(RegistryKeys.WORLD,Identifier.of(MOD_ID,simid.toString())));
if (sim == null) {
if (SERVER.isRunning()) {
DimensionAPI.addDimensionDynamically(SERVER, Identifier.of(MOD_ID, simid.toString()), new DimensionOptions(LIMBO.getDimensionEntry(), LIMBO.getChunkManager().getChunkGenerator()));
} else {
DimensionAPI.addDimension(SERVER, Identifier.of(MOD_ID, simid.toString()), new DimensionOptions(LIMBO.getDimensionEntry(), LIMBO.getChunkManager().getChunkGenerator()));
}
sim = SERVER.getWorld(RegistryKey.of(RegistryKeys.WORLD,Identifier.of(MOD_ID,simid.toString())));
}
return sim;
}
}

View File

@@ -7,10 +7,6 @@
"lakes": false,
"features": false,
"layers": [
{
"height": 1,
"block": "barrier"
}
]
}
}

View File

@@ -17,11 +17,12 @@
"piglin_safe": false,
"bed_works": true,
"respawn_anchor_works": false,
"has_raids": true,
"has_raids": false,
"logical_height": 16,
"logical_height": 1024,
"min_y": 0,
"height": 16,
"height": 1024,
"infiniburn": "#minecraft:infiniburn_overworld",

View File

@@ -1,9 +1,10 @@
{
"required": true,
"minVersion": "0.8",
"package": "org.ruffles.simulatedworlds.mixin",
"package": "org.ruffles.simulatedworlds.Mixins",
"compatibilityLevel": "JAVA_21",
"mixins": [
"PlayerMixin"
],
"injectors": {
"defaultRequire": 1