diff --git a/CHANGELOG.md b/CHANGELOG.md index 171e41c..942ac8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,17 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve Aucun changement non publié. +## `26.2.0-alpha.235` + +Module modifié temporairement : **ZEVENT `0.0.0-alpha.3`**. + +- remplace MCEF Modern, dont Chromium ne sait pas décoder les directs Twitch en H.264/AAC, par Dream Displays `1.9.6` et son pipeline vidéo natif ; +- conserve le bloc-écran 9 × 5, les chaînes enregistrées, l’interface et le protocole réseau ZEVENT 1 sans migration de monde ; +- réutilise directement la texture GPU décodée dans le renderer ZEVENT, avec une limite de 720p et deux flux visibles au maximum par client ; +- maintient le volume dans la catégorie Disques, l’atténuation jusqu’à 64 blocs et un seul écran audible à la fois ; +- réessaie automatiquement les chaînes momentanément indisponibles et affiche désormais un message explicite lorsqu’une chaîne est hors ligne ; +- valide le démarrage client natif sur macOS Apple Silicon ainsi que la résolution d’un direct Twitch actif en cinq qualités H.264 jusqu’en 1080p avec audio AAC. + ## `26.2.0-alpha.234` Module ajouté temporairement : **ZEVENT `0.0.0-alpha.2`**. diff --git a/README.md b/README.md index 621a735..8de5754 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,13 @@ Licence : **GNU GPL 3.0 or Later** (`GPL-3.0-or-later`) | `sanctuary` | Sanctuary | progression et aventure | progression globale, classements publics, Atlas et monde principal flottant | | `events` | Events | événements serveur | socle vide | | `masterkey` | MasterKey | administration et diagnostic | laboratoire minimal | -| `zevent` | ZEVENT | diffusion Twitch temporaire | écran mural 9×5, inclus dans l’alpha.234 pour le week-end | +| `zevent` | ZEVENT | diffusion Twitch temporaire | écran mural 9×5, inclus pour le week-end | Les descriptions FR/EN/RU sont déclarées dans chaque `fabric.mod.json` et dans les fichiers de langue. Les images fournies servent d'icônes Fabric de leur module. -Version courante du pack distribué : **`26.2.0-alpha.234`**. Cette release conserve Another World **`0.0.0-alpha.58`**, Sanctuary **`0.0.0-alpha.139`** et Red-Stoner **`0.0.0-alpha.20`**, ajoute temporairement ZEVENT **`0.0.0-alpha.2`** aux dix modules de l’alpha.233 et installe MCEF Modern **`0.3.3+mc26.2.jcef146.0.10`** uniquement sur les clients. +Version courante du pack distribué : **`26.2.0-alpha.235`**. Cette release conserve notamment Another World **`0.0.0-alpha.58`**, Sanctuary **`0.0.0-alpha.139`** et Red-Stoner **`0.0.0-alpha.20`**, passe temporairement ZEVENT en **`0.0.0-alpha.3`** et remplace MCEF Modern par Dream Displays **`1.9.6`** afin de décoder réellement les directs Twitch en H.264/AAC. + +L’alpha.235 corrige l’écran noir de ZEVENT. MCEF chargeait correctement l’interface et les liens Twitch, mais son Chromium ne prenait pas en charge les codecs des directs. L’écran utilise désormais le résolveur HLS et le décodeur natif de Dream Displays, conserve ses options et sa synchronisation serveur, réessaie automatiquement un flux indisponible et indique clairement lorsqu’une chaîne est hors ligne. Le volume suit toujours la catégorie Disques, décroît jusqu’à 64 blocs et seul l’écran visible le plus proche reste audible. L’alpha.234 ajoute pour le week-end l’écran Twitch ZEVENT de 9 × 5 blocs. Un clic droit permet de choisir une chaîne officielle ; la sélection est enregistrée par le serveur, tandis que l’image et le son sont rendus localement avec MCEF Modern. Le volume suit la catégorie Disques et décroît jusqu’à 64 blocs. Les mondes et les dix modules Sanctuary existants restent compatibles ; le client et le serveur doivent toutefois recevoir le JAR ZEVENT, et seul le client reçoit MCEF. @@ -421,7 +423,7 @@ Le menu pause est lui aussi possédé par Sanctuary. Il ne conserve que Retour a ## Versions du modpack et mises à jour Modrinth -`pack_version` dans `gradle.properties` est la version du pack complet. `mod_version=0.0.0-alpha.0` et `module_lifecycle=standby` sont les valeurs par défaut des modules en veille ; les propriétés `_version` et `_lifecycle` n’activent et ne font avancer que le module concerné. Le contrat de distribution est dans `pack/release.json`. Pour l’alpha.234, `zevent` rejoint temporairement les archives du pack ; MCEF reste une dépendance strictement cliente afin que le serveur dédié n’embarque pas Chromium. +`pack_version` dans `gradle.properties` est la version du pack complet. `mod_version=0.0.0-alpha.0` et `module_lifecycle=standby` sont les valeurs par défaut des modules en veille ; les propriétés `_version` et `_lifecycle` n’activent et ne font avancer que le module concerné. Le contrat de distribution est dans `pack/release.json`. Pour l’alpha.235, `zevent` reste temporairement dans les archives du pack et utilise Dream Displays pour la lecture native des flux Twitch. La version globale du pack n’est pas injectée dans les JAR inchangés : leur contenu et leur numéro restent immuables. Le lanceur possède la composition exacte du pack, tandis que chaque manifest conserve la version effective de son module. diff --git a/build.gradle b/build.gradle index b98deff..3b72e41 100644 --- a/build.gradle +++ b/build.gradle @@ -2922,7 +2922,7 @@ tasks.register("verifyNotchEncounter") { || rootProject.ouch_version != "0.0.0-alpha.11" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.masterkey_version != "0.0.0-alpha.9" - || rootProject.pack_version != "26.2.0-alpha.234" + || rootProject.pack_version != "26.2.0-alpha.235" || manifests.itsalive.custom?.sanctuary26?.data_version != 4 || manifests.sanctuary.custom?.sanctuary26?.data_version != 15 || manifests.ouch.depends?.itsalive != ">=0.0.0-alpha.37" @@ -3011,7 +3011,7 @@ tasks.register("verifyMagicCarpet") { "iliketomoveit/src/main/resources/assets/iliketomoveit/models/item/magic_carpet.json")) def carpetTexture = file( "iliketomoveit/src/main/resources/assets/iliketomoveit/textures/item/magic_carpet.png") - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.iliketomoveit_version != "0.0.0-alpha.18" || rootProject.onlyfun_version != "0.0.0-alpha.27" || rootProject.sanctuary_version != "0.0.0-alpha.139" @@ -3644,7 +3644,7 @@ tasks.register("verifyProgressivePauseMenuRelease") { [(locale): new JsonSlurper().parse(file( "sanctuary/src/main/resources/assets/sanctuary/lang/${locale}.json"))] } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.onlyfun_version != "0.0.0-alpha.27" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version @@ -3694,7 +3694,7 @@ tasks.register("verifyMirrorLavenderDrawerRelease") { def redStonerRegistry = file( "redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/registry/RedStonerRegistries.java").text def drawerRecipe = file("redstoner/src/main/resources/data/redstoner/recipe/drawer.json") - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || rootProject.redstoner_version != "0.0.0-alpha.20" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version @@ -4676,7 +4676,7 @@ tasks.register("verifyShopPricingLayoutRelease") { "pack/migrations/26.2.0-alpha.192-shop-pricing-layout-to-alpha.193.json")) def release = new JsonSlurper().parse(file("pack/release.json")) def index = new JsonSlurper().parse(file("pack/prism/modrinth.index.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.onlyfun_version != "0.0.0-alpha.27" || rootProject.sanctuary_version != "0.0.0-alpha.139" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version @@ -4721,7 +4721,7 @@ tasks.register("verifyCuisineCropsRelease") { def climate = file("itsalive/src/main/java/fr/koka99cab/sanctuary26/itsalive/agriculture/ClimateCropForaging.java").text def rice = file("itsalive/src/main/java/fr/koka99cab/sanctuary26/itsalive/agriculture/RiceCropBlock.java").text def bean = file("itsalive/src/main/java/fr/koka99cab/sanctuary26/itsalive/agriculture/BeanCropBlock.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.itsalive_version != "0.0.0-alpha.38" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version || migration.source?.pack_version != "26.2.0-alpha.193" @@ -4770,7 +4770,7 @@ tasks.register("verifyShopCsvBossGatesRelease") { def bossGate = file("onlyfun/src/main/java/fr/koka99cab/sanctuary26/onlyfun/shop/OnlyFunBossShopGate.java").text def catalog = file("onlyfun/src/main/java/fr/koka99cab/sanctuary26/onlyfun/shop/OnlyFunShopCatalog.java").text def offerCatalog = file("sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.onlyfun_version != "0.0.0-alpha.27" || rootProject.sanctuary_version != "0.0.0-alpha.139" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version @@ -4817,7 +4817,7 @@ tasks.register("verifyCulinaryMailboxGrappleFixesRelease") { def release = new JsonSlurper().parse(file("pack/release.json")) def prism = new JsonSlurper().parse(file("pack/prism/modrinth.index.json")) def packwiz = file("pack/packwiz/pack.toml").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || migration.source?.pack_version != "26.2.0-alpha.195" || migration.target?.pack_version != "26.2.0-alpha.196" || migration.target?.modules != [ @@ -4835,10 +4835,10 @@ tasks.register("verifyCulinaryMailboxGrappleFixesRelease") { || migration.distribution?.jei?.target != "30.26.0.182" || migration.compatibility?.save_migration_required != false || migration.compatibility?.registry_ids_changed != false - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"')) { + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"')) { throw new GradleException("The alpha.196 culinary, mailbox and grapple release contract is incomplete") } } @@ -4863,7 +4863,7 @@ tasks.register("verifyQuestRequestsCauldronBatchesRelease") { def prism = new JsonSlurper().parse(file("pack/prism/modrinth.index.json")) def packwiz = file("pack/packwiz/pack.toml").text def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.itsalive_version != "0.0.0-alpha.38" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.196" @@ -4883,10 +4883,10 @@ tasks.register("verifyQuestRequestsCauldronBatchesRelease") { || migration.distribution?.jei?.target != "30.26.0.186" || migration.compatibility?.sanctuary_target_network_protocol != 19 || sanctuaryManifest.custom?.sanctuary26?.network_protocol != 24 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"')) { + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"')) { throw new GradleException("The alpha.197 quest-request and cauldron-batch release contract is incomplete") } } @@ -4913,7 +4913,7 @@ tasks.register("verifyFermentationBarrelAutomationRelease") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def itsAliveManifest = new JsonSlurper().parse(file("itsalive/src/main/resources/fabric.mod.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.itsalive_version != "0.0.0-alpha.38" || migration.source?.pack_version != "26.2.0-alpha.197" || migration.target?.pack_version != "26.2.0-alpha.198" @@ -4932,10 +4932,10 @@ tasks.register("verifyFermentationBarrelAutomationRelease") { || migration.distribution?.packwiz_index_refreshed != true || itsAliveManifest.custom?.sanctuary26?.data_version != 4 || itsAliveManifest.custom?.sanctuary26?.network_protocol != 4 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.38.jar"')) { throw new GradleException("The alpha.198 fermentation barrel release contract is incomplete") } @@ -4963,7 +4963,7 @@ tasks.register("verifyQuestRequestContractsRelease") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.itsalive_version != "0.0.0-alpha.38" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.198" @@ -4977,10 +4977,10 @@ tasks.register("verifyQuestRequestContractsRelease") { || migration.quest_request_contracts?.chat_accept_revalidates_distance_owner_sign_and_claim != true || migration.compatibility?.sanctuary_target_network_protocol != 20 || sanctuaryManifest.custom?.sanctuary26?.network_protocol != 24 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.38.jar"') || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"')) { throw new GradleException("The alpha.199 quest-request contract release is incomplete") @@ -5018,7 +5018,7 @@ tasks.register("verifyWeatherTntAmbianceRelease") { def ambianceManifest = new JsonSlurper().parse(file("ambiance/src/main/resources/fabric.mod.json")) 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.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || rootProject.ouch_version != "0.0.0-alpha.11" || migration.source?.pack_version != "26.2.0-alpha.199" @@ -5052,10 +5052,10 @@ tasks.register("verifyWeatherTntAmbianceRelease") { || !weatherTnt.contains("AmbianceDailyWeather.CLEAR") || !weatherTnt.contains("CLEAR_WEATHER_TICKS = 864_000") || weatherTnt.contains("setWeatherParameters") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || !packwizIndex.contains('file = "mods/ouch-0.0.0-alpha.11.jar"')) { throw new GradleException("The alpha.200 Weather TNT and Ambiance release is incomplete") @@ -5084,7 +5084,7 @@ tasks.register("verifyQuestRequestEscrowRelease") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.200" || migration.source?.modules?.sanctuary != "0.0.0-alpha.115" @@ -5099,10 +5099,10 @@ tasks.register("verifyQuestRequestEscrowRelease") { || migration.compatibility?.sanctuary_target_network_protocol != 21 || sanctuaryManifest.custom?.sanctuary26?.data_version != 15 || sanctuaryManifest.custom?.sanctuary26?.network_protocol != 24 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"')) { throw new GradleException("The alpha.201 quest-request escrow release is incomplete") } @@ -5138,7 +5138,7 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") { "iliketomoveit/src/main/resources/fabric.mod.json")) def sanctuaryManifest = new JsonSlurper().parse(file( "sanctuary/src/main/resources/fabric.mod.json")) - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || rootProject.itsalive_version != "0.0.0-alpha.38" || rootProject.iliketomoveit_version != "0.0.0-alpha.18" @@ -5178,10 +5178,10 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") { || moveItManifest.custom?.sanctuary26?.network_protocol != 5 || sanctuaryManifest.custom?.sanctuary26?.data_version != 15 || sanctuaryManifest.custom?.sanctuary26?.network_protocol != 24 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.38.jar"') || !packwizIndex.contains('file = "mods/iliketomoveit-0.0.0-alpha.18.jar"') @@ -5298,7 +5298,7 @@ tasks.register("verifySafeVaultFeature") { def image = javax.imageio.ImageIO.read(file("anotherworld/src/main/resources/assets/anotherworld/textures/${path}")) image == null || image.width != size[0] || image.height != size[1] }.keySet() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.schema_version != 1 @@ -5490,7 +5490,7 @@ tasks.register("verifySafeVaultInterfaceAlpha203Release") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || migration.source?.pack_version != "26.2.0-alpha.202" || migration.source?.modules != [anotherworld: "0.0.0-alpha.50"] @@ -5508,9 +5508,9 @@ tasks.register("verifySafeVaultInterfaceAlpha203Release") { || migration.distribution?.jei?.modrinth_version_id != "XXTFqqwG" || migration.distribution?.jei?.prism_manifest_updated != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.50.jar"') || jeiFiles.size() != 1 @@ -5536,7 +5536,7 @@ tasks.register("verifySafeVaultFixAlpha204Release") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || migration.source?.pack_version != "26.2.0-alpha.203" || migration.source?.modules != [anotherworld: "0.0.0-alpha.51"] @@ -5562,9 +5562,9 @@ tasks.register("verifySafeVaultFixAlpha204Release") { || migration.distribution?.jei?.modrinth_version_id != "OcMayhUH" || migration.distribution?.jei?.prism_manifest_updated != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.51.jar"') || jeiFiles.size() != 1 @@ -5590,7 +5590,7 @@ tasks.register("verifySafeVaultCubeAlpha205Release") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || migration.source?.pack_version != "26.2.0-alpha.204" || migration.source?.modules != [anotherworld: "0.0.0-alpha.52"] @@ -5619,9 +5619,9 @@ tasks.register("verifySafeVaultCubeAlpha205Release") { || migration.distribution?.jei?.modrinth_version_id != "NtfJDMhk" || migration.distribution?.jei?.prism_manifest_updated != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.52.jar"') || jeiFiles.size() != 1 @@ -5648,7 +5648,7 @@ tasks.register("verifySafeVaultCtmAlpha206Release") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || migration.source?.pack_version != "26.2.0-alpha.205" || migration.source?.modules != [anotherworld: "0.0.0-alpha.53"] @@ -5671,9 +5671,9 @@ tasks.register("verifySafeVaultCtmAlpha206Release") { || migration.compatibility?.pack_release_updated != true || migration.distribution?.packwiz_index_refreshed != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.53.jar"') || jeiFiles.size() != 1 @@ -5700,7 +5700,7 @@ tasks.register("verifySafeVaultUnlimitedAlpha207Release") { def packwiz = file("pack/packwiz/pack.toml").text def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || migration.source?.pack_version != "26.2.0-alpha.206" || migration.source?.modules != [anotherworld: "0.0.0-alpha.54"] @@ -5730,9 +5730,9 @@ tasks.register("verifySafeVaultUnlimitedAlpha207Release") { || migration.compatibility?.pack_release_updated != true || migration.distribution?.packwiz_index_refreshed != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"') || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.54.jar"') || jeiFiles.size() != 1 @@ -5788,7 +5788,7 @@ tasks.register("verifyCanapliaFoundation") { "itsalive/src/main/java/fr/koka99cab/sanctuary26/itsalive/ItsAliveMod.java").text def visualApiSource = file( "ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/api/visual/AmbianceVisualEffectApi.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.itsalive_version != "0.0.0-alpha.38" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.issue != 35 @@ -6040,7 +6040,7 @@ tasks.register("verifyCanapliaAlpha209Release") { ambiance: "0.0.0-alpha.14", itsalive: "0.0.0-alpha.33", onlyfun: "0.0.0-alpha.20"] - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || rootProject.itsalive_version != "0.0.0-alpha.38" || rootProject.onlyfun_version != "0.0.0-alpha.27" @@ -6088,9 +6088,9 @@ tasks.register("verifyCanapliaAlpha209Release") { || fixMigration.compatibility?.network_protocol_changed != false || fixMigration.distribution?.pack_release_updated != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.38.jar"') || !packwizIndex.contains('file = "mods/onlyfun-0.0.0-alpha.27.jar"') @@ -6159,7 +6159,7 @@ tasks.register("verifyAlpha210Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.onlyfun_version != "0.0.0-alpha.27" || rootProject.iliketomoveit_version != "0.0.0-alpha.18" @@ -6205,10 +6205,10 @@ tasks.register("verifyAlpha210Release") { || manifests.iliketomoveit.custom?.sanctuary26?.network_protocol != 5 || manifests.itsalive.custom?.sanctuary26?.data_version != 4 || manifests.itsalive.custom?.sanctuary26?.network_protocol != 4 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || jeiFiles.size() != 1 @@ -6289,7 +6289,7 @@ tasks.register("verifyAlpha211Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || workspaceModules.any { id, version -> rootProject.property("${id}_version") != version } || migration.source?.pack_version != "26.2.0-alpha.210" || migration.source?.modules != expectedSource @@ -6317,9 +6317,9 @@ tasks.register("verifyAlpha211Release") { || migration.distribution?.prism_modrinth_index_updated != true || migration.distribution?.shared_client_server_mrpack != true || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || prism.files?.size() != 6 @@ -6327,7 +6327,7 @@ tasks.register("verifyAlpha211Release") { || jeiFiles[0].hashes?.sha1 != "e82447aff07e87a372cf817bc9c28b0d77b6f55c" || jeiFiles[0].hashes?.sha512 != "2279cb0ec4e41d9eebad80c2ecac76d19c8bc8e5aac69ba13f35b77494625c70d66edc74d59959116012bfb2f464b55806dd69fbf6387f25679b1553953e329a" || !changelog.contains("## `26.2.0-alpha.211`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.211 Abjection and gameplay-polish release is incomplete") } } @@ -6361,7 +6361,7 @@ tasks.register("verifyAlpha212Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.211" || migration.source?.modules != [sanctuary: "0.0.0-alpha.119"] @@ -6383,16 +6383,16 @@ tasks.register("verifyAlpha212Release") { || manifest.custom?.sanctuary26?.data_version != 15 || manifest.custom?.sanctuary26?.network_protocol != 24 || !minecraftMixin.contains('method = "pickBlockOrEntity"') - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 || jeiFiles.size() != 1 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"') || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.119.jar"') || !changelog.contains("## `26.2.0-alpha.212`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.212 Black Market startup-fix release is incomplete") } } @@ -6426,7 +6426,7 @@ tasks.register("verifyAlpha213Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.212" || migration.source?.modules != [ambiance: "0.0.0-alpha.15"] @@ -6450,16 +6450,16 @@ tasks.register("verifyAlpha213Release") { || manifest.custom?.sanctuary26?.network_protocol != 6 || !levelEventMixin.contains('@Mixin(LevelEventHandler.class)') || !levelEventMixin.contains('@Inject(method = "levelEvent"') - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 || jeiFiles.size() != 1 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.15.jar"') || !changelog.contains("## `26.2.0-alpha.213`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.213 Ambiance startup-fix release is incomplete") } } @@ -6494,7 +6494,7 @@ tasks.register("verifyAlpha214Release") { "ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/client/audio/WhiteDiscAudioPlayer.java").text def urlSmoke = file( "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/white_disc/WhiteDiscUrlSmoke.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.213" || migration.source?.modules != [ambiance: "0.0.0-alpha.16"] @@ -6523,16 +6523,16 @@ tasks.register("verifyAlpha214Release") { || !audioPlayer.contains('message.ambiance.white_disc.loading') || !audioPlayer.contains('message.ambiance.white_disc.failed') || !urlSmoke.contains("https://youtu.be/Ue5ZBe-GzSM?si=78LSbtBQzUYzhA2Y") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.16.jar"') || !changelog.contains("## `26.2.0-alpha.214`") || changelog.contains("## Modifications non distribuées") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.214 white-disc solo synchronization release is incomplete") } } @@ -6573,7 +6573,7 @@ tasks.register("verifyAlpha215Release") { "ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/client/audio/LavaplayerAudioStream.java").text def playbackSmoke = file( "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/client/audio/WhiteDiscPlaybackSmoke.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.214" || migration.source?.modules != [ambiance: "0.0.0-alpha.17"] @@ -6613,16 +6613,16 @@ tasks.register("verifyAlpha215Release") { || !playbackSmoke.contains("https://www.youtube.com/watch?v=Ue5ZBe-GzSM") || !playbackSmoke.contains("stream.paddedSilenceBytes() != 0L") || !playbackSmoke.contains("stream.decodedTimelineMillis() != 4_000L") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.17.jar"') || !changelog.contains("## `26.2.0-alpha.215`") || changelog.contains("## Modifications non distribuées") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.215 resilient white-disc playback release is incomplete") } } @@ -6667,7 +6667,7 @@ tasks.register("verifyAlpha216Release") { "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/client/audio/LavaplayerAudioStreamSmoke.java").text def playbackSmoke = file( "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/client/audio/WhiteDiscPlaybackSmoke.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.215" || migration.source?.modules != [ambiance: "0.0.0-alpha.18"] @@ -6711,16 +6711,16 @@ tasks.register("verifyAlpha216Release") { || !playbackSmoke.contains("stream.paddedSilenceBytes() != 0L") || !playbackSmoke.contains("stream.decodedTimelineMillis() != 4_000L") || !playbackSmoke.contains("LavaplayerAudioStream.SAMPLE_RATE * 2 * 4") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.18.jar"') || !changelog.contains("## `26.2.0-alpha.216`") || changelog.contains("## Modifications non distribuées") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.216 white-disc audio-quality release is incomplete") } } @@ -6755,7 +6755,7 @@ tasks.register("verifyAlpha217Release") { "ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/client/audio/WhiteDiscAudioPlayer.java").text def streamSmoke = file( "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/client/audio/LavaplayerAudioStreamSmoke.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.216" || migration.source?.modules != [ambiance: "0.0.0-alpha.19"] @@ -6786,16 +6786,16 @@ tasks.register("verifyAlpha217Release") { || !audioPlayer.contains("PLAYBACK_PITCH = 1.0F") || audioPlayer.count("channel.setPitch(PLAYBACK_PITCH)") != 2 || !streamSmoke.contains("WhiteDiscAudioPlayer.PLAYBACK_PITCH - 1.0F") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" || prism.files?.size() != 6 - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.19.jar"') || !changelog.contains("## `26.2.0-alpha.217`") || changelog.contains("## Modifications non distribuées") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.217 white-disc pitch release is incomplete") } } @@ -6852,7 +6852,7 @@ tasks.register("verifyAlpha218Release") { def obsoleteJars = sourceModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.redstoner_version != "0.0.0-alpha.20" || currentModules.findAll { id, version -> id != "redstoner" && id != "sanctuary" && id != "onlyfun" && id != "iliketomoveit" @@ -6893,13 +6893,13 @@ tasks.register("verifyAlpha218Release") { || !onlyFunPolicy.contains('namespace.equals("redstoner") && path.equals("storage_terminal")') || !blackMarketPolicy.contains('namespace.equals("redstoner") && path.equals("storage_terminal")') || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || !changelog.contains("## `26.2.0-alpha.218`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.218 Storage Terminal release is incomplete") } } @@ -6962,7 +6962,7 @@ tasks.register("verifyAlpha219Release") { include "**/*golden*days*.zip", "**/*golden*days*.jar" exclude "**/build/**", "**/.gradle/**", "**/.git/**" }.files - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || workspaceModules.any { id, version -> rootProject.property("${id}_version") != version } || migration.source?.pack_version != "26.2.0-alpha.218" || migration.source?.modules != sourceModules @@ -6994,15 +6994,15 @@ tasks.register("verifyAlpha219Release") { || manifests.ambiance.custom?.sanctuary26?.data_version != 2 || manifests.ambiance.custom?.sanctuary26?.network_protocol != 6 || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version || prism.files.any { it.path.toLowerCase().contains("golden-days") } - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || !forbiddenGoldenArchives.isEmpty() || !changelog.contains("## `26.2.0-alpha.219`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.219 finite Alpha/Indev release is incomplete") } } @@ -7041,7 +7041,7 @@ tasks.register("verifyAlpha220Release") { "redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/gui/StorageTerminalScreen.java").text def networking = file( "redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/network/RedStonerNetworking.java").text - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.redstoner_version != "0.0.0-alpha.20" || migration.source?.pack_version != "26.2.0-alpha.219" || migration.source?.modules != [redstoner: "0.0.0-alpha.11"] @@ -7082,13 +7082,13 @@ tasks.register("verifyAlpha220Release") { || networking.contains("storage_terminal_snapshot") || networking.contains("storage_terminal_action") || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.20.jar"') || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.11.jar"') || !changelog.contains("## `26.2.0-alpha.220`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.220 Storage Terminal menu release is incomplete") } } @@ -7136,7 +7136,7 @@ tasks.register("verifyAlpha221Release") { def playbackSmoke = file( "ambiance/src/test/java/fr/koka99cab/sanctuary26/ambiance/client/audio/WhiteDiscPlaybackSmoke.java").text def contract = migration.white_disc_native_rate - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.ambiance_version != "0.0.0-alpha.22" || migration.source?.pack_version != "26.2.0-alpha.220" || migration.source?.modules != [ambiance: "0.0.0-alpha.21"] @@ -7185,13 +7185,13 @@ tasks.register("verifyAlpha221Release") { || !playbackSmoke.contains("PCM cadence: 100%% speed") || !whiteDiscDocumentation.contains("48 000 Hz") || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version - || !packwiz.contains('version = "26.2.0-alpha.234"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.22.jar"') || packwizIndex.contains('file = "mods/ambiance-0.0.0-alpha.21.jar"') || !changelog.contains("## `26.2.0-alpha.221`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.221 native-rate white-disc release is incomplete") } } @@ -7270,7 +7270,7 @@ tasks.register("verifyAlpha222Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.redstoner_version != "0.0.0-alpha.20" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.221" @@ -7344,10 +7344,10 @@ tasks.register("verifyAlpha222Release") { || !questEditor.contains("QuestIdSuggestions.suggest") || !suggestions.contains("Normalizer.Form.NFD") || !suggestions.contains("public static final int LIMIT = 5") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.20.jar"') || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"') || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.12.jar"') @@ -7358,7 +7358,7 @@ tasks.register("verifyAlpha222Release") { || jeiFiles[0].hashes?.sha1 != "e82447aff07e87a372cf817bc9c28b0d77b6f55c" || jeiFiles[0].hashes?.sha512 != "2279cb0ec4e41d9eebad80c2ecac76d19c8bc8e5aac69ba13f35b77494625c70d66edc74d59959116012bfb2f464b55806dd69fbf6387f25679b1553953e329a" || !changelog.contains("## `26.2.0-alpha.222`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.222 terminal-search and quest-tracker release is incomplete") } } @@ -7489,7 +7489,7 @@ tasks.register("verifyAlpha223Release") { def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.201.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.source?.pack_version != "26.2.0-alpha.222" || migration.source?.modules != [sanctuary: "0.0.0-alpha.124"] @@ -7554,10 +7554,10 @@ tasks.register("verifyAlpha223Release") { || !questSync.contains("case EMERALD -> 2") || !inventorySmoke.contains("Hotbar snapshot must remain untouched") || !displaySmoke.contains("QuestTrackerDisplayMode.PANEL.next()") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"') || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.124.jar"') || !packwizJei.contains('filename = "jei-26.2-fabric-30.29.0.201.jar"') @@ -7566,7 +7566,7 @@ tasks.register("verifyAlpha223Release") { || jeiFiles[0].hashes?.sha1 != "e82447aff07e87a372cf817bc9c28b0d77b6f55c" || jeiFiles[0].hashes?.sha512 != "2279cb0ec4e41d9eebad80c2ecac76d19c8bc8e5aac69ba13f35b77494625c70d66edc74d59959116012bfb2f464b55806dd69fbf6387f25679b1553953e329a" || !changelog.contains("## `26.2.0-alpha.223`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.223 inventory-sort and quest-tracker display release is incomplete") } } @@ -7630,7 +7630,7 @@ tasks.register("verifyAlpha224Release") { }.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || workspaceModules.any { id, version -> rootProject.property("${id}_version") != version } || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.223" @@ -7673,14 +7673,14 @@ tasks.register("verifyAlpha224Release") { || !sortPayload.contains("buffer.writeBoolean(container)") || !sortPayload.contains("buffer.readBoolean()") || !networking.contains("PROTOCOL_VERSION = 24") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || !changelog.contains("## `26.2.0-alpha.224`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.224 Notch, Magic Carpet and container-sort release is incomplete") } } @@ -7775,7 +7775,7 @@ tasks.register("verifyAlpha225Release") { "iliketomoveit/src/main/resources/assets/iliketomoveit/textures/item/magic_carpet.png") def carpetTextureHash = MessageDigest.getInstance("SHA-256") .digest(carpetTexture.bytes).encodeHex().toString() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || currentWorkspaceModules.any { id, version -> rootProject.property("${id}_version") != version } || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.224" @@ -7828,14 +7828,14 @@ tasks.register("verifyAlpha225Release") { || !lootboxes.contains("SanctuaryEntityPolicy.isTemporaryCompanion") || carpetModel.textures?.layer0 != "iliketomoveit:item/magic_carpet" || carpetTextureHash != "3e4527d24a37f0632b27d2c857b047c581db07eaa41befaffbf28043a8ed86cc" - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || obsoleteJars.any { packwizIndex.contains(it) } || !changelog.contains("## `26.2.0-alpha.225`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.225 four-ticket bug-fix release is incomplete") } } @@ -7901,7 +7901,7 @@ tasks.register("verifyAlpha226Release") { def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.225" @@ -7944,14 +7944,14 @@ tasks.register("verifyAlpha226Release") { || !renderer.contains("LivingEntityRenderLayerRegistrationCallback") || !avatarMixin.contains("appearance.bannerCape()") || onlyFun.contains('"white_cape"') - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.129.jar"') || !changelog.contains("## `26.2.0-alpha.226`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.226 craftable banner cape release is incomplete") } } @@ -7992,7 +7992,7 @@ tasks.register("verifyAlpha227Release") { def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.status != "released" @@ -8032,15 +8032,15 @@ tasks.register("verifyAlpha227Release") { || anotherWorldManifest.custom?.sanctuary26?.network_protocol != 2 || sanctuaryManifest.custom?.sanctuary26?.data_version != 15 || sanctuaryManifest.custom?.sanctuary26?.network_protocol != 24 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.56.jar"') || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.130.jar"') || !changelog.contains("## `26.2.0-alpha.227`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.227 persistent Backroom release is incomplete") } } @@ -8090,7 +8090,7 @@ tasks.register("verifyAlpha228Release") { def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.redstoner_version != "0.0.0-alpha.20" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.status != "released" @@ -8137,15 +8137,15 @@ tasks.register("verifyAlpha228Release") { || !backroomLayout.contains("WORLD_MAX_Y_EXCLUSIVE = 384") || !backroomLayout.contains("LEVEL_4(-64, 27)") || !backroomLayout.contains("mazeConnected") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.13.jar"') || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.131.jar"') || !changelog.contains("## `26.2.0-alpha.228`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.228 five-level Backroom and terminal release is incomplete") } } @@ -8200,7 +8200,7 @@ tasks.register("verifyAlpha229Release") { "screen.redstoner.storage_terminal.sort.alphabetical", "screen.redstoner.storage_terminal.sort.count_ascending", "screen.redstoner.storage_terminal.sort.count_descending"] - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.redstoner_version != "0.0.0-alpha.20" || rootProject.sanctuary_version != "0.0.0-alpha.139" || migration.status != "released" @@ -8238,14 +8238,14 @@ tasks.register("verifyAlpha229Release") { || !screen.contains("sortMode = sortMode.next()") || !smoke.contains("verifySorting()") || !smoke.contains("periodic quantity refresh") - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || requiredJars.any { !packwizIndex.contains(it) } || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.15.jar"') || !changelog.contains("## `26.2.0-alpha.229`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.229 storage-terminal sorting release is incomplete") } } @@ -8285,7 +8285,7 @@ tasks.register("verifyAlpha230Release") { } def indexHash = java.security.MessageDigest.getInstance("SHA-256") .digest(packwizIndexFile.bytes).encodeHex().toString() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.redstoner_version != "0.0.0-alpha.20" || migration.schema_version != 1 @@ -8320,10 +8320,10 @@ tasks.register("verifyAlpha230Release") { || manifests.sanctuary.custom?.sanctuary26?.network_protocol != 24 || manifests.redstoner.custom?.sanctuary26?.data_version != 5 || manifests.redstoner.custom?.sanctuary26?.network_protocol != 9 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwiz.contains("hash = \"${indexHash}\"") || requiredJars.any { !packwizIndex.contains(it) } || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"\nhash = "22a37980bd7b121cbfe65e853a6c6a9f8549bbf4af9b4fdd5f22dbd04df273b0"') @@ -8331,7 +8331,7 @@ tasks.register("verifyAlpha230Release") { || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.132.jar"') || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.16.jar"') || !changelog.contains("## `26.2.0-alpha.230`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.230 Sanctuary polish release is incomplete") } } @@ -8391,7 +8391,7 @@ tasks.register("verifyAlpha231Release") { } def indexHash = java.security.MessageDigest.getInstance("SHA-256") .digest(packwizIndexFile.bytes).encodeHex().toString() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.redstoner_version != "0.0.0-alpha.20" || migration.schema_version != 1 @@ -8455,10 +8455,10 @@ tasks.register("verifyAlpha231Release") { || jeiFiles[0].hashes?.sha512 != "2279cb0ec4e41d9eebad80c2ecac76d19c8bc8e5aac69ba13f35b77494625c70d66edc74d59959116012bfb2f464b55806dd69fbf6387f25679b1553953e329a" || jeiFiles[0].fileSize != 1_860_103 || !packwizJei.contains('filename = "jei-26.2-fabric-30.29.0.201.jar"') - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwiz.contains("hash = \"${indexHash}\"") || requiredJars.any { !packwizIndex.contains(it) } || !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.139.jar"\nhash = "22a37980bd7b121cbfe65e853a6c6a9f8549bbf4af9b4fdd5f22dbd04df273b0"') @@ -8467,7 +8467,7 @@ tasks.register("verifyAlpha231Release") { || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.17.jar"') || !changelog.contains("## `26.2.0-alpha.231`") || !readme.contains("Red-Stoner **`0.0.0-alpha.20`**") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**")) { + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**")) { throw new GradleException("The alpha.231 Backroom and trophy-panel release is incomplete") } } @@ -8535,7 +8535,7 @@ tasks.register("verifyAlpha232Release") { } def indexHash = MessageDigest.getInstance("SHA-256") .digest(packwizIndexFile.bytes).encodeHex().toString() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.anotherworld_version != "0.0.0-alpha.58" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.redstoner_version != "0.0.0-alpha.20" @@ -8594,10 +8594,10 @@ tasks.register("verifyAlpha232Release") { !lang.containsKey("message.canon.camera.screenshot_saved") || !lang.containsKey("message.canon.camera.screenshot_failed") } - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwiz.contains("hash = \"${indexHash}\"") || requiredJars.any { !packwizIndex.contains(it) } || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"\nhash = "8936b0a5bf3f122afc752cba5e8d96ac92cfb1458785c3fac13d25f51cb4814c"') @@ -8608,7 +8608,7 @@ tasks.register("verifyAlpha232Release") { || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.18.jar"') || !changelog.contains("## `26.2.0-alpha.232`") || !changelog.contains("ticket #146") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**") + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**") || !readme.contains("Another World **`0.0.0-alpha.58`**")) { throw new GradleException("The alpha.232 Canon screenshot and alpha.231 follow-up release is incomplete") } @@ -8649,7 +8649,7 @@ tasks.register("verifyAlpha233Release") { } def indexHash = MessageDigest.getInstance("SHA-256") .digest(packwizIndexFile.bytes).encodeHex().toString() - if (rootProject.pack_version != "26.2.0-alpha.234" + if (rootProject.pack_version != "26.2.0-alpha.235" || rootProject.sanctuary_version != "0.0.0-alpha.139" || rootProject.redstoner_version != "0.0.0-alpha.20" || migration.schema_version != 1 @@ -8681,10 +8681,10 @@ tasks.register("verifyAlpha233Release") { || manifests.sanctuary.custom?.sanctuary26?.network_protocol != 24 || manifests.redstoner.custom?.sanctuary26?.data_version != 5 || manifests.redstoner.custom?.sanctuary26?.network_protocol != 9 - || release.pack_version != "26.2.0-alpha.234" - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" - || prism.versionId != "26.2.0-alpha.234" - || !packwiz.contains('version = "26.2.0-alpha.234"') + || release.pack_version != "26.2.0-alpha.235" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" + || prism.versionId != "26.2.0-alpha.235" + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwiz.contains("hash = \"${indexHash}\"") || requiredJars.any { !packwizIndex.contains(it) } || !packwizIndex.contains('file = "mods/anotherworld-0.0.0-alpha.58.jar"\nhash = "8936b0a5bf3f122afc752cba5e8d96ac92cfb1458785c3fac13d25f51cb4814c"') @@ -8693,34 +8693,34 @@ tasks.register("verifyAlpha233Release") { || packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.138.jar"') || packwizIndex.contains('file = "mods/redstoner-0.0.0-alpha.19.jar"') || !changelog.contains("## `26.2.0-alpha.233`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**") + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**") || !readme.contains("véritable panneau Vanilla en chêne pâle")) { throw new GradleException("The alpha.233 vanilla trophy-sign release is incomplete") } } } -tasks.register("verifyAlpha234Release") { +tasks.register("verifyAlpha235Release") { group = "verification" - description = "Checks the temporary Sanctuary 26.2.0-alpha.234 ZEVENT weekend release." - inputs.file(file("pack/migrations/26.2.0-alpha.233-zevent-weekend-to-alpha.234.json")) + description = "Checks the Sanctuary 26.2.0-alpha.235 native Twitch playback release." + inputs.file(file("pack/migrations/26.2.0-alpha.234-twitch-native-playback-to-alpha.235.json")) inputs.file(file("pack/release.json")) inputs.file(file("pack/prism/modrinth.index.json")) inputs.file(file("pack/packwiz/pack.toml")) inputs.file(file("pack/packwiz/index.toml")) - inputs.file(file("pack/packwiz/mods/mcef-modern.pw.toml")) + inputs.file(file("pack/packwiz/mods/dreamdisplays.pw.toml")) inputs.file(file("CHANGELOG.md")) inputs.file(file("README.md")) inputs.file(file("zevent/src/main/resources/fabric.mod.json")) doLast { def migration = new JsonSlurper().parse(file( - "pack/migrations/26.2.0-alpha.233-zevent-weekend-to-alpha.234.json")) + "pack/migrations/26.2.0-alpha.234-twitch-native-playback-to-alpha.235.json")) def release = new JsonSlurper().parse(file("pack/release.json")) def prism = new JsonSlurper().parse(file("pack/prism/modrinth.index.json")) def packwiz = file("pack/packwiz/pack.toml").text def packwizIndexFile = file("pack/packwiz/index.toml") def packwizIndex = packwizIndexFile.text - def mcefMetafile = file("pack/packwiz/mods/mcef-modern.pw.toml").text + def dreamMetafile = file("pack/packwiz/mods/dreamdisplays.pw.toml").text def changelog = file("CHANGELOG.md").text def readme = file("README.md").text def manifest = new JsonSlurper().parse(file("zevent/src/main/resources/fabric.mod.json")) @@ -8733,60 +8733,70 @@ tasks.register("verifyAlpha234Release") { def zeventHash = zeventJar.isFile() ? MessageDigest.getInstance("SHA-256").digest(zeventJar.bytes).encodeHex().toString() : "missing" - def mcefFiles = prism.files.findAll { - it.path == "mods/mcef-modern-0.3.3+mc26.2.jcef146.0.10.jar" + def dreamFiles = prism.files.findAll { + it.path == "mods/dreamdisplays-fabric-26.2-1.9.6.jar" } - if (rootProject.pack_version != "26.2.0-alpha.234" - || rootProject.zevent_version != "0.0.0-alpha.2" + if (rootProject.pack_version != "26.2.0-alpha.235" + || rootProject.zevent_version != "0.0.0-alpha.3" || migration.schema_version != 1 || migration.status != "released" - || migration.released_in != "26.2.0-alpha.234" + || migration.released_in != "26.2.0-alpha.235" || migration.temporary_until != "2026-09-07" - || migration.pack?.source_version != "26.2.0-alpha.233" - || migration.pack?.target_version != "26.2.0-alpha.234" - || migration.modules?.zevent?.source_module_version != null - || migration.modules?.zevent?.target_module_version != "0.0.0-alpha.2" + || migration.pack?.source_version != "26.2.0-alpha.234" + || migration.pack?.target_version != "26.2.0-alpha.235" + || migration.modules?.zevent?.source_module_version != "0.0.0-alpha.2" + || migration.modules?.zevent?.target_module_version != "0.0.0-alpha.3" || migration.modules?.zevent?.data_version != 1 || migration.modules?.zevent?.network_protocol != 1 - || migration.dependencies?.mcef_modern?.version != "0.3.3+mc26.2.jcef146.0.10" - || migration.dependencies?.mcef_modern?.modrinth_project_id != "YJFfu5pH" - || migration.dependencies?.mcef_modern?.modrinth_version_id != "FOXbUPNd" - || migration.dependencies?.mcef_modern?.environment != "client_only" + || migration.playback?.mcef_removed != true + || migration.playback?.native_hls_decoder != true + || migration.playback?.h264_video != true + || migration.playback?.aac_audio != true + || migration.playback?.maximum_quality_height != 720 + || migration.playback?.automatic_retry_seconds != 30 + || migration.playback?.offline_feedback != true + || migration.dependencies?.dream_displays?.version != "1.9.6" + || migration.dependencies?.dream_displays?.modrinth_project_id != "4IIKQyBu" + || migration.dependencies?.dream_displays?.modrinth_version_id != "GxyW2ksW" + || migration.dependencies?.dream_displays?.environment != "client_and_server" || migration.compatibility?.existing_saves_supported != true || migration.compatibility?.save_reset_required != false || migration.distribution?.packwiz_index_refreshed != true || migration.distribution?.prism_modrinth_index_updated != true - || migration.distribution?.mcef_client_only != true + || migration.distribution?.mcef_removed != true + || migration.distribution?.dream_displays_required != true || manifest.id != "zevent" || manifest.environment != "*" || manifest.custom?.sanctuary26?.data_version != 1 || manifest.custom?.sanctuary26?.network_protocol != 1 || manifest.custom?.sanctuary26?.distribution != "temporary-weekend-pack-module" + || manifest.depends?.dreamdisplays != ">=1.9.6" || manifest.depends?.containsKey("mcef-modern") - || manifest.suggests?."mcef-modern" != ">=0.3.3" + || manifest.suggests?.containsKey("mcef-modern") || release.pack_version != rootProject.pack_version - || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.234.mrpack" + || release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.235.mrpack" || prism.versionId != rootProject.pack_version || prism.files?.size() != 6 - || mcefFiles.size() != 1 - || mcefFiles[0].hashes?.sha1 != "a90404e9072f918b7029bb03f4a04da240b32986" - || mcefFiles[0].hashes?.sha512 != "1249687814d906fef8a84d42e3bec0bab7c0e1db8f7cdad3fc03af19668107777e1683e373d29e5ffc4479558d11513d2ae4f40f8f59fd74ee261ff4e69574d7" - || mcefFiles[0].env != [client: "required", server: "unsupported"] - || mcefFiles[0].fileSize != 248_099 - || !mcefMetafile.contains('filename = "mcef-modern-0.3.3+mc26.2.jcef146.0.10.jar"') - || !mcefMetafile.contains('side = "client"') - || !mcefMetafile.contains('pin = true') - || !mcefMetafile.contains('mod-id = "YJFfu5pH"') - || !mcefMetafile.contains('version = "FOXbUPNd"') - || !packwiz.contains('version = "26.2.0-alpha.234"') + || dreamFiles.size() != 1 + || dreamFiles[0].hashes?.sha1 != "2f040162d833ced2cd62d9cab459dbb2ee1a7e35" + || dreamFiles[0].hashes?.sha512 != "c57f7d85e85ac0a65811863dca4b433bd94d4f3c7a6a3e6d08998f5be7d54fd06242afee2f6307b7698535640be1374a425f9452fe68e43710a2a93ff9907e53" + || dreamFiles[0].env != [client: "required", server: "required"] + || dreamFiles[0].fileSize != 26_232_108 + || !dreamMetafile.contains('filename = "dreamdisplays-fabric-26.2-1.9.6.jar"') + || !dreamMetafile.contains('side = "both"') + || !dreamMetafile.contains('pin = true') + || !dreamMetafile.contains('mod-id = "4IIKQyBu"') + || !dreamMetafile.contains('version = "GxyW2ksW"') + || !packwiz.contains('version = "26.2.0-alpha.235"') || !packwiz.contains("hash = \"${indexHash}\"") || requiredJars.any { !packwizIndex.contains(it) } - || !packwizIndex.contains('file = "mods/mcef-modern.pw.toml"') - || !packwizIndex.contains("file = \"mods/zevent-0.0.0-alpha.2.jar\"\nhash = \"${zeventHash}\"") - || !changelog.contains("## `26.2.0-alpha.234`") - || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.234`**") - || !readme.contains("MCEF Modern **`0.3.3+mc26.2.jcef146.0.10`**")) { - throw new GradleException("The alpha.234 temporary ZEVENT weekend release is incomplete") + || packwizIndex.contains('file = "mods/mcef-modern.pw.toml"') + || !packwizIndex.contains('file = "mods/dreamdisplays.pw.toml"') + || !packwizIndex.contains("file = \"mods/zevent-0.0.0-alpha.3.jar\"\nhash = \"${zeventHash}\"") + || !changelog.contains("## `26.2.0-alpha.235`") + || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.235`**") + || !readme.contains("Dream Displays **`1.9.6`**")) { + throw new GradleException("The alpha.235 native Twitch playback release is incomplete") } } } @@ -8815,7 +8825,7 @@ tasks.named("verifyWorkspace") { dependsOn tasks.named("verifyAlpha231Release") dependsOn tasks.named("verifyAlpha232Release") dependsOn tasks.named("verifyAlpha233Release") - dependsOn tasks.named("verifyAlpha234Release") + dependsOn tasks.named("verifyAlpha235Release") } tasks.named("check") { diff --git a/gradle.properties b/gradle.properties index 51e45e7..e7c2d63 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,7 +30,7 @@ onlyfun_version=0.0.0-alpha.27 onlyfun_lifecycle=active sanctuary_version=0.0.0-alpha.139 sanctuary_lifecycle=active -zevent_version=0.0.0-alpha.2 +zevent_version=0.0.0-alpha.3 zevent_lifecycle=active -pack_version=26.2.0-alpha.234 +pack_version=26.2.0-alpha.235 maven_group=fr.koka99cab.sanctuary26 diff --git a/itsalive/build.gradle b/itsalive/build.gradle index 5ffaf89..24bd3f7 100644 --- a/itsalive/build.gradle +++ b/itsalive/build.gradle @@ -1261,6 +1261,7 @@ tasks.named("processResources") { tasks.named("sourcesJar") { dependsOn tasks.named("generateAgricultureResources") + dependsOn tasks.named("generateCanapliaResources") } tasks.register("verifyCulinaryReliability") { diff --git a/pack/migrations/26.2.0-alpha.234-twitch-native-playback-to-alpha.235.json b/pack/migrations/26.2.0-alpha.234-twitch-native-playback-to-alpha.235.json new file mode 100644 index 0000000..253ae9c --- /dev/null +++ b/pack/migrations/26.2.0-alpha.234-twitch-native-playback-to-alpha.235.json @@ -0,0 +1,51 @@ +{ + "schema_version": 1, + "status": "released", + "released_in": "26.2.0-alpha.235", + "temporary_until": "2026-09-07", + "pack": { + "source_version": "26.2.0-alpha.234", + "target_version": "26.2.0-alpha.235" + }, + "modules": { + "zevent": { + "source_module_version": "0.0.0-alpha.2", + "target_module_version": "0.0.0-alpha.3", + "data_version": 1, + "network_protocol": 1, + "client_and_server_required": true + } + }, + "playback": { + "mcef_removed": true, + "native_hls_decoder": true, + "h264_video": true, + "aac_audio": true, + "maximum_quality_height": 720, + "automatic_retry_seconds": 30, + "offline_feedback": true + }, + "dependencies": { + "dream_displays": { + "version": "1.9.6", + "modrinth_project_id": "4IIKQyBu", + "modrinth_version_id": "GxyW2ksW", + "environment": "client_and_server" + } + }, + "compatibility": { + "existing_saves_supported": true, + "new_world_required": false, + "save_reset_required": false, + "data_version_changed": false, + "network_protocol_changed": false, + "zevent_client_server_update_required": true + }, + "distribution": { + "packwiz_index_refreshed": true, + "prism_modrinth_index_updated": true, + "shared_client_server_mrpack": true, + "mcef_removed": true, + "dream_displays_required": true + } +} diff --git a/pack/packwiz/index.toml b/pack/packwiz/index.toml index 9a4633d..87f0935 100644 --- a/pack/packwiz/index.toml +++ b/pack/packwiz/index.toml @@ -20,6 +20,11 @@ hash = "960322cd387c47588f6fd76202c0abf2c9993cf0effa82e19f8bb31d86ab07a4" file = "mods/anotherworld-0.0.0-alpha.58.jar" hash = "8936b0a5bf3f122afc752cba5e8d96ac92cfb1458785c3fac13d25f51cb4814c" +[[files]] +file = "mods/dreamdisplays.pw.toml" +hash = "b444a117085376d96a0964131ce0e2f2b86f7996314c27288f45f0b8117a36f5" +metafile = true + [[files]] file = "mods/events-0.0.0-alpha.0.jar" hash = "1fe3fc2f6ca371f8dde44e0bb535b1e70df0e9c4de3f56002f9f3ec6d5826745" @@ -51,11 +56,6 @@ metafile = true file = "mods/masterkey-0.0.0-alpha.9.jar" hash = "95265c4aa4ebb89d5e89e3245917f47a4044db192f88995cfee2bdf63f348b79" -[[files]] -file = "mods/mcef-modern.pw.toml" -hash = "8a2d7d5c6aae5e1c954bfb18c59b201a08b33b948dd95ed6b2a0e4004b69b49b" -metafile = true - [[files]] file = "mods/onlyfun-0.0.0-alpha.27.jar" hash = "dcd5003390c132f3421c12550f851846548b4d1cc541d3ada0deb35c65bb3f54" @@ -83,5 +83,5 @@ hash = "f06c0b9150da9877b99cb265d037c067e509340d9bf347e02cef2043c110e963" metafile = true [[files]] -file = "mods/zevent-0.0.0-alpha.2.jar" -hash = "5123ad255381a783dafdb7b8ba66df56196d30e85f1d507d9c2758bd7ed4f0c5" +file = "mods/zevent-0.0.0-alpha.3.jar" +hash = "98f1af94549e95fabf99141130c2a56b650165bb405cae57af488c2811b907be" diff --git a/pack/packwiz/mods/dreamdisplays.pw.toml b/pack/packwiz/mods/dreamdisplays.pw.toml new file mode 100644 index 0000000..9b5f837 --- /dev/null +++ b/pack/packwiz/mods/dreamdisplays.pw.toml @@ -0,0 +1,14 @@ +name = "Dream Displays" +filename = "dreamdisplays-fabric-26.2-1.9.6.jar" +side = "both" +pin = true + +[download] +url = "https://cdn.modrinth.com/data/4IIKQyBu/versions/GxyW2ksW/dreamdisplays-fabric-26.2-1.9.6.jar" +hash-format = "sha512" +hash = "c57f7d85e85ac0a65811863dca4b433bd94d4f3c7a6a3e6d08998f5be7d54fd06242afee2f6307b7698535640be1374a425f9452fe68e43710a2a93ff9907e53" + +[update] +[update.modrinth] +mod-id = "4IIKQyBu" +version = "GxyW2ksW" diff --git a/pack/packwiz/mods/mcef-modern.pw.toml b/pack/packwiz/mods/mcef-modern.pw.toml deleted file mode 100644 index 908cff1..0000000 --- a/pack/packwiz/mods/mcef-modern.pw.toml +++ /dev/null @@ -1,14 +0,0 @@ -name = "MCEF Modern" -filename = "mcef-modern-0.3.3+mc26.2.jcef146.0.10.jar" -side = "client" -pin = true - -[download] -url = "https://cdn.modrinth.com/data/YJFfu5pH/versions/FOXbUPNd/mcef-modern-0.3.3%2Bmc26.2.jcef146.0.10.jar" -hash-format = "sha512" -hash = "1249687814d906fef8a84d42e3bec0bab7c0e1db8f7cdad3fc03af19668107777e1683e373d29e5ffc4479558d11513d2ae4f40f8f59fd74ee261ff4e69574d7" - -[update] -[update.modrinth] -mod-id = "YJFfu5pH" -version = "FOXbUPNd" diff --git a/pack/packwiz/pack.toml b/pack/packwiz/pack.toml index 63affd9..8bee2c3 100644 --- a/pack/packwiz/pack.toml +++ b/pack/packwiz/pack.toml @@ -1,12 +1,12 @@ name = "Sanctuary 26.2" author = "KOKA99CAB" -version = "26.2.0-alpha.234" +version = "26.2.0-alpha.235" pack-format = "packwiz:1.1.0" [index] file = "index.toml" hash-format = "sha256" -hash = "07587749b1bd7fc7be7bfbab7ae251fccb2936eba203af22dce13e08fbaffc2a" +hash = "4b92999f44991f7d4cbcbf221949ec2fd50602156da16d0655a6e89a554dfda2" [versions] fabric = "0.19.3" diff --git a/pack/prism/modrinth.index.json b/pack/prism/modrinth.index.json index bd03409..204f06b 100644 --- a/pack/prism/modrinth.index.json +++ b/pack/prism/modrinth.index.json @@ -3,7 +3,7 @@ "game": "minecraft", "name": "Sanctuary 26.2", "summary": "Sanctuary 26.2 — progression, exploration, worldgen and multiplayer systems by KOKA99CAB.", - "versionId": "26.2.0-alpha.234", + "versionId": "26.2.0-alpha.235", "files": [ { "path": "mods/fabric-api-0.159.0+26.2.jar", @@ -81,19 +81,19 @@ "fileSize": 2820763 }, { - "path": "mods/mcef-modern-0.3.3+mc26.2.jcef146.0.10.jar", + "path": "mods/dreamdisplays-fabric-26.2-1.9.6.jar", "hashes": { - "sha1": "a90404e9072f918b7029bb03f4a04da240b32986", - "sha512": "1249687814d906fef8a84d42e3bec0bab7c0e1db8f7cdad3fc03af19668107777e1683e373d29e5ffc4479558d11513d2ae4f40f8f59fd74ee261ff4e69574d7" + "sha1": "2f040162d833ced2cd62d9cab459dbb2ee1a7e35", + "sha512": "c57f7d85e85ac0a65811863dca4b433bd94d4f3c7a6a3e6d08998f5be7d54fd06242afee2f6307b7698535640be1374a425f9452fe68e43710a2a93ff9907e53" }, "env": { "client": "required", - "server": "unsupported" + "server": "required" }, "downloads": [ - "https://cdn.modrinth.com/data/YJFfu5pH/versions/FOXbUPNd/mcef-modern-0.3.3%2Bmc26.2.jcef146.0.10.jar" + "https://cdn.modrinth.com/data/4IIKQyBu/versions/GxyW2ksW/dreamdisplays-fabric-26.2-1.9.6.jar" ], - "fileSize": 248099 + "fileSize": 26232108 } ], "dependencies": { diff --git a/pack/release.json b/pack/release.json index 29933f1..256d525 100644 --- a/pack/release.json +++ b/pack/release.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "pack_version": "26.2.0-alpha.234", + "pack_version": "26.2.0-alpha.235", "release_channel": "alpha", "minecraft_version": "26.2", "fabric_loader_version": "0.19.3", @@ -9,7 +9,7 @@ "project_id": "FgOqyAXd", "project_slug": "sanctuary-koka99", "project_url": "https://modrinth.com/modpack/sanctuary-koka99", - "primary_file": "sanctuary-26.2.0-alpha.234.mrpack", + "primary_file": "sanctuary-26.2.0-alpha.235.mrpack", "shared_client_server_pack": true, "update_owner": "packwiz-installer", "check_on_launch": true, diff --git a/zevent/README.md b/zevent/README.md index 92d6076..5ff20f6 100644 --- a/zevent/README.md +++ b/zevent/README.md @@ -8,12 +8,12 @@ Mod Fabric événementiel distribué séparément du pack Sanctuary. Il ajoute u 2. Faire un clic droit sur n'importe laquelle de ses 45 cases. 3. Saisir un nom de chaîne (`zeventfr`) ou coller une URL Twitch, puis valider. -La chaîne est enregistrée par le serveur et synchronisée aux joueurs. Le client rend le lecteur Twitch officiel dans la surface. Son volume utilise la catégorie **Disques** de Minecraft et diminue jusqu'au silence à 64 blocs. Seul l'écran le plus proche est audible et deux flux visibles au maximum sont décodés par client. +La chaîne est enregistrée par le serveur et synchronisée aux joueurs. Le client résout le flux Twitch puis le décode nativement dans la surface. Son volume utilise la catégorie **Disques** de Minecraft et diminue jusqu'au silence à 64 blocs. Seul l'écran le plus proche est audible et deux flux visibles au maximum sont décodés par client. ## Dépendance et limites -Le client exige [MCEF Modern](https://modrinth.com/mod/mcef-modern) `0.3.3+mc26.2.jcef146.0.10`. MCEF télécharge son runtime Chromium natif lors de la première utilisation ; une connexion Internet est donc nécessaire. Le lecteur utilise le backend OpenGL pris en charge par cette version de MCEF. +Le client exige [Dream Displays](https://modrinth.com/mod/dream-displays) `1.9.6` pour la résolution HLS Twitch, le décodage H.264/AAC et l'envoi des images vers le GPU. Une connexion Internet est nécessaire. Cette version est épinglée : l'adaptateur ZEVENT utilise `DisplayScreen` pour posséder un lecteur local sans l'enregistrer comme écran Dream Displays, puis réutilise uniquement son `RenderType` dans le renderer du multibloc ZEVENT. Toute mise à jour de Dream Displays doit donc être validée avec `:zevent:check` et un essai de flux Twitch réel. -Le serveur ne reçoit jamais d'URL arbitraire : les entrées sont ramenées à un identifiant Twitch de 1 à 25 caractères (`a-z`, `0-9`, `_`). La page locale est liée uniquement à l'interface loopback et n'expose que le lecteur officiel `player.twitch.tv`. +Le serveur ne reçoit jamais d'URL arbitraire : les entrées sont ramenées à un identifiant Twitch de 1 à 25 caractères (`a-z`, `0-9`, `_`). Le client ne construit ensuite que l'URL canonique `https://www.twitch.tv/` remise au résolveur Twitch de Dream Displays. -Documentation du lecteur : [Twitch Embedded Video & Clips](https://dev.twitch.tv/docs/embed/video-and-clips/). +Sources du lecteur : [Dream Displays](https://github.com/arnodoelinger/dreamdisplays). diff --git a/zevent/build.gradle b/zevent/build.gradle index 389f73b..2d22027 100644 --- a/zevent/build.gradle +++ b/zevent/build.gradle @@ -3,8 +3,7 @@ repositories { } dependencies { - implementation "maven.modrinth:mcef-modern:FOXbUPNd" - compileOnly "me.friwi:jcef-api:jcef-d3de827+cef-146.0.10+g8219561+chromium-146.0.7680.179" + implementation "maven.modrinth:dreamdisplays:GxyW2ksW" testImplementation "org.junit.jupiter:junit-jupiter:5.11.4" testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4" } diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayout.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayout.java index 2d2db38..9282f2b 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayout.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayout.java @@ -29,6 +29,16 @@ public final class ZeventScreenLayout { ); } + /** Returns the minimum world-space corner used by rectangular media renderers. */ + public static BlockPos anchor(BlockPos controller, Direction facing) { + BlockPos first = partPos(controller, facing, 0, 0); + BlockPos last = partPos(controller, facing, WIDTH - 1, HEIGHT - 1); + return new BlockPos( + Math.min(first.getX(), last.getX()), + Math.min(first.getY(), last.getY()), + Math.min(first.getZ(), last.getZ())); + } + public static BlockPos controllerPos(BlockPos part, BlockState state) { Direction facing = state.getValue(ZeventScreenBlock.FACING); int column = state.getValue(ZeventScreenBlock.COLUMN); diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/ZeventClient.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/ZeventClient.java index c7f5da6..19e5044 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/ZeventClient.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/ZeventClient.java @@ -24,6 +24,6 @@ public final class ZeventClient implements ClientModInitializer { ClientTickEvents.END_CLIENT_TICK.register(TwitchBrowserManager::tick); ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> TwitchBrowserManager.clear(client)); ClientLifecycleEvents.CLIENT_STOPPING.register(TwitchBrowserManager::shutdown); - ZeventMod.LOGGER.info("[{}] Twitch browser renderer registered.", ZeventMod.DISPLAY_NAME); + ZeventMod.LOGGER.info("[{}] Native Twitch renderer registered.", ZeventMod.DISPLAY_NAME); } } diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/ZeventScreenBlockEntityRenderer.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/ZeventScreenBlockEntityRenderer.java index 91beb4b..aa4075e 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/ZeventScreenBlockEntityRenderer.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/ZeventScreenBlockEntityRenderer.java @@ -11,14 +11,11 @@ import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.feature.ModelFeatureRenderer; -import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.client.renderer.state.level.CameraRenderState; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.core.Direction; -import net.minecraft.util.LightCoordsUtil; import net.minecraft.world.phys.Vec3; -/** Projects one browser texture over the central block entity's complete 9x5 surface. */ +/** Projects one decoded video texture over the central block entity's complete 9x5 surface. */ public final class ZeventScreenBlockEntityRenderer implements BlockEntityRenderer { private static final int VIEW_DISTANCE = 128; @@ -39,18 +36,19 @@ public final class ZeventScreenBlockEntityRenderer public void extractRenderState(ZeventScreenBlockEntity screen, ZeventScreenRenderState state, float tickProgress, Vec3 cameraPos, ModelFeatureRenderer.CrumblingOverlay crumblingOverlay) { BlockEntityRenderer.super.extractRenderState(screen, state, tickProgress, cameraPos, crumblingOverlay); - state.texture = null; + state.renderType = null; if (!ZeventScreenLayout.isController(screen.getBlockState()) || screen.getLevel() == null) return; state.facing = screen.getBlockState().getValue(ZeventScreenBlock.FACING); - state.texture = TwitchBrowserManager.markVisible(screen.getLevel(), screen.getBlockPos(), screen.channel()); + state.renderType = TwitchBrowserManager.markVisible( + screen.getLevel(), screen.getBlockPos(), state.facing, screen.channel()); } @Override public void submit(ZeventScreenRenderState state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState) { - if (state.texture == null) return; + if (state.renderType == null) return; submitNodeCollector.submitCustomGeometry(poseStack, - RenderTypes.entityTranslucentEmissive(state.texture), + state.renderType, (pose, consumer) -> drawScreen(pose, consumer, state.facing)); } @@ -74,22 +72,19 @@ public final class ZeventScreenBlockEntityRenderer Direction right = ZeventScreenLayout.right(facing); float centerX = 0.5F - facing.getStepX() * CENTER_TO_FRONT; float centerZ = 0.5F - facing.getStepZ() * CENTER_TO_FRONT; - vertex(consumer, pose, centerX, centerZ, right, facing, -HALF_WIDTH, -HALF_HEIGHT, 0.0F, 1.0F); - vertex(consumer, pose, centerX, centerZ, right, facing, HALF_WIDTH, -HALF_HEIGHT, 1.0F, 1.0F); - vertex(consumer, pose, centerX, centerZ, right, facing, HALF_WIDTH, HALF_HEIGHT, 1.0F, 0.0F); - vertex(consumer, pose, centerX, centerZ, right, facing, -HALF_WIDTH, HALF_HEIGHT, 0.0F, 0.0F); + vertex(consumer, pose, centerX, centerZ, right, -HALF_WIDTH, -HALF_HEIGHT, 0.0F, 1.0F); + vertex(consumer, pose, centerX, centerZ, right, HALF_WIDTH, -HALF_HEIGHT, 1.0F, 1.0F); + vertex(consumer, pose, centerX, centerZ, right, HALF_WIDTH, HALF_HEIGHT, 1.0F, 0.0F); + vertex(consumer, pose, centerX, centerZ, right, -HALF_WIDTH, HALF_HEIGHT, 0.0F, 0.0F); } private static void vertex(VertexConsumer consumer, PoseStack.Pose pose, float centerX, float centerZ, - Direction right, Direction normal, float horizontal, float vertical, float u, float v) { + Direction right, float horizontal, float vertical, float u, float v) { consumer.addVertex(pose, centerX + right.getStepX() * horizontal, 0.5F + vertical, centerZ + right.getStepZ() * horizontal) - .setColor(0xFFFFFFFF) .setUv(u, v) - .setOverlay(OverlayTexture.NO_OVERLAY) - .setLight(LightCoordsUtil.FULL_BRIGHT) - .setNormal(pose, normal.getStepX(), 0.0F, normal.getStepZ()); + .setColor(0xFFFFFFFF); } } diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/state/ZeventScreenRenderState.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/state/ZeventScreenRenderState.java index 24d26d8..6a679cb 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/state/ZeventScreenRenderState.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/render/state/ZeventScreenRenderState.java @@ -1,10 +1,10 @@ package fr.koka99cab.sanctuary26.zevent.client.render.state; import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; public final class ZeventScreenRenderState extends BlockEntityRenderState { public Direction facing = Direction.NORTH; - public Identifier texture; + public RenderType renderType; } diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/BrowserTexture.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/BrowserTexture.java deleted file mode 100644 index f65fa5f..0000000 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/BrowserTexture.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.koka99cab.sanctuary26.zevent.client.twitch; - -import com.mojang.blaze3d.textures.GpuTexture; -import com.mojang.blaze3d.textures.GpuTextureView; -import net.dimaskama.mcef.api.MCEFBrowser; -import net.minecraft.client.renderer.texture.AbstractTexture; - -/** Texture-manager bridge; MCEF remains the sole owner of the GPU allocation. */ -final class BrowserTexture extends AbstractTexture { - private final MCEFBrowser browser; - - BrowserTexture(MCEFBrowser browser) { - this.browser = browser; - } - - @Override - public GpuTexture getTexture() { - GpuTexture current = browser.getTexture(); - if (current == null) throw new IllegalStateException("MCEF browser texture is not ready"); - return current; - } - - @Override - public GpuTextureView getTextureView() { - GpuTextureView current = browser.getTextureView(); - if (current == null) throw new IllegalStateException("MCEF browser texture view is not ready"); - return current; - } - - @Override - public void close() { - // The browser closes its changing texture and view; the texture manager only drops this bridge. - } -} diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchBrowserManager.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchBrowserManager.java index ba01911..e3fc565 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchBrowserManager.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchBrowserManager.java @@ -1,56 +1,72 @@ package fr.koka99cab.sanctuary26.zevent.client.twitch; +import com.dreamdisplays.api.display.model.property.DisplayFacing; +import com.dreamdisplays.api.display.model.property.DisplayRotation; +import com.dreamdisplays.api.media.audio.service.AudioAcousticsService; +import com.dreamdisplays.api.media.audio.service.keys.AudioAcousticsServices; +import com.dreamdisplays.api.playback.model.PlaybackMode; +import com.dreamdisplays.platform.client.core.DreamServices; +import com.dreamdisplays.platform.client.displays.DisplayScreen; import fr.koka99cab.sanctuary26.zevent.ZeventMod; import fr.koka99cab.sanctuary26.zevent.block.ZeventScreenLayout; import fr.koka99cab.sanctuary26.zevent.block.entity.ZeventScreenBlockEntity; import fr.koka99cab.sanctuary26.zevent.twitch.TwitchChannel; -import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Comparator; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; -import net.dimaskama.mcef.api.MCEFApi; -import net.dimaskama.mcef.api.MCEFBrowser; +import java.util.UUID; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -/** Owns a small, distance-bounded set of official Twitch browser players. */ +/** Owns a small, distance-bounded set of native Twitch players supplied by Dream Displays. */ public final class TwitchBrowserManager { - private static final int BROWSER_WIDTH = 900; - private static final int BROWSER_HEIGHT = 500; - private static final int MAXIMUM_BROWSERS = 2; + private static final int MAXIMUM_PLAYERS = 2; private static final int STALE_TICKS = 40; private static final int AUDIBLE_FRESH_TICKS = 10; + private static final int RETRY_TICKS = 20 * 30; private static final double AUDIO_DISTANCE = 64.0D; private static final double AUDIO_DISTANCE_SQR = AUDIO_DISTANCE * AUDIO_DISTANCE; private static final double FULL_VOLUME_DISTANCE = 4.0D; - private static final TwitchPlayerPageServer PAGE_SERVER = new TwitchPlayerPageServer(); private static final Map SESSIONS = new LinkedHashMap<>(); private static boolean initializationNoticeShown; private TwitchBrowserManager() { } - public static Identifier markVisible(Level level, BlockPos pos, String requestedChannel) { + public static RenderType markVisible(Level level, BlockPos pos, Direction facing, String requestedChannel) { Minecraft client = Minecraft.getInstance(); if (client.level != level || client.player == null) return null; String channel = TwitchChannel.normalize(requestedChannel).orElse(TwitchChannel.DEFAULT); ScreenKey key = new ScreenKey(level.dimension(), pos.immutable()); Session session = SESSIONS.get(key); + if (session != null && session.facing != facing) { + remove(session); + session = null; + } if (session == null) { if (!admit(client, pos)) return null; - session = new Session(key, channel, textureId(key)); + session = start(client, key, facing, channel); SESSIONS.put(key, session); } session.lastSeenTick = level.getGameTime(); if (!session.channel.equals(channel)) session.changeChannel(channel); - if (session.browser == null && !session.starting && !session.failed) start(client, session); - return session.browser != null && session.browser.getTextureView() != null ? session.textureId : null; + if (session.player == null) return null; + try { + session.player.fitTexture(); + return session.player.isVideoStarted() ? session.player.getRenderType() : null; + } catch (RuntimeException | LinkageError exception) { + ZeventMod.LOGGER.warn("Unable to upload a ZEVENT Twitch frame", exception); + return null; + } } public static void tick(Minecraft client) { @@ -65,68 +81,100 @@ public final class TwitchBrowserManager { boolean missing = !client.level.hasChunkAt(session.key.pos) || !(client.level.getBlockEntity(session.key.pos) instanceof ZeventScreenBlockEntity screen) || !ZeventScreenLayout.isController(screen.getBlockState()); - if (wrongLevel || stale || missing) remove(client, session); + if (wrongLevel || stale || missing) { + remove(session); + continue; + } + if (session.player != null) session.player.tick(session.key.pos); + if (session.player != null) { + if (session.player.isVideoStarted()) session.errorReported = false; + if (session.player.getMediaError() != null) { + if (!session.errorReported) { + session.errorReported = true; + client.player.sendOverlayMessage(Component.translatable( + "message.zevent.player.unavailable", session.channel)); + ZeventMod.LOGGER.warn("Twitch channel {} could not be played: {}", + session.channel, session.player.getMediaError().getMessage()); + } + if (now - session.lastRetryTick >= RETRY_TICKS) { + session.lastRetryTick = now; + session.player.retryVideo(); + } + } + } } - if (now % 5L == 0L) updateVolumes(client, now); + updateVolumes(client, now); } public static void clear(Minecraft client) { - for (Session session : SESSIONS.values().toArray(Session[]::new)) remove(client, session); + for (Session session : SESSIONS.values().toArray(Session[]::new)) remove(session); SESSIONS.clear(); initializationNoticeShown = false; } public static void shutdown(Minecraft client) { clear(client); - PAGE_SERVER.stop(); } private static boolean admit(Minecraft client, BlockPos requested) { - if (SESSIONS.size() < MAXIMUM_BROWSERS) return true; + if (SESSIONS.size() < MAXIMUM_PLAYERS) return true; Session farthest = SESSIONS.values().stream().max(Comparator.comparingDouble( session -> distanceSqr(client, session.key.pos))).orElse(null); if (farthest == null || distanceSqr(client, requested) >= distanceSqr(client, farthest.key.pos)) return false; - remove(client, farthest); + remove(farthest); return true; } - private static void start(Minecraft client, Session session) { - session.starting = true; + private static Session start(Minecraft client, ScreenKey key, Direction facing, String channel) { + Session session = new Session(key, facing, channel); if (!initializationNoticeShown && client.player != null) { initializationNoticeShown = true; client.player.sendOverlayMessage(Component.translatable("message.zevent.player.initializing")); } - MCEFApi.getInstanceFuture().whenComplete((api, error) -> client.execute(() -> { - if (SESSIONS.get(session.key) != session) return; - session.starting = false; - if (error != null) { - session.failed = true; - ZeventMod.LOGGER.error("Unable to initialize MCEF for the ZEVENT screen", error); - return; + DisplayScreen player = null; + try { + BlockPos anchor = ZeventScreenLayout.anchor(key.pos, facing); + UUID displayId = UUID.nameUUIDFromBytes(("zevent:" + key.dimension.identifier() + ":" + key.pos.asLong()) + .getBytes(StandardCharsets.UTF_8)); + player = new DisplayScreen( + displayId, + client.player.getUUID(), + anchor.getX(), anchor.getY(), anchor.getZ(), + DisplayFacing.valueOf(facing.getName().toUpperCase(Locale.ROOT)), + ZeventScreenLayout.WIDTH, ZeventScreenLayout.HEIGHT, + PlaybackMode.LOCAL, 720, DisplayRotation.NONE, + key.dimension.identifier().toString()); + session.player = player; + // ZEVENT owns distance and the Minecraft Records slider; keep Dream's DSP on its legacy-gain path. + player.setAcousticsEnabled(false); + player.createTexture(); + player.loadVideo(TwitchChannel.streamUrl(channel), ""); + } catch (RuntimeException | LinkageError exception) { + if (player != null) { + try { + unregisterPlayer(player); + } catch (RuntimeException | LinkageError cleanupException) { + exception.addSuppressed(cleanupException); + } } - try { - MCEFBrowser browser = api.createBrowser(PAGE_SERVER.playerUrl(session.channel), false); - browser.resize(BROWSER_WIDTH, BROWSER_HEIGHT); - browser.setFocus(false); - session.browser = browser; - client.getTextureManager().register(session.textureId, new BrowserTexture(browser)); - session.textureRegistered = true; - } catch (IOException | RuntimeException | LinkageError exception) { - session.failed = true; - ZeventMod.LOGGER.error("Unable to create the ZEVENT Twitch player", exception); - } - })); + session.player = null; + ZeventMod.LOGGER.error("Unable to create the native ZEVENT Twitch player", exception); + if (client.player != null) client.player.sendOverlayMessage(Component.translatable( + "message.zevent.player.unavailable", channel)); + } + return session; } private static void updateVolumes(Minecraft client, long now) { Session nearest = SESSIONS.values().stream() - .filter(session -> session.browser != null && now - session.lastSeenTick <= AUDIBLE_FRESH_TICKS) + .filter(session -> session.player != null && now - session.lastSeenTick <= AUDIBLE_FRESH_TICKS) .filter(session -> distanceSqr(client, session.key.pos) <= AUDIO_DISTANCE_SQR) .min(Comparator.comparingDouble(session -> distanceSqr(client, session.key.pos))) .orElse(null); for (Session session : SESSIONS.values()) { + if (session.player == null) continue; float volume = session == nearest ? attenuatedVolume(client, session.key.pos) : 0.0F; - session.updateVolume(volume); + session.player.setVideoVolume(volume); } } @@ -143,23 +191,28 @@ public final class TwitchBrowserManager { : client.player.distanceToSqr(Vec3.atCenterOf(pos)); } - private static void remove(Minecraft client, Session session) { + private static void remove(Session session) { if (SESSIONS.remove(session.key) == null) return; - if (session.browser != null) session.updateVolume(0.0F); - if (session.textureRegistered) client.getTextureManager().release(session.textureId); - if (session.browser != null) { + if (session.player != null) { try { - session.browser.close(); + unregisterPlayer(session.player); } catch (RuntimeException | LinkageError exception) { - ZeventMod.LOGGER.warn("Unable to close a ZEVENT browser cleanly", exception); + ZeventMod.LOGGER.warn("Unable to close a ZEVENT Twitch player cleanly", exception); } - session.browser = null; + session.player = null; } } - private static Identifier textureId(ScreenKey key) { - String dimension = Integer.toUnsignedString(key.dimension.identifier().hashCode(), 36); - return ZeventMod.id("live/" + dimension + "/" + Long.toUnsignedString(key.pos.asLong(), 36)); + private static void unregisterPlayer(DisplayScreen player) { + player.setVideoVolume(0.0F); + UUID displayId = player.getUuid(); + try { + player.unregister(); + } finally { + AudioAcousticsService acoustics = DreamServices.INSTANCE.getRegistry() + .getOrNull(AudioAcousticsServices.INSTANCE.getACOUSTICS()); + if (acoustics != null) acoustics.unregisterSource(displayId); + } } private record ScreenKey(ResourceKey dimension, BlockPos pos) { @@ -167,40 +220,24 @@ public final class TwitchBrowserManager { private static final class Session { private final ScreenKey key; - private final Identifier textureId; + private final Direction facing; private String channel; - private MCEFBrowser browser; + private DisplayScreen player; private long lastSeenTick; - private float lastVolume = -1.0F; - private boolean starting; - private boolean failed; - private boolean textureRegistered; + private long lastRetryTick; + private boolean errorReported; - private Session(ScreenKey key, String channel, Identifier textureId) { + private Session(ScreenKey key, Direction facing, String channel) { this.key = key; + this.facing = facing; this.channel = channel; - this.textureId = textureId; } private void changeChannel(String next) { channel = next; - if (browser == null) return; - execute("window.zeventSetChannel&&window.zeventSetChannel('" + next + "');"); - } - - private void updateVolume(float volume) { - if (browser == null || Math.abs(volume - lastVolume) < 0.01F) return; - lastVolume = volume; - execute("window.zeventSetVolume&&window.zeventSetVolume(" + Float.toString(volume) + ");"); - } - - private void execute(String script) { - try { - String url = browser.getCefBrowser().getURL(); - browser.getCefBrowser().executeJavaScript(script, url == null ? "" : url, 0); - } catch (RuntimeException | LinkageError exception) { - ZeventMod.LOGGER.debug("ZEVENT browser command failed: {}", exception.getMessage()); - } + lastRetryTick = 0L; + errorReported = false; + if (player != null) player.loadVideo(TwitchChannel.streamUrl(next), ""); } } } diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServer.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServer.java deleted file mode 100644 index 11f0466..0000000 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServer.java +++ /dev/null @@ -1,108 +0,0 @@ -package fr.koka99cab.sanctuary26.zevent.client.twitch; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpServer; -import fr.koka99cab.sanctuary26.zevent.twitch.TwitchChannel; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** Loopback-only origin required by Twitch's official interactive embed. */ -final class TwitchPlayerPageServer { - private static final String PLAYER_PATH = "/player/"; - private HttpServer server; - private ExecutorService executor; - - synchronized String playerUrl(String channel) throws IOException { - if (!TwitchChannel.valid(channel)) throw new IllegalArgumentException("Invalid Twitch channel"); - ensureStarted(); - return "http://localhost:" + server.getAddress().getPort() + PLAYER_PATH + channel; - } - - synchronized void stop() { - if (server != null) { - server.stop(0); - server = null; - } - if (executor != null) { - executor.shutdownNow(); - executor = null; - } - } - - private void ensureStarted() throws IOException { - if (server != null) return; - server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); - executor = Executors.newSingleThreadExecutor(runnable -> { - Thread thread = new Thread(runnable, "ZEVENT Twitch page"); - thread.setDaemon(true); - return thread; - }); - server.setExecutor(executor); - server.createContext(PLAYER_PATH, this::servePlayer); - server.start(); - } - - private void servePlayer(HttpExchange exchange) throws IOException { - try (exchange) { - if (!"GET".equals(exchange.getRequestMethod())) { - exchange.sendResponseHeaders(405, -1L); - return; - } - String path = exchange.getRequestURI().getPath(); - String channel = path.startsWith(PLAYER_PATH) - ? TwitchChannel.normalize(path.substring(PLAYER_PATH.length())).orElse(null) - : null; - if (channel == null) { - exchange.sendResponseHeaders(404, -1L); - return; - } - byte[] body = page(channel).getBytes(StandardCharsets.UTF_8); - exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8"); - exchange.getResponseHeaders().set("Cache-Control", "no-store"); - exchange.getResponseHeaders().set("X-Content-Type-Options", "nosniff"); - exchange.getResponseHeaders().set("Referrer-Policy", "no-referrer"); - exchange.getResponseHeaders().set("Content-Security-Policy", - "default-src 'self' https: wss: blob: data:; script-src 'unsafe-inline' https://player.twitch.tv; " - + "frame-src https://player.twitch.tv; style-src 'unsafe-inline'"); - exchange.sendResponseHeaders(200, body.length); - exchange.getResponseBody().write(body); - } - } - - private static String page(String channel) { - return """ - - - - - - - - -
- - """.replace("__CHANNEL__", channel); - } -} diff --git a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannel.java b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannel.java index df4659c..7870724 100644 --- a/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannel.java +++ b/zevent/src/main/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannel.java @@ -39,6 +39,11 @@ public final class TwitchChannel { return channel != null && NAME.matcher(channel).matches(); } + public static String streamUrl(String channel) { + if (!valid(channel)) throw new IllegalArgumentException("Invalid Twitch channel"); + return "https://www.twitch.tv/" + channel; + } + private static Optional channelFromUrl(String input) { try { URI uri = URI.create(input); diff --git a/zevent/src/main/resources/assets/zevent/lang/en_us.json b/zevent/src/main/resources/assets/zevent/lang/en_us.json index af11973..ba2bff8 100644 --- a/zevent/src/main/resources/assets/zevent/lang/en_us.json +++ b/zevent/src/main/resources/assets/zevent/lang/en_us.json @@ -13,5 +13,6 @@ "message.zevent.screen.too_far": "You are too far away from the screen.", "message.zevent.screen.missing": "The ZEVENT screen no longer exists.", "message.zevent.screen.newer_data": "This screen uses newer data and is read-only.", - "message.zevent.player.initializing": "Initializing the Twitch player…" + "message.zevent.player.initializing": "Initializing the Twitch decoder…", + "message.zevent.player.unavailable": "Channel twitch.tv/%s is offline or temporarily unavailable." } diff --git a/zevent/src/main/resources/assets/zevent/lang/fr_fr.json b/zevent/src/main/resources/assets/zevent/lang/fr_fr.json index 7c0a796..68ba68a 100644 --- a/zevent/src/main/resources/assets/zevent/lang/fr_fr.json +++ b/zevent/src/main/resources/assets/zevent/lang/fr_fr.json @@ -13,5 +13,6 @@ "message.zevent.screen.too_far": "Tu es trop loin de l'écran.", "message.zevent.screen.missing": "L'écran ZEVENT n'existe plus.", "message.zevent.screen.newer_data": "Cet écran utilise des données plus récentes et reste en lecture seule.", - "message.zevent.player.initializing": "Initialisation du lecteur Twitch…" + "message.zevent.player.initializing": "Initialisation du décodeur Twitch…", + "message.zevent.player.unavailable": "La chaîne twitch.tv/%s est hors ligne ou momentanément inaccessible." } diff --git a/zevent/src/main/resources/assets/zevent/lang/ru_ru.json b/zevent/src/main/resources/assets/zevent/lang/ru_ru.json index 304f8c7..8e6615d 100644 --- a/zevent/src/main/resources/assets/zevent/lang/ru_ru.json +++ b/zevent/src/main/resources/assets/zevent/lang/ru_ru.json @@ -13,5 +13,6 @@ "message.zevent.screen.too_far": "Вы слишком далеко от экрана.", "message.zevent.screen.missing": "Экран ZEVENT больше не существует.", "message.zevent.screen.newer_data": "Этот экран использует более новые данны и доступен только для чтения.", - "message.zevent.player.initializing": "Инициализация плеера Twitch…" + "message.zevent.player.initializing": "Инициализация декодера Twitch…", + "message.zevent.player.unavailable": "Канал twitch.tv/%s не в сети или временно недоступен." } diff --git a/zevent/src/main/resources/fabric.mod.json b/zevent/src/main/resources/fabric.mod.json index 7a6cb31..50de79f 100644 --- a/zevent/src/main/resources/fabric.mod.json +++ b/zevent/src/main/resources/fabric.mod.json @@ -22,10 +22,8 @@ "fabricloader": ">=0.19.3", "minecraft": "~26.2", "java": ">=25", - "fabric-api": ">=0.159.0+26.2" - }, - "suggests": { - "mcef-modern": ">=0.3.3" + "fabric-api": ">=0.159.0+26.2", + "dreamdisplays": ">=1.9.6" }, "custom": { "sanctuary26": { diff --git a/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayoutTest.java b/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayoutTest.java new file mode 100644 index 0000000..3a7ce9b --- /dev/null +++ b/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/block/ZeventScreenLayoutTest.java @@ -0,0 +1,34 @@ +package fr.koka99cab.sanctuary26.zevent.block; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import org.junit.jupiter.api.Test; + +class ZeventScreenLayoutTest { + @Test + void mediaAnchorAlwaysCoversTheCompleteNineByFiveScreen() { + BlockPos controller = new BlockPos(20, 70, -10); + for (Direction facing : Direction.Plane.HORIZONTAL) { + BlockPos anchor = ZeventScreenLayout.anchor(controller, facing); + for (int column = 0; column < ZeventScreenLayout.WIDTH; column++) { + for (int row = 0; row < ZeventScreenLayout.HEIGHT; row++) { + BlockPos part = ZeventScreenLayout.partPos(controller, facing, column, row); + assertTrue(part.getY() >= anchor.getY()); + assertTrue(part.getY() < anchor.getY() + ZeventScreenLayout.HEIGHT); + if (facing.getAxis() == Direction.Axis.Z) { + assertTrue(part.getX() >= anchor.getX()); + assertTrue(part.getX() < anchor.getX() + ZeventScreenLayout.WIDTH); + assertEquals(anchor.getZ(), part.getZ()); + } else { + assertTrue(part.getZ() >= anchor.getZ()); + assertTrue(part.getZ() < anchor.getZ() + ZeventScreenLayout.WIDTH); + assertEquals(anchor.getX(), part.getX()); + } + } + } + } + } +} diff --git a/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServerTest.java b/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServerTest.java deleted file mode 100644 index e7980c5..0000000 --- a/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/client/twitch/TwitchPlayerPageServerTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.koka99cab.sanctuary26.zevent.client.twitch; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import org.junit.jupiter.api.Test; - -class TwitchPlayerPageServerTest { - @Test - void servesOnlyTheBoundedOfficialPlayerPage() throws Exception { - TwitchPlayerPageServer server = new TwitchPlayerPageServer(); - try (HttpClient client = HttpClient.newHttpClient()) { - String url = server.playerUrl("zeventfr"); - HttpResponse response = client.send( - HttpRequest.newBuilder(URI.create(url)).GET().build(), HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - assertTrue(response.body().contains("https://player.twitch.tv/js/embed/v1.js")); - assertTrue(response.body().contains("const initialChannel=\"zeventfr\"")); - assertTrue(response.headers().firstValue("Content-Security-Policy").isPresent()); - assertThrows(IllegalArgumentException.class, () -> server.playerUrl("bad-channel!")); - } finally { - server.stop(); - } - } -} diff --git a/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannelTest.java b/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannelTest.java index f6b4d09..7abc1ba 100644 --- a/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannelTest.java +++ b/zevent/src/test/java/fr/koka99cab/sanctuary26/zevent/twitch/TwitchChannelTest.java @@ -19,4 +19,11 @@ class TwitchChannelTest { assertTrue(TwitchChannel.normalize("bad-channel!").isEmpty()); assertTrue(TwitchChannel.normalize("a".repeat(TwitchChannel.MAX_NAME_LENGTH + 1)).isEmpty()); } + + @Test + void buildsOnlyValidatedPlaybackUrls() { + assertEquals("https://www.twitch.tv/zeventfr", TwitchChannel.streamUrl("zeventfr")); + org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, + () -> TwitchChannel.streamUrl("bad-channel!")); + } }