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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private static DeferredHolder<SoundEvent, SoundEvent> registerSound(String name)
public static final DeferredHolder<SoundEvent, SoundEvent> BIBI_SPEECH = registerSound("entity.bibi_boss.speech");
public static final DeferredHolder<SoundEvent, SoundEvent> BIBI_ENRAGE = registerSound("entity.bibi_boss.enrage");
public static final DeferredHolder<SoundEvent, SoundEvent> BIBI_THEME = registerSound("music.boss.bibi_theme");
public static final DeferredHolder<SoundEvent, SoundEvent> KIRK_THEME = registerSound("music.boss.kirk_theme");
public static final DeferredHolder<SoundEvent, SoundEvent> ORATOR_THEME = registerSound("music.boss.orator_theme");

// Transportation Audio (§47)
public static final DeferredHolder<SoundEvent, SoundEvent> BICYCLE_BELL = registerSound("entity.bicycle.bell");
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/assets/israel_simulator/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/assets/israel_simulator/lang/it_it.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/assets/israel_simulator/sounds.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
Expand Down
Binary file not shown.
29 changes: 21 additions & 8 deletions src/test/java/com/israelsimulator/audio/KirkBossMusicTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand All @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
);

Expand Down Expand Up @@ -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<String> 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 {
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions test.md
Original file line number Diff line number Diff line change
Expand Up @@ -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".
Loading