diff --git a/src/main/java/io/github/foundationgames/phonos/Phonos.java b/src/main/java/io/github/foundationgames/phonos/Phonos.java index d98c34a..1433a57 100644 --- a/src/main/java/io/github/foundationgames/phonos/Phonos.java +++ b/src/main/java/io/github/foundationgames/phonos/Phonos.java @@ -77,16 +77,6 @@ public void onInitialize() { Phonos.LOG.error("Error loading custom audio files", ex); } }); - ServerLifecycleEvents.SERVER_STOPPED.register(e -> { - try { - var path = PhonosUtil.getCustomSoundFolder(e); - if (!Files.exists(path)) Files.createDirectory(path); - - ServerCustomAudio.save(path); - } catch (IOException ex) { - Phonos.LOG.error("Error saving custom audio files", ex); - } - }); ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> ServerCustomAudio.onPlayerDisconnect(handler.getPlayer())); diff --git a/src/main/java/io/github/foundationgames/phonos/block/ConnectionHubBlock.java b/src/main/java/io/github/foundationgames/phonos/block/ConnectionHubBlock.java index 2448e19..a543faf 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/ConnectionHubBlock.java +++ b/src/main/java/io/github/foundationgames/phonos/block/ConnectionHubBlock.java @@ -163,6 +163,7 @@ public void setInputPluggedIn(int inputIndex, boolean pluggedIn, BlockState stat inputIndex = MathHelper.clamp(inputIndex, 0, be.inputs.length - 1); be.inputs[inputIndex] = pluggedIn; be.sync(); + be.markDirty(); } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/ElectronicNoteBlock.java b/src/main/java/io/github/foundationgames/phonos/block/ElectronicNoteBlock.java index c676b55..38650c3 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/ElectronicNoteBlock.java +++ b/src/main/java/io/github/foundationgames/phonos/block/ElectronicNoteBlock.java @@ -147,6 +147,7 @@ public void setInputPluggedIn(int inputIndex, boolean pluggedIn, BlockState stat inputIndex = MathHelper.clamp(inputIndex, 0, be.inputs.length - 1); be.inputs[inputIndex] = pluggedIn; be.sync(); + be.markDirty(); } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java b/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java index 1f105f8..8d312f7 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java +++ b/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java @@ -168,6 +168,7 @@ public void setInputPluggedIn(int inputIndex, boolean pluggedIn, BlockState stat } be.sync(); + be.markDirty(); } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/entity/SatelliteStationBlockEntity.java b/src/main/java/io/github/foundationgames/phonos/block/entity/SatelliteStationBlockEntity.java index 50c89c8..9ed0c96 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/entity/SatelliteStationBlockEntity.java +++ b/src/main/java/io/github/foundationgames/phonos/block/entity/SatelliteStationBlockEntity.java @@ -69,7 +69,7 @@ public SatelliteStationBlockEntity(BlockPos pos, BlockState state) { } public void play() { - if (world instanceof ServerWorld sWorld && ServerCustomAudio.hasSaved(this.streamId)) { + if (world instanceof ServerWorld sWorld && ServerCustomAudio.loaded() && ServerCustomAudio.hasSaved(this.streamId)) { var aud = ServerCustomAudio.loadSaved(this.streamId); ServerOutgoingStreamHandler.startStream(this.streamId, aud, sWorld.getServer()); @@ -143,11 +143,13 @@ public void tick(World world, BlockPos pos, BlockState state) { sync(); } - if (status == Status.NONE && (ServerCustomAudio.UPLOADING.containsKey(this.streamId) || ServerCustomAudio.SAVED.containsKey(this.streamId))) { - this.performAction(ACTION_LAUNCH); - } else if (status == Status.IN_ORBIT) { - if (!ServerCustomAudio.SAVED.containsKey(this.streamId)) { - this.performAction(ACTION_CRASH); + if (ServerCustomAudio.loaded()) { + if (status == Status.NONE && (ServerCustomAudio.UPLOADING.containsKey(this.streamId) || ServerCustomAudio.SAVED.containsKey(this.streamId))) { + this.performAction(ACTION_LAUNCH); + } else if (status == Status.IN_ORBIT) { + if (!ServerCustomAudio.SAVED.containsKey(this.streamId)) { + this.performAction(ACTION_CRASH); + } } } } else { diff --git a/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java index 2a0f78b..9d0453f 100644 --- a/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java +++ b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java @@ -3,7 +3,6 @@ import com.google.gson.Gson; import io.github.foundationgames.phonos.Phonos; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.option.SimpleOption; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/io/github/foundationgames/phonos/sound/custom/ServerCustomAudio.java b/src/main/java/io/github/foundationgames/phonos/sound/custom/ServerCustomAudio.java index 55a09dc..84b7f1a 100644 --- a/src/main/java/io/github/foundationgames/phonos/sound/custom/ServerCustomAudio.java +++ b/src/main/java/io/github/foundationgames/phonos/sound/custom/ServerCustomAudio.java @@ -16,17 +16,23 @@ import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; public class ServerCustomAudio { public static final String FILE_EXT = ".phonosaud"; public static final ExecutorService UPLOAD_POOL = Executors.newFixedThreadPool(1); + public static final ExecutorService FILESYS_POOL = Executors.newFixedThreadPool(4); public static final Long2ObjectMap UPLOADING = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); - public static final Long2ObjectMap SAVED = new Long2ObjectOpenHashMap<>(); + public static final Long2ObjectMap SAVED = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); private static int TOTAL_SAVED_SIZE = 0; @@ -94,6 +100,10 @@ private static void handleUpload(MinecraftServer srv, ServerPlayerEntity player, } } + public static boolean loaded() { + return LOADED; + } + public static void deleteSaved(MinecraftServer srv, long id) { var aud = SAVED.remove(id); @@ -132,7 +142,7 @@ public static void deleteOnly(long id, Path folder) throws IOException { Files.deleteIfExists(path); } - public static void save(Path folder) throws IOException { + public static void saveAll(Path folder) throws IOException { if (!LOADED) { Phonos.LOG.error("Tried to save custom uploaded audio before it was loaded!"); @@ -168,7 +178,11 @@ public static void save(Path folder) throws IOException { } public static void load(Path folder) throws IOException { + final var startTime = Instant.now(); + SAVED.clear(); + + List files = new ArrayList<>(); try (var paths = Files.walk(folder, 1)) { for (var path : paths.toList()) { var filename = path.getFileName().toString(); @@ -176,13 +190,8 @@ public static void load(Path folder) throws IOException { var hexStr = filename.replace(FILE_EXT, ""); try { - long id = Long.parseUnsignedLong(hexStr, 16); - try (var in = Files.newInputStream(path)) { - var aud = AudioDataQueue.read(in, ByteBuffer::allocate); - SAVED.put(id, aud); - TOTAL_SAVED_SIZE += aud.originalSize; - } - + Long.parseUnsignedLong(hexStr, 16); + files.add(hexStr); } catch (NumberFormatException ex) { Phonos.LOG.error("Audio data " + filename + " has invalid name"); } @@ -190,7 +199,30 @@ public static void load(Path folder) throws IOException { } } - LOADED = true; - Phonos.LOG.info("Loaded " + TOTAL_SAVED_SIZE + " bytes of saved audio from /phonos/"); + final int foundDataCount = files.size(); + var loadedDataCount = new AtomicInteger(0); + + for (final var hexStr : files) { + final var path = folder.resolve(hexStr + FILE_EXT); + FILESYS_POOL.submit(() -> { + long id = Long.parseUnsignedLong(hexStr, 16); + + try (var in = Files.newInputStream(path)) { + var aud = AudioDataQueue.read(in, ByteBuffer::allocate); + + SAVED.put(id, aud); + TOTAL_SAVED_SIZE += aud.originalSize; + } catch (IOException ex) { + Phonos.LOG.error("Error loading custom audio file {}", path.getFileName()); + } + + if (loadedDataCount.incrementAndGet() >= foundDataCount) { + LOADED = true; + + var dur = Duration.between(startTime, Instant.now()); + Phonos.LOG.info("Loaded {} bytes of saved audio from /phonos/ in {} ms", TOTAL_SAVED_SIZE, dur.toMillis()); + } + }); + } } } diff --git a/src/main/java/io/github/foundationgames/phonos/world/command/PhonosCommands.java b/src/main/java/io/github/foundationgames/phonos/world/command/PhonosCommands.java index 7c5051f..f55ace5 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/command/PhonosCommands.java +++ b/src/main/java/io/github/foundationgames/phonos/world/command/PhonosCommands.java @@ -73,6 +73,12 @@ public static void init() { public static int satelliteInspect(ServerCommandSource source, BlockPos pos) { var world = source.getWorld(); + if (!ServerCustomAudio.loaded()) { + source.sendError(Text.translatable("command.phonos.satellite.not_loaded")); + + return 1; + } + if (world.getBlockEntity(pos) instanceof SatelliteStationBlockEntity be) { long id = be.streamId; @@ -98,6 +104,12 @@ public static int satelliteInspect(ServerCommandSource source, BlockPos pos) { } public static int satelliteList(ServerCommandSource source) { + if (!ServerCustomAudio.loaded()) { + source.sendError(Text.translatable("command.phonos.satellite.not_loaded")); + + return 1; + } + var set = ServerCustomAudio.SAVED.long2ObjectEntrySet(); if (set.isEmpty()) { @@ -125,6 +137,12 @@ public static int satelliteList(ServerCommandSource source) { } public static int satelliteCrash(ServerCommandSource source, long id) throws CommandSyntaxException { + if (!ServerCustomAudio.loaded()) { + source.sendError(Text.translatable("command.phonos.satellite.not_loaded")); + + return 1; + } + var idStr = Long.toHexString(id); Phonos.LOG.info("Satellite {} was crashed via command by player {}.", idStr, source.getPlayerOrThrow()); diff --git a/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockEntityOutputs.java b/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockEntityOutputs.java index 712292f..b4c40d6 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockEntityOutputs.java +++ b/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockEntityOutputs.java @@ -105,6 +105,8 @@ public boolean purge(Consumer purgeAction) { } if (connections[i] != null && connections[i].shouldRemove(this.blockEntity.getWorld())) { + System.out.println("CAN EXIST: " + connections[i].end.canPlugExist(this.blockEntity.getWorld())); + purgeAction.accept(connections[i]); connections[i] = null; changed = true; diff --git a/src/main/resources/assets/phonos/lang/en_us.json b/src/main/resources/assets/phonos/lang/en_us.json index e369ad7..c7877dc 100644 --- a/src/main/resources/assets/phonos/lang/en_us.json +++ b/src/main/resources/assets/phonos/lang/en_us.json @@ -25,6 +25,7 @@ "command.phonos.radar.none_found": "Found no radio emitters on channel %s.", "command.phonos.radar.success": "Nearest radio emitter located at %s.", + "command.phonos.satellite.not_loaded": "Satellites are not yet ready.", "command.phonos.satellite.inspect.no_upload": "This station has no orbiting satellite!", "command.phonos.satellite.inspect.invalid": "This block is not a satellite station!", "command.phonos.satellite.crash": "Crashed satellite with id %s.",