diff --git a/TODO.md b/TODO.md index 94b1eae..93fdcbc 100644 --- a/TODO.md +++ b/TODO.md @@ -963,6 +963,7 @@ Events: * [x] Microphone. (Acoustic rostrum podium fixture) * [x] Speakers. (Public address acoustic amplifiers) * [x] Speaker NPC. (Fictional orator addressing civic assembly) +* [ ] Musica dell'Oratore: aggiungere a mano `src/main/resources/assets/israel_simulator/sounds/music/orator_boss_theme.ogg` (Ogg Vorbis; brano scelto da Riccardo, coperto da copyright e quindi non nel repo). Evento `music.boss.orator_theme` già registrato; senza file il client registra solo un warning. * [x] Crowd NPCs. (Civic crowd participants in forum area) * [x] Signs. (Civic banner proclamations on free expression) * [x] Chairs. (Forum seating arrangements) diff --git a/src/main/java/com/israelsimulator/client/music/KirkBossMusicClientEvents.java b/src/main/java/com/israelsimulator/client/music/KirkBossMusicClientEvents.java index 5a574b4..867769c 100644 --- a/src/main/java/com/israelsimulator/client/music/KirkBossMusicClientEvents.java +++ b/src/main/java/com/israelsimulator/client/music/KirkBossMusicClientEvents.java @@ -37,7 +37,14 @@ static void onClientTick(ClientTickEvent.Post event) { current = null; } if (current != null && !current.isFading()) { - return; + OratorEntity orator = current.orator(); + // Without orator_boss_theme.ogg the sound never starts (Minecraft only logs a warning), so + // tick() never runs: drop the instance once the Orator is gone so vanilla music comes back. + if (mc.getSoundManager().isActive(current) + || KirkBossMusicRules.shouldPlay(orator.isAlive(), orator.isRemoved(), orator.distanceToSqr(mc.player))) { + return; + } + current = null; } if (--scanCooldown > 0) { return; diff --git a/src/main/java/com/israelsimulator/client/music/KirkBossMusicInstance.java b/src/main/java/com/israelsimulator/client/music/KirkBossMusicInstance.java index dc3cc7e..4a955f6 100644 --- a/src/main/java/com/israelsimulator/client/music/KirkBossMusicInstance.java +++ b/src/main/java/com/israelsimulator/client/music/KirkBossMusicInstance.java @@ -17,7 +17,7 @@ public final class KirkBossMusicInstance extends AbstractTickableSoundInstance { private int fadeTicks; public KirkBossMusicInstance(OratorEntity orator) { - super(ModSoundEvents.KIRK_THEME.get(), SoundSource.MUSIC, RandomSource.create()); + super(ModSoundEvents.ORATOR_THEME.get(), SoundSource.MUSIC, RandomSource.create()); this.orator = orator; this.looping = false; this.delay = 0; diff --git a/src/main/java/com/israelsimulator/registry/ModSoundEvents.java b/src/main/java/com/israelsimulator/registry/ModSoundEvents.java index 8efeb5c..c5f2784 100644 --- a/src/main/java/com/israelsimulator/registry/ModSoundEvents.java +++ b/src/main/java/com/israelsimulator/registry/ModSoundEvents.java @@ -43,7 +43,7 @@ private static DeferredHolder registerSound(String name) public static final DeferredHolder BIBI_SPEECH = registerSound("entity.bibi_boss.speech"); public static final DeferredHolder BIBI_ENRAGE = registerSound("entity.bibi_boss.enrage"); public static final DeferredHolder BIBI_THEME = registerSound("music.boss.bibi_theme"); - public static final DeferredHolder KIRK_THEME = registerSound("music.boss.kirk_theme"); + public static final DeferredHolder ORATOR_THEME = registerSound("music.boss.orator_theme"); // Transportation Audio (§47) public static final DeferredHolder BICYCLE_BELL = registerSound("entity.bicycle.bell"); diff --git a/src/main/resources/assets/israel_simulator/lang/en_us.json b/src/main/resources/assets/israel_simulator/lang/en_us.json index b98a889..fba728c 100644 --- a/src/main/resources/assets/israel_simulator/lang/en_us.json +++ b/src/main/resources/assets/israel_simulator/lang/en_us.json @@ -263,7 +263,7 @@ "entity.israel_simulator.trump_miniboss": "Donald Trump", "entity.israel_simulator.ice_agent": "ICE Agent", "entity.israel_simulator.jeffrey_epstein": "Jeffrey Epstein", - "entity.israel_simulator.child_zombie_minion": "Epstein's Lawyer", + "entity.israel_simulator.child_zombie_minion": "Henchman", "entity.israel_simulator.money_changer": "Money Changer", "item.israel_simulator.money_changer_spawn_egg": "Money Changer Spawn Egg", "item.israel_simulator.pistol": "Security Pistol", diff --git a/src/main/resources/assets/israel_simulator/lang/it_it.json b/src/main/resources/assets/israel_simulator/lang/it_it.json index 87e295a..c87cea0 100644 --- a/src/main/resources/assets/israel_simulator/lang/it_it.json +++ b/src/main/resources/assets/israel_simulator/lang/it_it.json @@ -261,7 +261,7 @@ "entity.israel_simulator.trump_miniboss": "Donald Trump", "entity.israel_simulator.ice_agent": "Agente dell'ICE", "entity.israel_simulator.jeffrey_epstein": "Jeffrey Epstein", - "entity.israel_simulator.child_zombie_minion": "Avvocato di Epstein", + "entity.israel_simulator.child_zombie_minion": "Scagnozzo", "entity.israel_simulator.money_changer": "Cambiavalute", "item.israel_simulator.money_changer_spawn_egg": "Uovo generatore di cambiavalute", "item.israel_simulator.pistol": "Pistola", diff --git a/src/main/resources/assets/israel_simulator/sounds.json b/src/main/resources/assets/israel_simulator/sounds.json index 8516a11..3d2a1e0 100644 --- a/src/main/resources/assets/israel_simulator/sounds.json +++ b/src/main/resources/assets/israel_simulator/sounds.json @@ -93,10 +93,10 @@ } ] }, - "music.boss.kirk_theme": { + "music.boss.orator_theme": { "sounds": [ { - "name": "israel_simulator:music/kirk_boss_theme", + "name": "israel_simulator:music/orator_boss_theme", "stream": true } ] diff --git a/src/main/resources/assets/israel_simulator/sounds/music/kirk_boss_theme.ogg b/src/main/resources/assets/israel_simulator/sounds/music/kirk_boss_theme.ogg deleted file mode 100644 index 1b04dfb..0000000 Binary files a/src/main/resources/assets/israel_simulator/sounds/music/kirk_boss_theme.ogg and /dev/null differ diff --git a/src/test/java/com/israelsimulator/audio/KirkBossMusicTest.java b/src/test/java/com/israelsimulator/audio/KirkBossMusicTest.java index 700f5d5..ccc5309 100644 --- a/src/test/java/com/israelsimulator/audio/KirkBossMusicTest.java +++ b/src/test/java/com/israelsimulator/audio/KirkBossMusicTest.java @@ -25,17 +25,30 @@ void fadeOutReachesZero() { } @Test - void soundEventStreamsBundledOgg() throws Exception { + void oratorHasOwnStreamedTheme() throws Exception { String json = Files.readString(Path.of("src/main/resources/assets/israel_simulator/sounds.json")); - int i = json.indexOf("\"music.boss.kirk_theme\""); - assertTrue(i != -1, "music.boss.kirk_theme must be in sounds.json"); + int i = json.indexOf("\"music.boss.orator_theme\""); + assertTrue(i != -1, "music.boss.orator_theme must be in sounds.json"); String block = json.substring(i, json.indexOf("}", i) + 1); - assertTrue(block.contains("israel_simulator:music/kirk_boss_theme")); + assertTrue(block.contains("israel_simulator:music/orator_boss_theme")); assertTrue(block.contains("\"stream\": true")); - Path ogg = Path.of("src/main/resources/assets/israel_simulator/sounds/music/kirk_boss_theme.ogg"); - assertTrue(Files.exists(ogg), "kirk_boss_theme.ogg must exist"); - byte[] head = Files.readAllBytes(ogg); - assertEquals("OggS", new String(head, 0, 4)); + assertFalse(json.contains("music/kirk_boss_theme"), "the old copy of Bibi's theme must be gone"); + String inst = Files.readString(Path.of("src/main/java/com/israelsimulator/client/music/KirkBossMusicInstance.java")); + assertTrue(inst.contains("ModSoundEvents.ORATOR_THEME"), "the Orator must not reuse Bibi's theme"); + assertFalse(inst.contains("BIBI_THEME")); + // The Ogg is optional (owner adds it); if present it must be a real Ogg. + Path ogg = Path.of("src/main/resources/assets/israel_simulator/sounds/music/orator_boss_theme.ogg"); + if (Files.exists(ogg)) { + byte[] head = Files.readAllBytes(ogg); + assertEquals("OggS", new String(head, 0, 4)); + } + } + + @Test + void missingOggDoesNotSilenceVanillaMusicForever() throws Exception { + String ev = Files.readString(Path.of("src/main/java/com/israelsimulator/client/music/KirkBossMusicClientEvents.java")); + assertTrue(ev.contains("getSoundManager().isActive(current)")); + assertTrue(ev.contains("current = null;")); } @Test diff --git a/src/test/java/com/israelsimulator/audio/MusicAndAudioTest.java b/src/test/java/com/israelsimulator/audio/MusicAndAudioTest.java index 2720501..54de397 100644 --- a/src/test/java/com/israelsimulator/audio/MusicAndAudioTest.java +++ b/src/test/java/com/israelsimulator/audio/MusicAndAudioTest.java @@ -24,7 +24,7 @@ void testSoundEventClassAndFields() throws Exception { assertNotNull(soundClass.getField("JERUSALEM_AMBIENT")); assertNotNull(soundClass.getField("JAFFA_AMBIENT")); assertNotNull(soundClass.getField("BIBI_THEME")); - assertNotNull(soundClass.getField("KIRK_THEME")); + assertNotNull(soundClass.getField("ORATOR_THEME")); assertNotNull(soundClass.getField("BICYCLE_BELL")); assertNotNull(soundClass.getField("BUS_HORN")); assertNotNull(soundClass.getField("TRAIN_WHISTLE")); @@ -46,7 +46,7 @@ void testSoundsJsonIntegrity() throws Exception { assertTrue(content.contains("ambient.city.jerusalem"), "sounds.json must define jerusalem ambience"); assertTrue(content.contains("ambient.city.jaffa"), "sounds.json must define jaffa ambience"); assertTrue(content.contains("music.boss.bibi_theme"), "sounds.json must define bibi_theme"); - assertTrue(content.contains("music.boss.kirk_theme"), "sounds.json must define kirk_theme"); + assertTrue(content.contains("music.boss.orator_theme"), "sounds.json must define orator_theme"); assertTrue(content.contains("entity.bicycle.bell"), "sounds.json must define bicycle bell"); assertTrue(content.contains("entity.bus.horn"), "sounds.json must define bus horn"); assertTrue(content.contains("entity.train.whistle"), "sounds.json must define train whistle"); diff --git a/src/test/java/com/israelsimulator/validation/DataAndResourceValidationTest.java b/src/test/java/com/israelsimulator/validation/DataAndResourceValidationTest.java index 84b203a..0df8b19 100644 --- a/src/test/java/com/israelsimulator/validation/DataAndResourceValidationTest.java +++ b/src/test/java/com/israelsimulator/validation/DataAndResourceValidationTest.java @@ -57,7 +57,7 @@ public class DataAndResourceValidationTest { "ambient.event.speech_crowd", "ambient.event.market_bustle", "audio.festival.hanukkah_chime", "audio.festival.shabbat_candle", "entity.bibi_boss.ambient", "entity.bibi_boss.hurt", "entity.bibi_boss.death", "entity.bibi_boss.speech", "entity.bibi_boss.enrage", - "music.boss.bibi_theme", "entity.bicycle.bell", "entity.bus.horn", + "music.boss.bibi_theme", "music.boss.orator_theme", "entity.bicycle.bell", "entity.bus.horn", "entity.train.whistle", "entity.transport.travel", "ui.landmark_discovered" ); @@ -355,6 +355,14 @@ void testVanillaSoundFilesExist() throws IOException { } } + /** + * Custom sounds whose Ogg the owner adds by hand (copyrighted songs, not shipped in the repo). + * A missing file only makes the client log a warning; the sound event stays registered. + */ + public static final java.util.Set USER_PROVIDED_SOUND_FILES = java.util.Set.of( + "music/orator_boss_theme" + ); + @Test @DisplayName("Every custom sound in sounds.json has a bundled, non-empty Ogg file") void testCustomSoundFilesExist() throws IOException { @@ -375,6 +383,7 @@ void testCustomSoundFilesExist() throws IOException { && "event".equals(entry.getAsJsonObject().get("type").getAsString())) continue; String relative = name.contains(":") ? name.substring(name.indexOf(':') + 1) : name; Path ogg = soundsDir.resolve(relative + ".ogg"); + if (USER_PROVIDED_SOUND_FILES.contains(relative) && !Files.exists(ogg)) continue; if (!Files.exists(ogg) || Files.size(ogg) < 64) { missing.add(event.getKey() + " -> " + ogg); continue; diff --git a/test.md b/test.md index 9ddae1b..86a140a 100644 --- a/test.md +++ b/test.md @@ -974,3 +974,8 @@ Non provato dall'utente in gioco. - Coltivazioni: olivo ed erbe si raccolgono con il click destro e ricrescono. La vite torna all'età 3. Pomodoro e ceci crescono e lasciano il raccolto. - Commerci: il Money Changer e lo Shuk Vendor hanno scambi validi. - Nota: il Goy appena evocato non ha una professione, quindi non ha scambi (come un villager vanilla disoccupato). + +## Oratore con la musica di Bibi e scagnozzi di Epstein chiamati "Avvocato di Epstein" +- Problema riscontrato: durante il discorso l'Oratore suonava `kirk_boss_theme.ogg`, che era una copia byte per byte di `bibi_boss_theme.ogg`, quindi i due boss avevano la stessa musica. Gli scagnozzi di Epstein (`child_zombie_minion`) si chiamavano "Avvocato di Epstein" / "Epstein's Lawyer". +- Funzionamento atteso: l'Oratore ha un tema suo (`music.boss.orator_theme` → `music/orator_boss_theme`, in streaming) e il nome resta quello di prima. Gli scagnozzi non hanno più quel nome: il tipo di entità mostra solo un nome generico ("Scagnozzo" / "Henchman"), nessun nome custom. +- Soluzione: nuovo evento `ORATOR_THEME` in `ModSoundEvents` e in `sounds.json`, usato da `KirkBossMusicInstance` al posto della vecchia copia; tolti `music.boss.kirk_theme` e `kirk_boss_theme.ogg`. Il file `orator_boss_theme.ogg` lo aggiunge Riccardo (brano con copyright): finché manca, Minecraft scrive solo un warning e `KirkBossMusicClientEvents` rilascia l'istanza quando l'Oratore sparisce, così la musica vanilla torna. `testCustomSoundFilesExist` salta solo i file in `USER_PROVIDED_SOUND_FILES`; `KirkBossMusicTest` verifica il nuovo evento, che l'Oratore non usi il tema di Bibi e il rilascio senza file. Lang: `entity.israel_simulator.child_zombie_minion` = "Scagnozzo" / "Henchman".