fix(ambiance): attendre la synchronisation du disque blanc #84
@@ -6,6 +6,15 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
|
||||
- Depuis `26.2.0-alpha.6`, le pack et les modules ont des versions indépendantes. I Like To Move It et Only Fun deviennent les cinquième et sixième modules actifs dans l'alpha 46.
|
||||
- Les versions ci-dessous ont été reconstituées à partir des JAR archivés, des packs locaux et du code source actuel. Les dates n'étant pas enregistrées de manière fiable, elles ne sont pas inventées.
|
||||
|
||||
## Modifications non distribuées
|
||||
|
||||
Module modifié : **Ambiance `0.0.0-alpha.17`**.
|
||||
|
||||
- attend de façon bornée la synchronisation client du jukebox avant de charger un disque blanc, ce qui rétablit sa lecture en solo ;
|
||||
- affiche immédiatement le chargement puis un échec explicite si le jukebox n'est toujours pas synchronisé après cinq secondes ;
|
||||
- accepte toujours les liens de partage YouTube avec paramètres, notamment `https://youtu.be/Ue5ZBe-GzSM?si=…` ;
|
||||
- conserve les données Ambiance v2 et le protocole réseau 6, sans migration de sauvegarde.
|
||||
|
||||
## `26.2.0-alpha.213`
|
||||
|
||||
Module modifié : **Ambiance `0.0.0-alpha.16`**. Les neuf autres modules conservent leur version issue de l'alpha.212.
|
||||
|
||||
@@ -70,7 +70,7 @@ tasks.named("test") {
|
||||
|
||||
tasks.register("verifyAmbiance") {
|
||||
group = "verification"
|
||||
description = "Checks Ambiance alpha.16, including the Minecraft 26.2 white-disc event hook."
|
||||
description = "Checks Ambiance alpha.17, including deferred white-disc playback startup."
|
||||
inputs.files(fileTree("src/main/java"))
|
||||
inputs.files(fileTree("src/main/resources"))
|
||||
inputs.file(rootProject.file("pack/migrations/26.2.0-alpha.125-realtime-calendar-to-alpha.126.json"))
|
||||
@@ -123,7 +123,7 @@ tasks.register("verifyAmbiance") {
|
||||
def levelEventMixin = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/ambiance/mixin/client/LevelEventHandlerMixin.java").text
|
||||
|
||||
if (project.version.toString() != "0.0.0-alpha.16"
|
||||
if (project.version.toString() != "0.0.0-alpha.17"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.125"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.126"
|
||||
|| migration.target?.modules?.ambiance != "0.0.0-alpha.1"
|
||||
@@ -321,7 +321,9 @@ tasks.register("verifyAmbiance") {
|
||||
|| !javaText.contains('PlayerLookup.tracking(level, pos)')
|
||||
|| !javaText.contains('ServerPlayNetworking.canSend(receiver, WhiteDiscPlaybackPayload.ID)')
|
||||
|| !javaText.contains('MAXIMUM_SIMULTANEOUS_DISCS = 4')
|
||||
|| !javaText.contains('REQUESTS.size() + PLAYBACKS.size() >= MAXIMUM_SIMULTANEOUS_DISCS')
|
||||
|| !javaText.contains('PENDING_STARTS.size() + REQUESTS.size() + PLAYBACKS.size()')
|
||||
|| !javaText.contains('MAXIMUM_START_WAIT_TICKS = 100')
|
||||
|| !javaText.contains('tickPendingStarts(client)')
|
||||
|| !javaText.contains('client.level.dimension().equals(playback.dimension())')
|
||||
|| !javaText.contains('MAXIMUM_TRACK_MILLIS = 30L * 60L * 1_000L')
|
||||
|| !javaText.contains('new Pcm16AudioDataFormat(1, LavaplayerAudioStream.SAMPLE_RATE')
|
||||
@@ -347,7 +349,7 @@ tasks.register("verifyAmbiance") {
|
||||
}
|
||||
|| !file("build.gradle").text.contains('dev.arbjerg:lavaplayer:2.2.7')
|
||||
|| !file("build.gradle").text.contains('dev.lavalink.youtube:v2:1.18.2')) {
|
||||
throw new GradleException("Ambiance alpha.16 white-disc playback contract is incomplete")
|
||||
throw new GradleException("Ambiance alpha.17 white-disc playback contract is incomplete")
|
||||
}
|
||||
|
||||
[
|
||||
|
||||
+57
-6
@@ -30,10 +30,12 @@ import net.minecraft.world.phys.Vec3;
|
||||
/** Client-only, positional and resource-bounded YouTube playback for white discs. */
|
||||
public final class WhiteDiscAudioPlayer {
|
||||
private static final int MAXIMUM_SIMULTANEOUS_DISCS = 4;
|
||||
private static final int MAXIMUM_START_WAIT_TICKS = 100;
|
||||
private static final long MAXIMUM_TRACK_MILLIS = 30L * 60L * 1_000L;
|
||||
private static final long FINISHED_GRACE_NANOS = 5_000_000_000L;
|
||||
private static final float ATTENUATION_DISTANCE = 64.0F;
|
||||
private static final DefaultAudioPlayerManager MANAGER = createManager();
|
||||
private static final Map<Long, PendingStart> PENDING_STARTS = new HashMap<>();
|
||||
private static final Map<Long, Long> REQUESTS = new HashMap<>();
|
||||
private static final LinkedHashMap<Long, Playback> PLAYBACKS = new LinkedHashMap<>();
|
||||
private static long requestSequence;
|
||||
@@ -43,16 +45,27 @@ public final class WhiteDiscAudioPlayer {
|
||||
}
|
||||
|
||||
public static void play(Minecraft client, BlockPos pos, String videoId) {
|
||||
if (shutdown || !WhiteDiscUrl.validVideoId(videoId) || !validTarget(client, pos)) return;
|
||||
if (shutdown || !WhiteDiscUrl.validVideoId(videoId) || !validJukeboxTarget(client, pos)) return;
|
||||
long key = pos.asLong();
|
||||
if (REQUESTS.containsKey(key)) return;
|
||||
if (PENDING_STARTS.containsKey(key) || REQUESTS.containsKey(key)) return;
|
||||
boolean replacingPlayback = PLAYBACKS.containsKey(key);
|
||||
if (!replacingPlayback
|
||||
&& REQUESTS.size() + PLAYBACKS.size() >= MAXIMUM_SIMULTANEOUS_DISCS) return;
|
||||
&& PENDING_STARTS.size() + REQUESTS.size() + PLAYBACKS.size()
|
||||
>= MAXIMUM_SIMULTANEOUS_DISCS) return;
|
||||
stop(key);
|
||||
client.player.sendOverlayMessage(Component.translatable("message.ambiance.white_disc.loading"));
|
||||
if (!validTarget(client, pos)) {
|
||||
PENDING_STARTS.put(key, new PendingStart(pos.immutable(), client.level.dimension(), videoId,
|
||||
MAXIMUM_START_WAIT_TICKS));
|
||||
return;
|
||||
}
|
||||
startLoading(client, pos, videoId);
|
||||
}
|
||||
|
||||
private static void startLoading(Minecraft client, BlockPos pos, String videoId) {
|
||||
long key = pos.asLong();
|
||||
long request = ++requestSequence;
|
||||
REQUESTS.put(key, request);
|
||||
client.player.sendOverlayMessage(Component.translatable("message.ambiance.white_disc.loading"));
|
||||
MANAGER.loadItemOrdered(key, WhiteDiscUrl.canonicalUrl(videoId), new AudioLoadResultHandler() {
|
||||
@Override
|
||||
public void trackLoaded(AudioTrack track) {
|
||||
@@ -137,6 +150,7 @@ public final class WhiteDiscAudioPlayer {
|
||||
}
|
||||
|
||||
private static void stop(long key) {
|
||||
PENDING_STARTS.remove(key);
|
||||
REQUESTS.remove(key);
|
||||
Playback playback = PLAYBACKS.remove(key);
|
||||
if (playback == null) return;
|
||||
@@ -150,6 +164,7 @@ public final class WhiteDiscAudioPlayer {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
tickPendingStarts(client);
|
||||
long now = System.nanoTime();
|
||||
for (Map.Entry<Long, Playback> entry : Map.copyOf(PLAYBACKS).entrySet()) {
|
||||
Playback playback = entry.getValue();
|
||||
@@ -167,6 +182,7 @@ public final class WhiteDiscAudioPlayer {
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
PENDING_STARTS.clear();
|
||||
REQUESTS.clear();
|
||||
for (long key : PLAYBACKS.keySet().stream().mapToLong(Long::longValue).toArray()) stop(key);
|
||||
}
|
||||
@@ -189,11 +205,46 @@ public final class WhiteDiscAudioPlayer {
|
||||
}
|
||||
|
||||
private static boolean validTarget(Minecraft client, BlockPos pos) {
|
||||
return validJukeboxTarget(client, pos)
|
||||
&& client.level.getBlockState(pos).getValue(JukeboxBlock.HAS_RECORD);
|
||||
}
|
||||
|
||||
private static boolean validJukeboxTarget(Minecraft client, BlockPos pos) {
|
||||
return client.player != null && client.level != null
|
||||
&& client.player.distanceToSqr(Vec3.atCenterOf(pos))
|
||||
<= ATTENUATION_DISTANCE * ATTENUATION_DISTANCE * 4.0D
|
||||
&& client.level.getBlockState(pos).is(Blocks.JUKEBOX)
|
||||
&& client.level.getBlockState(pos).getValue(JukeboxBlock.HAS_RECORD);
|
||||
&& client.level.getBlockState(pos).is(Blocks.JUKEBOX);
|
||||
}
|
||||
|
||||
private static void tickPendingStarts(Minecraft client) {
|
||||
for (Map.Entry<Long, PendingStart> entry : Map.copyOf(PENDING_STARTS).entrySet()) {
|
||||
long key = entry.getKey();
|
||||
PendingStart pending = entry.getValue();
|
||||
if (!client.level.dimension().equals(pending.dimension())
|
||||
|| !validJukeboxTarget(client, pending.pos())) {
|
||||
PENDING_STARTS.remove(key);
|
||||
continue;
|
||||
}
|
||||
if (validTarget(client, pending.pos())) {
|
||||
PENDING_STARTS.remove(key);
|
||||
startLoading(client, pending.pos(), pending.videoId());
|
||||
continue;
|
||||
}
|
||||
if (pending.ticksRemaining() <= 1) {
|
||||
PENDING_STARTS.remove(key);
|
||||
if (client.player != null) client.player.sendOverlayMessage(
|
||||
Component.translatable("message.ambiance.white_disc.failed"));
|
||||
continue;
|
||||
}
|
||||
PENDING_STARTS.put(key, pending.waitOneTick());
|
||||
}
|
||||
}
|
||||
|
||||
private record PendingStart(BlockPos pos, ResourceKey<Level> dimension, String videoId,
|
||||
int ticksRemaining) {
|
||||
private PendingStart waitOneTick() {
|
||||
return new PendingStart(pos, dimension, videoId, ticksRemaining - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private record Playback(BlockPos pos, ResourceKey<Level> dimension,
|
||||
|
||||
+2
@@ -10,6 +10,8 @@ public final class WhiteDiscUrlSmoke {
|
||||
public static void main(String[] args) {
|
||||
require(VIDEO_ID.equals(id("https://www.youtube.com/watch?v=" + VIDEO_ID)), "watch URL rejected");
|
||||
require(VIDEO_ID.equals(id("https://youtu.be/" + VIDEO_ID + "?si=abc")), "short URL rejected");
|
||||
require("Ue5ZBe-GzSM".equals(id("https://youtu.be/Ue5ZBe-GzSM?si=78LSbtBQzUYzhA2Y")),
|
||||
"reported white-disc URL rejected");
|
||||
require(VIDEO_ID.equals(id("https://music.youtube.com/watch?v=" + VIDEO_ID)), "music URL rejected");
|
||||
require(VIDEO_ID.equals(id("https://www.youtube.com/shorts/" + VIDEO_ID)), "shorts URL rejected");
|
||||
require(VIDEO_ID.equals(id("https://www.youtube.com/embed/" + VIDEO_ID)), "embed URL rejected");
|
||||
|
||||
+5
-6
@@ -4548,7 +4548,7 @@ tasks.register("verifyWeatherTntAmbianceRelease") {
|
||||
def ouchManifest = new JsonSlurper().parse(file("ouch/src/main/resources/fabric.mod.json"))
|
||||
def rootBuild = file("build.gradle").text
|
||||
if (rootProject.pack_version != "26.2.0-alpha.213"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.16"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.17"
|
||||
|| rootProject.ouch_version != "0.0.0-alpha.10"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.199"
|
||||
|| migration.source?.modules != [ambiance: "0.0.0-alpha.11", ouch: "0.0.0-alpha.8"]
|
||||
@@ -5319,7 +5319,7 @@ tasks.register("verifyCanapliaFoundation") {
|
||||
"ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/api/visual/AmbianceVisualEffectApi.java").text
|
||||
if (rootProject.pack_version != "26.2.0-alpha.213"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.16"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.17"
|
||||
|| migration.issue != 35
|
||||
|| migration.source?.fabric_id != "canaplia"
|
||||
|| migration.source?.version != "2.0.0"
|
||||
@@ -5570,7 +5570,7 @@ tasks.register("verifyCanapliaAlpha209Release") {
|
||||
itsalive: "0.0.0-alpha.33",
|
||||
onlyfun: "0.0.0-alpha.20"]
|
||||
if (rootProject.pack_version != "26.2.0-alpha.213"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.16"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.17"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.24"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.207"
|
||||
@@ -5785,7 +5785,7 @@ tasks.register("verifyAlpha211Release") {
|
||||
def currentModules = expectedTarget + [
|
||||
sanctuary: "0.0.0-alpha.120",
|
||||
ambiance: "0.0.0-alpha.16"]
|
||||
def workspaceModules = currentModules + [ambiance: "0.0.0-alpha.16"]
|
||||
def workspaceModules = currentModules + [ambiance: "0.0.0-alpha.17"]
|
||||
def expectedDataVersions = [ambiance: 2, itsalive: 3, onlyfun: 2, ouch: 1, sanctuary: 11]
|
||||
def expectedProtocols = [ambiance: 6, itsalive: 4, onlyfun: 3, ouch: 1, sanctuary: 22]
|
||||
def manifests = expectedTarget.collectEntries { id, version ->
|
||||
@@ -5948,7 +5948,7 @@ tasks.register("verifyAlpha213Release") {
|
||||
it.path == "mods/jei-26.2-fabric-30.28.0.193.jar"
|
||||
}
|
||||
if (rootProject.pack_version != "26.2.0-alpha.213"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.16"
|
||||
|| rootProject.ambiance_version != "0.0.0-alpha.17"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.212"
|
||||
|| migration.source?.modules != [ambiance: "0.0.0-alpha.15"]
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.213"
|
||||
@@ -5980,7 +5980,6 @@ tasks.register("verifyAlpha213Release") {
|
||||
|| !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.16.jar"')
|
||||
|| packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.15.jar"')
|
||||
|| !changelog.contains("## `26.2.0-alpha.213`")
|
||||
|| changelog.contains("## Modifications non distribuées")
|
||||
|| !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.213`**")) {
|
||||
throw new GradleException("The alpha.213 Ambiance startup-fix release is incomplete")
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fabric_api_version=0.158.0+26.2
|
||||
# Standby modules stay at zero until their migration really begins.
|
||||
mod_version=0.0.0-alpha.0
|
||||
module_lifecycle=standby
|
||||
ambiance_version=0.0.0-alpha.16
|
||||
ambiance_version=0.0.0-alpha.17
|
||||
ambiance_lifecycle=active
|
||||
redstoner_version=0.0.0-alpha.10
|
||||
redstoner_lifecycle=active
|
||||
|
||||
Reference in New Issue
Block a user