From 37999d142ab154eac337a0697cb8b9f95de87b1a Mon Sep 17 00:00:00 2001 From: FoundationGames <43485105+FoundationGames@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:46:49 -0700 Subject: [PATCH] Add config with volume and LOD options, add server data for upcoming radar feature --- build.gradle | 3 + gradle.properties | 4 +- .../github/foundationgames/phonos/Phonos.java | 4 - .../foundationgames/phonos/PhonosClient.java | 3 + .../phonos/block/RadioTransceiverBlock.java | 19 ++++ .../entity/AbstractOutputBlockEntity.java | 1 + .../entity/ElectronicJukeboxBlockEntity.java | 1 + .../entity/RadioTransceiverBlockEntity.java | 8 ++ ...ectionRenderer.java => CableRenderer.java} | 27 +++-- .../block/CableOutputBlockEntityRenderer.java | 6 +- .../phonos/config/PhonosClientConfig.java | 71 +++++++++++++ .../config/PhonosClientConfigScreen.java | 99 +++++++++++++++++++ .../sound/MultiSourceSoundInstance.java | 8 +- .../sound/StreamMultiSoundInstance.java | 6 ++ .../sound/custom/ServerCustomAudio.java | 4 +- .../phonos/util/compat/PhonosModMenu.java | 13 +++ .../phonos/world/RadarPoints.java | 75 ++++++++++++++ ...reConnection.java => CableConnection.java} | 10 +- ...WirePlugPoint.java => CablePlugPoint.java} | 2 +- .../phonos/world/sound/InputPlugPoint.java | 2 +- .../sound/block/BlockConnectionLayout.java | 4 +- .../world/sound/block/BlockEntityOutputs.java | 18 ++-- .../resources/assets/phonos/lang/en_us.json | 11 ++- src/main/resources/fabric.mod.json | 3 + 24 files changed, 367 insertions(+), 35 deletions(-) rename src/main/java/io/github/foundationgames/phonos/client/render/{ConnectionRenderer.java => CableRenderer.java} (86%) create mode 100644 src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java create mode 100644 src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfigScreen.java create mode 100644 src/main/java/io/github/foundationgames/phonos/util/compat/PhonosModMenu.java create mode 100644 src/main/java/io/github/foundationgames/phonos/world/RadarPoints.java rename src/main/java/io/github/foundationgames/phonos/world/sound/{WireConnection.java => CableConnection.java} (82%) rename src/main/java/io/github/foundationgames/phonos/world/sound/{WirePlugPoint.java => CablePlugPoint.java} (97%) diff --git a/build.gradle b/build.gradle index 6234dd9..2d0db24 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ group = project.maven_group repositories { maven { url "https://api.modrinth.com/maven" } + maven { url = 'https://maven.terraformersmc.com/' } } dependencies { @@ -23,6 +24,8 @@ dependencies { modImplementation "maven.modrinth:jsonem:${project.jsonem_version}" include "maven.modrinth:jsonem:${project.jsonem_version}" + + modApi("com.terraformersmc:modmenu:${project.modmenu_version}") { transitive false } } processResources { diff --git a/gradle.properties b/gradle.properties index 7ef5cff..ae5d5b0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,9 +7,9 @@ loader_version=0.14.21 #Fabric api fabric_version=0.84.0+1.20.1 -mod_version = 1.0.0-beta.4 +mod_version = 1.0.0-beta.5 maven_group = io.github.foundationgames archives_base_name = phonos jsonem_version=0.2.1+1.20 - +modmenu_version=7.1.0 diff --git a/src/main/java/io/github/foundationgames/phonos/Phonos.java b/src/main/java/io/github/foundationgames/phonos/Phonos.java index 60ffa6f..2bed42b 100644 --- a/src/main/java/io/github/foundationgames/phonos/Phonos.java +++ b/src/main/java/io/github/foundationgames/phonos/Phonos.java @@ -115,8 +115,4 @@ public void onInitialize() { public static Identifier id(String path) { return new Identifier("phonos", path); } - - public static float getPhonosVolume() { - return 1; - } } diff --git a/src/main/java/io/github/foundationgames/phonos/PhonosClient.java b/src/main/java/io/github/foundationgames/phonos/PhonosClient.java index d54b076..f39763a 100644 --- a/src/main/java/io/github/foundationgames/phonos/PhonosClient.java +++ b/src/main/java/io/github/foundationgames/phonos/PhonosClient.java @@ -6,6 +6,7 @@ import io.github.foundationgames.phonos.client.render.block.RadioLoudspeakerBlockEntityRenderer; import io.github.foundationgames.phonos.client.render.block.RadioTransceiverBlockEntityRenderer; import io.github.foundationgames.phonos.client.render.block.SatelliteStationBlockEntityRenderer; +import io.github.foundationgames.phonos.config.PhonosClientConfig; import io.github.foundationgames.phonos.item.AudioCableItem; import io.github.foundationgames.phonos.item.PhonosItems; import io.github.foundationgames.phonos.network.ClientPayloadPackets; @@ -37,6 +38,8 @@ public class PhonosClient implements ClientModInitializer { @Override public void onInitializeClient() { + PhonosClientConfig.get(); // Load if not already + ClientPayloadPackets.initClient(); ClientSoundStorage.initClient(); 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 89ebb2a..1f105f8 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java +++ b/src/main/java/io/github/foundationgames/phonos/block/RadioTransceiverBlock.java @@ -2,6 +2,7 @@ import io.github.foundationgames.phonos.block.entity.RadioTransceiverBlockEntity; import io.github.foundationgames.phonos.util.PhonosUtil; +import io.github.foundationgames.phonos.world.RadarPoints; import io.github.foundationgames.phonos.world.sound.block.BlockConnectionLayout; import io.github.foundationgames.phonos.world.sound.block.InputBlock; import net.minecraft.block.*; @@ -11,6 +12,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemUsageContext; +import net.minecraft.server.world.ServerWorld; import net.minecraft.state.StateManager; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; @@ -148,6 +150,23 @@ public void setInputPluggedIn(int inputIndex, boolean pluggedIn, BlockState stat if (world.getBlockEntity(pos) instanceof RadioTransceiverBlockEntity be) { inputIndex = MathHelper.clamp(inputIndex, 0, be.inputs.length - 1); be.inputs[inputIndex] = pluggedIn; + + if (world instanceof ServerWorld sWorld) { + if (pluggedIn) { + RadarPoints.get(sWorld).add(be.getChannel(), pos); + } else { + boolean remove = true; + for (boolean in : be.inputs) if (in) { + remove = false; + break; + } + + if (remove) { + RadarPoints.get(sWorld).remove(be.getChannel(), pos); + } + } + } + be.sync(); } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/entity/AbstractOutputBlockEntity.java b/src/main/java/io/github/foundationgames/phonos/block/entity/AbstractOutputBlockEntity.java index b4c2805..fd5245b 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/entity/AbstractOutputBlockEntity.java +++ b/src/main/java/io/github/foundationgames/phonos/block/entity/AbstractOutputBlockEntity.java @@ -39,6 +39,7 @@ public void tick(World world, BlockPos pos, BlockState state) { if (!world.isClient()) { if (this.outputs.purge(conn -> this.outputs.dropConnectionItem(world, conn, true))) { sync(); + markDirty(); } } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/entity/ElectronicJukeboxBlockEntity.java b/src/main/java/io/github/foundationgames/phonos/block/entity/ElectronicJukeboxBlockEntity.java index 1d06e2f..a2cc02c 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/entity/ElectronicJukeboxBlockEntity.java +++ b/src/main/java/io/github/foundationgames/phonos/block/entity/ElectronicJukeboxBlockEntity.java @@ -118,6 +118,7 @@ public void tick(World world, BlockPos pos, BlockState state) { if (this.outputs.purge(conn -> this.outputs.dropConnectionItem(world, conn, true))) { sync(); + markDirty(); } } } diff --git a/src/main/java/io/github/foundationgames/phonos/block/entity/RadioTransceiverBlockEntity.java b/src/main/java/io/github/foundationgames/phonos/block/entity/RadioTransceiverBlockEntity.java index e36fab3..7f0ad91 100644 --- a/src/main/java/io/github/foundationgames/phonos/block/entity/RadioTransceiverBlockEntity.java +++ b/src/main/java/io/github/foundationgames/phonos/block/entity/RadioTransceiverBlockEntity.java @@ -4,6 +4,7 @@ import io.github.foundationgames.phonos.block.RadioTransceiverBlock; import io.github.foundationgames.phonos.radio.RadioDevice; import io.github.foundationgames.phonos.radio.RadioStorage; +import io.github.foundationgames.phonos.world.RadarPoints; import io.github.foundationgames.phonos.world.sound.InputPlugPoint; import io.github.foundationgames.phonos.world.sound.block.BlockConnectionLayout; import net.minecraft.block.BlockState; @@ -11,6 +12,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.world.ServerWorld; import net.minecraft.state.property.Properties; import net.minecraft.util.DyeColor; import net.minecraft.util.math.BlockPos; @@ -112,6 +114,12 @@ public Direction getRotation() { public void setAndUpdateChannel(int channel) { channel = Math.floorMod(channel, RadioStorage.CHANNEL_COUNT); + if (this.world instanceof ServerWorld sWorld) for (boolean in : this.inputs) if (in) { + RadarPoints.get(sWorld).remove(this.channel, this.pos); + RadarPoints.get(sWorld).add(channel, this.pos); + break; + } + var radio = RadioStorage.getInstance(this.world); radio.removeReceivingEmitter(this.channel, this.emitterId()); diff --git a/src/main/java/io/github/foundationgames/phonos/client/render/ConnectionRenderer.java b/src/main/java/io/github/foundationgames/phonos/client/render/CableRenderer.java similarity index 86% rename from src/main/java/io/github/foundationgames/phonos/client/render/ConnectionRenderer.java rename to src/main/java/io/github/foundationgames/phonos/client/render/CableRenderer.java index 1a7ad3f..74a71f8 100644 --- a/src/main/java/io/github/foundationgames/phonos/client/render/ConnectionRenderer.java +++ b/src/main/java/io/github/foundationgames/phonos/client/render/CableRenderer.java @@ -1,9 +1,11 @@ package io.github.foundationgames.phonos.client.render; +import io.github.foundationgames.phonos.config.PhonosClientConfig; import io.github.foundationgames.phonos.util.PhonosUtil; import io.github.foundationgames.phonos.util.Pose3f; -import io.github.foundationgames.phonos.world.sound.WireConnection; -import io.github.foundationgames.phonos.world.sound.WirePlugPoint; +import io.github.foundationgames.phonos.world.sound.CableConnection; +import io.github.foundationgames.phonos.world.sound.CablePlugPoint; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.model.Model; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.WorldRenderer; @@ -17,7 +19,7 @@ import java.util.function.Consumer; -public class ConnectionRenderer { +public class CableRenderer { private static final Quaternionf rotationCache = new Quaternionf(); private static final BlockPos.Mutable lightPos = new BlockPos.Mutable(); @@ -62,7 +64,7 @@ private static void lerpCableEnd(Vector4f[] out, Vector4f[] begin, Vector4f[] en } } - public static void renderConnection(World world, WireConnection conn, MatrixStack matrices, VertexConsumer buffer, Model cableEndModel, int overlay, float tickDelta) { + public static void renderConnection(PhonosClientConfig config, World world, CableConnection conn, MatrixStack matrices, VertexConsumer buffer, Model cableEndModel, int overlay, float tickDelta) { int startLight, endLight; matrices.push(); @@ -91,7 +93,20 @@ public static void renderConnection(World world, WireConnection conn, MatrixStac float g = conn.color != null ? conn.color.getColorComponents()[1] : 1; float b = conn.color != null ? conn.color.getColorComponents()[2] : 1; float length = cableStPt.distance(cableEnPt); - int segments = (int) Math.ceil(4 * length); + int segments = Math.max((int) Math.ceil(4 * length * config.cableLODNearDetail), 1); + + if (config.cableLODs) { + float cx = (cableStPt.x + cableEnPt.x) * 0.5f; + float cy = (cableStPt.y + cableEnPt.y) * 0.5f; + float cz = (cableStPt.z + cableEnPt.z) * 0.5f; + + double sqDist = MinecraftClient.getInstance().gameRenderer.getCamera().getPos() + .squaredDistanceTo(cx, cy, cz); + double delta = MathHelper.clamp(sqDist / (length * length * 4), 0, 1); + double detail = MathHelper.lerp(delta, config.cableLODNearDetail, config.cableLODFarDetail); + + segments = Math.max((int) Math.ceil(4 * length * detail), Math.min(3, segments)); + } cableRotAxis.set(cableEnPt.z - cableStPt.z, 0, cableEnPt.x - cableStPt.x); @@ -162,7 +177,7 @@ public static void renderConnection(World world, WireConnection conn, MatrixStac private static final Pose3f tcp_endPose = new Pose3f(new Vector3f(), new Quaternionf()); private static final Quaternionf tcp_rot = new Quaternionf(); private static final Vector4f tcp_vec4a = new Vector4f(); - private static void transformConnPoint(World world, WirePlugPoint point, MatrixStack matrices, Vector3f connPos, float tickDelta) { + private static void transformConnPoint(World world, CablePlugPoint point, MatrixStack matrices, Vector3f connPos, float tickDelta) { connPos.set(0, 0, 0); point.writeOriginPose(world, tickDelta, tcp_originPose); diff --git a/src/main/java/io/github/foundationgames/phonos/client/render/block/CableOutputBlockEntityRenderer.java b/src/main/java/io/github/foundationgames/phonos/client/render/block/CableOutputBlockEntityRenderer.java index 6604c53..ffa0238 100644 --- a/src/main/java/io/github/foundationgames/phonos/client/render/block/CableOutputBlockEntityRenderer.java +++ b/src/main/java/io/github/foundationgames/phonos/client/render/block/CableOutputBlockEntityRenderer.java @@ -3,7 +3,8 @@ import io.github.foundationgames.phonos.Phonos; import io.github.foundationgames.phonos.PhonosClient; import io.github.foundationgames.phonos.client.model.BasicModel; -import io.github.foundationgames.phonos.client.render.ConnectionRenderer; +import io.github.foundationgames.phonos.client.render.CableRenderer; +import io.github.foundationgames.phonos.config.PhonosClientConfig; import io.github.foundationgames.phonos.world.sound.block.OutputBlockEntity; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.render.VertexConsumerProvider; @@ -23,12 +24,13 @@ public CableOutputBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) { @Override public void render(E entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) { var buffer = vertexConsumers.getBuffer(cableEndModel.getLayer(TEXTURE)); + var config = PhonosClientConfig.get(); matrices.push(); matrices.translate(-entity.getPos().getX(), -entity.getPos().getY(), -entity.getPos().getZ()); entity.getOutputs().forEach((i, conn) -> - ConnectionRenderer.renderConnection(entity.getWorld(), conn, matrices, buffer, cableEndModel, overlay, tickDelta)); + CableRenderer.renderConnection(config, entity.getWorld(), conn, matrices, buffer, cableEndModel, overlay, tickDelta)); matrices.pop(); } diff --git a/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java new file mode 100644 index 0000000..6f5d9a1 --- /dev/null +++ b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfig.java @@ -0,0 +1,71 @@ +package io.github.foundationgames.phonos.config; + +import com.google.gson.Gson; +import io.github.foundationgames.phonos.Phonos; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PhonosClientConfig { + private static PhonosClientConfig config = null; + + public double phonosMasterVolume = 1; + public double streamVolume = 1; + + public boolean cableLODs = true; + public double cableLODNearDetail = 1; + public double cableLODFarDetail = 0.25; + + public PhonosClientConfig() { + } + + public PhonosClientConfig copyTo(PhonosClientConfig copy) { + for (var f : PhonosClientConfig.class.getDeclaredFields()) { + try { + f.set(copy, f.get(this)); + } catch (IllegalAccessException ignored) {} + } + + return copy; + } + + public static PhonosClientConfig get() { + if (config == null) { + config = new PhonosClientConfig(); + + try { + config.load(); + } catch (IOException ex) { + Phonos.LOG.error("Error loading Phonos client config!", ex); + } + } + + return config; + } + + private static Path configPath() { + return FabricLoader.getInstance().getConfigDir().resolve("phonos.json"); + } + + public void load() throws IOException { + var path = configPath(); + + try (var in = Files.newBufferedReader(path)) { + var fileCfg = new Gson().fromJson(in, PhonosClientConfig.class); + fileCfg.copyTo(this); + } + } + + public void save() throws IOException { + var path = configPath(); + + var gson = new Gson(); + try (var writer = gson.newJsonWriter(Files.newBufferedWriter(path))) { + writer.setIndent(" "); + + gson.toJson(gson.toJsonTree(this, PhonosClientConfig.class), writer); + } + } +} diff --git a/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfigScreen.java b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfigScreen.java new file mode 100644 index 0000000..8f89a48 --- /dev/null +++ b/src/main/java/io/github/foundationgames/phonos/config/PhonosClientConfigScreen.java @@ -0,0 +1,99 @@ +package io.github.foundationgames.phonos.config; + +import io.github.foundationgames.phonos.Phonos; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.OptionListWidget; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.SimpleOption; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; + +public class PhonosClientConfigScreen extends Screen { + private static final Text TITLE = Text.translatable("text.config.phonos.title"); + + private final Screen parent; + private final List> options = new ArrayList<>(); + private final Runnable save; + + public PhonosClientConfigScreen(Screen parent, Runnable save) { + super(TITLE); + + this.parent = parent; + this.save = save; + } + + public static PhonosClientConfigScreen create(PhonosClientConfig config, Screen parent) { + var copy = config.copyTo(new PhonosClientConfig()); + + var screen = new PhonosClientConfigScreen(parent, () -> { + copy.copyTo(config); + try { + config.save(); + } catch (IOException e) { + Phonos.LOG.error("Could not save config!", e); + } + }); + + screen.addPercentage("phonosMasterVolume", val -> copy.phonosMasterVolume = val, copy.phonosMasterVolume); + screen.addPercentage("streamVolume", val -> copy.streamVolume = val, copy.streamVolume); + screen.addBoolean("cableLODs", val -> copy.cableLODs = val, copy.cableLODs); + screen.addPercentage("cableLODNearDetail", val -> copy.cableLODNearDetail = val, copy.cableLODNearDetail); + screen.addPercentage("cableLODFarDetail", val -> copy.cableLODFarDetail = val, copy.cableLODFarDetail); + + return screen; + } + + public void addBoolean(String key, BooleanConsumer setter, boolean currentValue) { + this.options.add(SimpleOption.ofBoolean("text.config.phonos.option." + key, currentValue, setter)); + } + + public void addPercentage(String key, DoubleConsumer setter, double currentValue) { + addIntRange(key, val -> setter.accept(val * 0.01D), (int)(currentValue * 100), 0, 100); + } + + public void addIntRange(String key, IntConsumer setter, int currentValue, int min, int max) { + this.options.add(new SimpleOption<>("text.config.phonos.option." + key, + SimpleOption.emptyTooltip(), + (optionText, value) -> GameOptions.getGenericValueText(optionText, Text.literal(value.toString())), + new SimpleOption.ValidatingIntSliderCallbacks(min, max), + currentValue, setter::accept) + ); + } + + public void close() { + this.client.setScreen(this.parent); + } + + @Override + protected void init() { + var buttons = new OptionListWidget(this.client, this.width, this.height, 32, this.height - 32, 25); + for (SimpleOption option : this.options) { + buttons.addSingleOptionEntry(option); + } + this.addDrawableChild(buttons); + + this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> { + this.save.run(); + this.close(); + }).dimensions(this.width / 2 + 2, this.height - 27, 150, 20).build()); + + this.addDrawableChild(ButtonWidget.builder(ScreenTexts.CANCEL, (button) -> this.close()) + .dimensions(this.width / 2 - 152, this.height - 27, 150, 20).build()); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 13, 0xFFFFFF); + } +} diff --git a/src/main/java/io/github/foundationgames/phonos/sound/MultiSourceSoundInstance.java b/src/main/java/io/github/foundationgames/phonos/sound/MultiSourceSoundInstance.java index dccc27a..ba25e5c 100644 --- a/src/main/java/io/github/foundationgames/phonos/sound/MultiSourceSoundInstance.java +++ b/src/main/java/io/github/foundationgames/phonos/sound/MultiSourceSoundInstance.java @@ -1,5 +1,6 @@ package io.github.foundationgames.phonos.sound; +import io.github.foundationgames.phonos.config.PhonosClientConfig; import io.github.foundationgames.phonos.sound.emitter.SoundEmitterTree; import net.minecraft.client.MinecraftClient; import net.minecraft.client.sound.AbstractSoundInstance; @@ -21,7 +22,7 @@ public class MultiSourceSoundInstance extends AbstractSoundInstance implements T private boolean done; protected MultiSourceSoundInstance(SoundEmitterTree tree, Identifier sound, Random random, float volume, float pitch) { - super(sound, SoundCategory.RECORDS, random); + super(sound, SoundCategory.MASTER, random); this.emitters = new AtomicReference<>(tree); this.volume = volume; @@ -34,6 +35,11 @@ public MultiSourceSoundInstance(SoundEmitterTree tree, SoundEvent sound, Random this(tree, sound.getId(), random, volume, pitch); } + @Override + public float getVolume() { + return (float) (super.getVolume() * PhonosClientConfig.get().phonosMasterVolume); + } + @Override public double getX() { return x; diff --git a/src/main/java/io/github/foundationgames/phonos/sound/StreamMultiSoundInstance.java b/src/main/java/io/github/foundationgames/phonos/sound/StreamMultiSoundInstance.java index d228724..eec0625 100644 --- a/src/main/java/io/github/foundationgames/phonos/sound/StreamMultiSoundInstance.java +++ b/src/main/java/io/github/foundationgames/phonos/sound/StreamMultiSoundInstance.java @@ -1,6 +1,7 @@ package io.github.foundationgames.phonos.sound; import io.github.foundationgames.phonos.Phonos; +import io.github.foundationgames.phonos.config.PhonosClientConfig; import io.github.foundationgames.phonos.sound.emitter.SoundEmitterTree; import io.github.foundationgames.phonos.sound.stream.ClientIncomingStreamHandler; import net.fabricmc.fabric.api.client.sound.v1.FabricSoundInstance; @@ -20,6 +21,11 @@ public StreamMultiSoundInstance(SoundEmitterTree tree, long streamId, Random ran this.streamId = streamId; } + @Override + public float getVolume() { + return (float) (super.getVolume() * PhonosClientConfig.get().streamVolume); + } + @Override public CompletableFuture getAudioStream(SoundLoader loader, Identifier id, boolean repeatInstantly) { return ClientIncomingStreamHandler.getStream(this.streamId); 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 cdf06ae..790e50b 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 @@ -98,7 +98,9 @@ public static void deleteSaved(MinecraftServer srv, long id) { try { deleteOnly(id, PhonosUtil.getCustomSoundFolder(srv)); - Phonos.LOG.info("Saved audio with ID {} ({} bytes) was deleted.", Long.toHexString(id), aud.originalSize); + if (aud != null) { + Phonos.LOG.info("Saved audio with ID {} ({} bytes) was deleted.", Long.toHexString(id), aud.originalSize); + } } catch (IOException ex) { Phonos.LOG.error("Error saving uploaded sound", ex); } diff --git a/src/main/java/io/github/foundationgames/phonos/util/compat/PhonosModMenu.java b/src/main/java/io/github/foundationgames/phonos/util/compat/PhonosModMenu.java new file mode 100644 index 0000000..1292c26 --- /dev/null +++ b/src/main/java/io/github/foundationgames/phonos/util/compat/PhonosModMenu.java @@ -0,0 +1,13 @@ +package io.github.foundationgames.phonos.util.compat; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; +import io.github.foundationgames.phonos.config.PhonosClientConfig; +import io.github.foundationgames.phonos.config.PhonosClientConfigScreen; + +public class PhonosModMenu implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return parent -> PhonosClientConfigScreen.create(PhonosClientConfig.get(), parent); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/foundationgames/phonos/world/RadarPoints.java b/src/main/java/io/github/foundationgames/phonos/world/RadarPoints.java new file mode 100644 index 0000000..845c5bf --- /dev/null +++ b/src/main/java/io/github/foundationgames/phonos/world/RadarPoints.java @@ -0,0 +1,75 @@ +package io.github.foundationgames.phonos.world; + +import io.github.foundationgames.phonos.radio.RadioStorage; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.PersistentState; + +public class RadarPoints extends PersistentState { + private Int2ObjectMap channelToSources = new Int2ObjectOpenHashMap<>(); + + public void add(int channel, BlockPos pos) { + var set = channelToSources.computeIfAbsent(channel, LongOpenHashSet::new); + set.add(pos.asLong()); + markDirty(); + } + + public void remove(int channel, BlockPos pos) { + if (channelToSources.containsKey(channel)) { + channelToSources.get(channel).remove(pos.asLong()); + markDirty(); + } + } + + public static RadarPoints get(ServerWorld world) { + return world.getPersistentStateManager().getOrCreate(RadarPoints::readNbt, RadarPoints::new, "phonos_radar_points"); + } + + @Override + public NbtCompound writeNbt(NbtCompound nbt) { + for (var entry : channelToSources.int2ObjectEntrySet()) if (entry.getValue().size() > 0) { + var packedPosSet = new int[entry.getValue().size() * 2]; + + int idx = 0; + for (long pos : entry.getValue()) { + packedPosSet[idx] = (int) (pos >> 32); + packedPosSet[idx + 1] = (int) pos; + + idx += 2; + } + + nbt.putIntArray("ch" + entry.getIntKey(), packedPosSet); + } + + return nbt; + } + + public static RadarPoints readNbt(NbtCompound nbt) { + var state = new RadarPoints(); + + for (int ch = 0; ch < RadioStorage.CHANNEL_COUNT; ch++) { + var key = "ch" + ch; + + if (nbt.contains(key)) { + var packedPosSet = nbt.getIntArray(key); + var posSet = new LongOpenHashSet(); + + for (int i = 0; i < packedPosSet.length; i += 2) { + long upper = packedPosSet[i]; + long lower = packedPosSet[i + 1]; + + posSet.add(lower | (upper << 32)); + } + + state.channelToSources.put(ch, posSet); + } + } + + return state; + } +} diff --git a/src/main/java/io/github/foundationgames/phonos/world/sound/WireConnection.java b/src/main/java/io/github/foundationgames/phonos/world/sound/CableConnection.java similarity index 82% rename from src/main/java/io/github/foundationgames/phonos/world/sound/WireConnection.java rename to src/main/java/io/github/foundationgames/phonos/world/sound/CableConnection.java index a24f721..081587b 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/sound/WireConnection.java +++ b/src/main/java/io/github/foundationgames/phonos/world/sound/CableConnection.java @@ -6,13 +6,13 @@ import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; -public class WireConnection { - public final WirePlugPoint start; +public class CableConnection { + public final CablePlugPoint start; public final InputPlugPoint end; public final @Nullable DyeColor color; public final ItemStack drop; - public WireConnection(WirePlugPoint start, InputPlugPoint end, @Nullable DyeColor color, ItemStack drop) { + public CableConnection(CablePlugPoint start, InputPlugPoint end, @Nullable DyeColor color, ItemStack drop) { this.start = start; this.end = end; this.color = color; @@ -40,7 +40,7 @@ public void writeNbt(NbtCompound nbt) { nbt.put("item", drop.writeNbt(new NbtCompound())); } - public static WireConnection readNbt(World world, WirePlugPoint start, NbtCompound nbt) { + public static CableConnection readNbt(World world, CablePlugPoint start, NbtCompound nbt) { DyeColor color = null; if (nbt.contains("color")) { color = DyeColor.byName(nbt.getString("color"), null); @@ -58,6 +58,6 @@ public static WireConnection readNbt(World world, WirePlugPoint start, NbtCompou var cable = ItemStack.fromNbt(cableData); if (cable == null) return null; - return new WireConnection(start, end, color, cable); + return new CableConnection(start, end, color, cable); } } diff --git a/src/main/java/io/github/foundationgames/phonos/world/sound/WirePlugPoint.java b/src/main/java/io/github/foundationgames/phonos/world/sound/CablePlugPoint.java similarity index 97% rename from src/main/java/io/github/foundationgames/phonos/world/sound/WirePlugPoint.java rename to src/main/java/io/github/foundationgames/phonos/world/sound/CablePlugPoint.java index 7339ce5..0846149 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/sound/WirePlugPoint.java +++ b/src/main/java/io/github/foundationgames/phonos/world/sound/CablePlugPoint.java @@ -8,7 +8,7 @@ import org.joml.Vector3f; import org.joml.Vector4f; -public interface WirePlugPoint { +public interface CablePlugPoint { default Vec3d calculatePos(World world, double extend) { var originPose = new Pose3f(new Vector3f(), new Quaternionf()); var plugPose = new Pose3f(new Vector3f(), new Quaternionf()); diff --git a/src/main/java/io/github/foundationgames/phonos/world/sound/InputPlugPoint.java b/src/main/java/io/github/foundationgames/phonos/world/sound/InputPlugPoint.java index 6822426..d00bb9f 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/sound/InputPlugPoint.java +++ b/src/main/java/io/github/foundationgames/phonos/world/sound/InputPlugPoint.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; -public abstract class InputPlugPoint implements WirePlugPoint { +public abstract class InputPlugPoint implements CablePlugPoint { public static final RegistryKey> REGISTRY_KEY = RegistryKey.ofRegistry(Phonos.id("wire_plug_point")); public static final Registry REGISTRY = new SimpleRegistry<>(REGISTRY_KEY, Lifecycle.stable()); diff --git a/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockConnectionLayout.java b/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockConnectionLayout.java index 22dbb88..b012bb0 100644 --- a/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockConnectionLayout.java +++ b/src/main/java/io/github/foundationgames/phonos/world/sound/block/BlockConnectionLayout.java @@ -5,8 +5,8 @@ import io.github.foundationgames.phonos.util.PhonosUtil; import io.github.foundationgames.phonos.util.Pose3f; import io.github.foundationgames.phonos.util.UniqueId; +import io.github.foundationgames.phonos.world.sound.CablePlugPoint; import io.github.foundationgames.phonos.world.sound.InputPlugPoint; -import io.github.foundationgames.phonos.world.sound.WirePlugPoint; import io.github.foundationgames.phonos.world.sound.data.SoundData; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.BlockPos; @@ -194,7 +194,7 @@ public double z() { } } - public static class BlockOutput implements WirePlugPoint { + public static class BlockOutput implements CablePlugPoint { private final BlockPos blockPos; private final Pose3f pose; public final int connectionIndex; 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 e0a5a13..297b9c0 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 @@ -1,7 +1,7 @@ package io.github.foundationgames.phonos.world.sound.block; +import io.github.foundationgames.phonos.world.sound.CableConnection; import io.github.foundationgames.phonos.world.sound.InputPlugPoint; -import io.github.foundationgames.phonos.world.sound.WireConnection; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.ItemEntity; import net.minecraft.item.ItemStack; @@ -18,13 +18,13 @@ public class BlockEntityOutputs { private final boolean[] skip; // Will not be purged on first tick of existing - protected final WireConnection[] connections; + protected final CableConnection[] connections; protected final BlockConnectionLayout connectionLayout; protected final BlockEntity blockEntity; public BlockEntityOutputs(BlockConnectionLayout layout, BlockEntity blockEntity) { this.connectionLayout = layout; - this.connections = new WireConnection[layout.getConnectionCount()]; + this.connections = new CableConnection[layout.getConnectionCount()]; this.skip = new boolean[layout.getConnectionCount()]; this.blockEntity = blockEntity; } @@ -41,7 +41,7 @@ public boolean tryPlugOutputIn(int outputIndex, @Nullable DyeColor color, InputP } var srcOutput = connectionLayout.outputOfConnection(this.blockEntity.getPos(), outputIndex); - this.connections[outputIndex] = new WireConnection(srcOutput, destInput, color, cable); + this.connections[outputIndex] = new CableConnection(srcOutput, destInput, color, cable); this.skip[outputIndex] = true; return true; @@ -63,12 +63,12 @@ public boolean tryRemoveConnection(World world, BlockHitResult hit, boolean drop return false; } - public @Nullable WireConnection getOutputConnection(int outputIndex) { + public @Nullable CableConnection getOutputConnection(int outputIndex) { outputIndex = MathHelper.clamp(outputIndex, 0, connections.length - 1); return connections[outputIndex]; } - public void dropConnectionItem(World world, WireConnection conn, boolean atInput) { + public void dropConnectionItem(World world, CableConnection conn, boolean atInput) { var point = atInput ? conn.end : conn.start; var pos = point.calculatePos(world, 0.25); var item = new ItemEntity(world, pos.x, pos.y, pos.z, conn.drop); @@ -86,7 +86,7 @@ public int getOutputCount() { return count; } - public void forEach(BiConsumer action) { + public void forEach(BiConsumer action) { for (int i = 0; i < connections.length; i++) { if (connections[i] != null) { action.accept(i, connections[i]); @@ -94,7 +94,7 @@ public void forEach(BiConsumer action) { } } - public boolean purge(Consumer purgeAction) { + public boolean purge(Consumer purgeAction) { boolean changed = false; for (int i = 0; i < connections.length; i++) { if (skip[i]) { @@ -134,7 +134,7 @@ public void writeNbt(NbtCompound nbt) { var connNbt = nbt.getCompound(key); var outputPoint = this.connectionLayout.outputOfConnection(this.blockEntity.getPos(), i); - var conn = WireConnection.readNbt(this.blockEntity.getWorld(), outputPoint, connNbt); + var conn = CableConnection.readNbt(this.blockEntity.getWorld(), outputPoint, connNbt); if (conn != null) { nbt.remove(key); diff --git a/src/main/resources/assets/phonos/lang/en_us.json b/src/main/resources/assets/phonos/lang/en_us.json index 5bc2532..e5c9595 100644 --- a/src/main/resources/assets/phonos/lang/en_us.json +++ b/src/main/resources/assets/phonos/lang/en_us.json @@ -48,5 +48,14 @@ "item.phonos.purple_audio_cable": "Purple Audio Cable", "item.phonos.red_audio_cable": "Red Audio Cable", "item.phonos.white_audio_cable": "White Audio Cable", - "item.phonos.yellow_audio_cable": "Yellow Audio Cable" + "item.phonos.yellow_audio_cable": "Yellow Audio Cable", + + "text.config.phonos.title": "Phonos Client Config", + + "text.config.phonos.option.phonosMasterVolume": "Loudspeaker Master Volume", + "text.config.phonos.option.streamVolume": "Satellite Audio Volume", + + "text.config.phonos.option.cableLODs": "Use Detail Levels for Audio Cables", + "text.config.phonos.option.cableLODNearDetail": "Highest Audio Cable Detail Level", + "text.config.phonos.option.cableLODFarDetail": "Lowest Audio Cable Detail Level" } \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 263abbd..1849e6c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -23,6 +23,9 @@ ], "client": [ "io.github.foundationgames.phonos.PhonosClient" + ], + "modmenu": [ + "io.github.foundationgames.phonos.util.compat.PhonosModMenu" ] }, "mixins": [