Sanctuary 26.2.0-alpha.199 — contrats complets des demandes de quêtes #6
@@ -6,6 +6,21 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
|
||||
- Depuis `26.2.0-alpha.6`, le pack et les modules ont des versions indépendantes. I Like To Move It et Only Fun deviennent les cinquième et sixième modules actifs dans l'alpha 46.
|
||||
- Les versions ci-dessous ont été reconstituées à partir des JAR archivés, des packs locaux et du code source actuel. Les dates n'étant pas enregistrées de manière fiable, elles ne sont pas inventées.
|
||||
|
||||
## `26.2.0-alpha.199`
|
||||
|
||||
Module modifié : **Sanctuary `0.0.0-alpha.115`**. Les neuf autres modules conservent leur version issue de l’alpha.198.
|
||||
|
||||
- donne au panneau communautaire de demandes une texture rose framboise dédiée, sans changer ses IDs debout et mural ;
|
||||
- réduit le texte visible sur le panneau au demandeur, à l’état disponible/prise et à l’invitation à lire les détails ;
|
||||
- remplace la réservation immédiate par un aperçu détaillé dans le chat puis un bouton cliquable de confirmation ;
|
||||
- revalide lors de cette confirmation la distance, la dimension, le panneau physique, le propriétaire et l’absence de réservation concurrente ;
|
||||
- complète l’éditeur avec une cible KILL de type mob ou joueur et conserve BRING sur un item et PAY sur un joueur ;
|
||||
- ajoute une récompense promise obligatoire pour les nouvelles demandes, sous forme de don, paiement ou prêt d’un item et d’une quantité validés côté serveur ;
|
||||
- présente séparément dans le chat le demandeur, l’objectif, la mission, la cible, la quantité, la récompense et l’éventuel preneur ;
|
||||
- migre monotoniquement `quest_requests` de la donnée v1 à v2 ; les anciennes demandes restent lisibles avec une récompense non renseignée ;
|
||||
- porte le protocole Sanctuary de 19 à 20 pour les nouveaux champs bornés, sans automatiser la remise de récompense, le retour d’un prêt ou la complétion ;
|
||||
- conserve les données Sanctuary v11, tous les IDs de registre et les sauvegardes existantes.
|
||||
|
||||
## `26.2.0-alpha.198`
|
||||
|
||||
Modules modifiés : **It's Alive `0.0.0-alpha.30`** et **Sanctuary `0.0.0-alpha.114`**. Les huit autres modules restent inchangés.
|
||||
|
||||
@@ -22,7 +22,9 @@ Licence : **GNU GPL 3.0 or Later** (`GPL-3.0-or-later`)
|
||||
|
||||
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 local : **`26.2.0-alpha.198`**. It's Alive passe en **`0.0.0-alpha.30`** et Sanctuary en **`0.0.0-alpha.114`** ; les huit autres modules restent inchangés.
|
||||
Version courante du pack local : **`26.2.0-alpha.199`**. It's Alive est en **`0.0.0-alpha.30`** et Sanctuary passe en **`0.0.0-alpha.115`** ; les huit autres modules restent inchangés.
|
||||
|
||||
L’alpha.199 rend le panneau communautaire immédiatement identifiable grâce à une texture rose dédiée et garde son texte minimal. Un clic droit affiche désormais dans le chat l’objectif complet, la cible mob/item/joueur et la récompense promise sous forme de don, paiement ou prêt ; la quête n’est prise qu’après confirmation sur le bouton du chat. Les contrats restent communautaires : le serveur valide et conserve leurs termes sans simuler une remise, une restitution ou une complétion automatique.
|
||||
|
||||
L’alpha.198 borne l’automatisation du tonneau de fermentation : chaque emplacement n’accepte qu’une unité utile à une recette encore réalisable, les doublons invalides sont refusés et les observateurs suivent les changements visibles du contenu sans impulsion de progression parasite. Elle intègre aussi la correction de Chris : le shift-clic de l’inventaire suit le comportement vanilla sur toutes les rangées débloquées, y compris les rangées 5 et 6, tandis qu’une rangée de stockage ou d’overflow n’alimente que la hotbar.
|
||||
|
||||
@@ -34,7 +36,7 @@ L’alpha.195 charge le catalogue Shop depuis le CSV rééquilibré et conserve
|
||||
|
||||
L’alpha.194 ouvre la cuisine avec huit cultures supplémentaires — riz, soja, haricot, pois chiche, piment, basilic, menthe et coriandre — ainsi que le café, la vanille, l’olivier et le citronnier. Le riz pousse réellement immergé sur de la boue, le haricot se récolte jeune ou sec, le café se torréfie et la vanille se sèche au smoker. Le climat détermine seulement la découverte : les nouvelles plantes sauvages apparaissent dans les nouveaux chunks, tandis qu’une chance rare de semence sur la végétation permet de continuer un monde existant. Aucune réinitialisation de sauvegarde n’est requise.
|
||||
|
||||
Le [wiki cuisine de l’alpha.197](itsalive/FOOD_WIKI.md) détaille les cultures, les six postes, l’automatisation, les ingrédients transformés, le livre et ses 64 recettes.
|
||||
Le [wiki cuisine de l’alpha.199](itsalive/FOOD_WIKI.md) détaille les cultures, les six postes, l’automatisation, les ingrédients transformés, le livre et ses 64 recettes.
|
||||
|
||||
L’alpha.193 donne à chaque item du Shop une petite variation de prix stable et reproductible, tout en réservant des tarifs explicites aux vrais objets exceptionnels. L’œuf doré, porte d’entrée extrêmement rare vers les poules à gemmes, coûte désormais 811 rubis ou 59 saphirs dans le catalogue. Les six emplacements verrouillés occupent directement les six cartes restantes de la grille : ils se débloquent toujours dans l’ordre pour 2, 4, 8, 12, 18 puis 25 niveaux. L’aide de boîte aux lettres remonte légèrement et la bourse rubis/saphirs s’ancre en bas à droite.
|
||||
|
||||
|
||||
+71
-25
@@ -3427,8 +3427,8 @@ 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.198"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.114"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.115"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.19"
|
||||
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|
||||
|| migration.source?.modules != [sanctuary: "0.0.0-alpha.108", onlyfun: "0.0.0-alpha.17"]
|
||||
@@ -3477,7 +3477,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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.49"
|
||||
|| rootProject.redstoner_version != "0.0.0-alpha.10"
|
||||
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|
||||
@@ -4121,9 +4121,9 @@ 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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.19"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.114"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.115"
|
||||
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.192"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.193"
|
||||
@@ -4166,7 +4166,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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.30"
|
||||
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.193"
|
||||
@@ -4215,9 +4215,9 @@ 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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.19"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.114"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.115"
|
||||
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.194"
|
||||
|| migration.source?.modules != [onlyfun: "0.0.0-alpha.18", sanctuary: "0.0.0-alpha.110"]
|
||||
@@ -4261,7 +4261,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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.195"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.196"
|
||||
|| migration.target?.modules != [
|
||||
@@ -4279,10 +4279,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.198"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.198.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.198"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.198"')) {
|
||||
|| release.pack_version != "26.2.0-alpha.199"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.199.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.199"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.199"')) {
|
||||
throw new GradleException("The alpha.196 culinary, mailbox and grapple release contract is incomplete")
|
||||
}
|
||||
}
|
||||
@@ -4307,9 +4307,9 @@ 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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.30"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.114"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.115"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.196"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.197"
|
||||
|| migration.target?.modules != [itsalive: "0.0.0-alpha.29", sanctuary: "0.0.0-alpha.113"]
|
||||
@@ -4326,11 +4326,11 @@ tasks.register("verifyQuestRequestsCauldronBatchesRelease") {
|
||||
|| migration.distribution?.jei?.prism_source != "30.24.0.176"
|
||||
|| migration.distribution?.jei?.target != "30.26.0.186"
|
||||
|| migration.compatibility?.sanctuary_target_network_protocol != 19
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 19
|
||||
|| release.pack_version != "26.2.0-alpha.198"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.198.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.198"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.198"')) {
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 20
|
||||
|| release.pack_version != "26.2.0-alpha.199"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.199.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.199"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.199"')) {
|
||||
throw new GradleException("The alpha.197 quest-request and cauldron-batch release contract is incomplete")
|
||||
}
|
||||
}
|
||||
@@ -4357,7 +4357,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.198"
|
||||
if (rootProject.pack_version != "26.2.0-alpha.199"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.30"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.197"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.198"
|
||||
@@ -4376,10 +4376,10 @@ tasks.register("verifyFermentationBarrelAutomationRelease") {
|
||||
|| migration.distribution?.packwiz_index_refreshed != true
|
||||
|| itsAliveManifest.custom?.sanctuary26?.data_version != 1
|
||||
|| itsAliveManifest.custom?.sanctuary26?.network_protocol != 3
|
||||
|| release.pack_version != "26.2.0-alpha.198"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.198.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.198"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.198"')
|
||||
|| release.pack_version != "26.2.0-alpha.199"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.199.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.199"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.199"')
|
||||
|| !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.30.jar"')) {
|
||||
throw new GradleException("The alpha.198 fermentation barrel release contract is incomplete")
|
||||
}
|
||||
@@ -4390,6 +4390,52 @@ tasks.named("verifyWorkspace") {
|
||||
dependsOn tasks.named("verifyFermentationBarrelAutomationRelease")
|
||||
}
|
||||
|
||||
tasks.register("verifyQuestRequestContractsRelease") {
|
||||
group = "verification"
|
||||
description = "Checks the complete Sanctuary 26.2.0-alpha.199 quest-request contract release."
|
||||
inputs.file(file("pack/migrations/26.2.0-alpha.198-quest-request-contracts-to-alpha.199.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("sanctuary/src/main/resources/fabric.mod.json"))
|
||||
doLast {
|
||||
def migration = new JsonSlurper().parse(file(
|
||||
"pack/migrations/26.2.0-alpha.198-quest-request-contracts-to-alpha.199.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 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.199"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.30"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.115"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.198"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.114"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.199"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.115"
|
||||
|| migration.quest_request_contracts?.target_data_version != 2
|
||||
|| migration.quest_request_contracts?.kill_target_kinds != ["mob", "player"]
|
||||
|| migration.quest_request_contracts?.reward_types != ["gift", "payment", "loan"]
|
||||
|| migration.quest_request_contracts?.right_click_shows_details_before_claim != true
|
||||
|| 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 != 20
|
||||
|| release.pack_version != "26.2.0-alpha.199"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.199.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.199"
|
||||
|| !packwiz.contains('version = "26.2.0-alpha.199"')
|
||||
|| !packwizIndex.contains('file = "mods/itsalive-0.0.0-alpha.30.jar"')
|
||||
|| !packwizIndex.contains('file = "mods/sanctuary-0.0.0-alpha.115.jar"')) {
|
||||
throw new GradleException("The alpha.199 quest-request contract release is incomplete")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("verifyWorkspace") {
|
||||
dependsOn tasks.named("verifyQuestRequestContractsRelease")
|
||||
}
|
||||
|
||||
tasks.named("check") {
|
||||
dependsOn tasks.named("verifyWorkspace")
|
||||
dependsOn tasks.named("verifyTransport")
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ iliketomoveit_version=0.0.0-alpha.13
|
||||
iliketomoveit_lifecycle=active
|
||||
onlyfun_version=0.0.0-alpha.19
|
||||
onlyfun_lifecycle=active
|
||||
sanctuary_version=0.0.0-alpha.114
|
||||
sanctuary_version=0.0.0-alpha.115
|
||||
sanctuary_lifecycle=active
|
||||
pack_version=26.2.0-alpha.198
|
||||
pack_version=26.2.0-alpha.199
|
||||
maven_group=fr.koka99cab.sanctuary26
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"source": {
|
||||
"pack_version": "26.2.0-alpha.198",
|
||||
"modules": {
|
||||
"sanctuary": "0.0.0-alpha.114"
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"pack_version": "26.2.0-alpha.199",
|
||||
"modules": {
|
||||
"sanctuary": "0.0.0-alpha.115"
|
||||
}
|
||||
},
|
||||
"quest_request_contracts": {
|
||||
"standing_id": "sanctuary:quest_request_sign",
|
||||
"wall_id": "sanctuary:quest_request_wall_sign",
|
||||
"save_key": "quest_requests",
|
||||
"source_data_version": 1,
|
||||
"target_data_version": 2,
|
||||
"existing_requests_default_reward": "none",
|
||||
"new_requests_require_reward": true,
|
||||
"kill_target_kinds": ["mob", "player"],
|
||||
"reward_types": ["gift", "payment", "loan"],
|
||||
"reward_item_server_validated": true,
|
||||
"reward_transfer_or_completion_automated": false,
|
||||
"right_click_shows_details_before_claim": true,
|
||||
"chat_accept_command": "sanctuary_quest_accept",
|
||||
"chat_accept_revalidates_distance_owner_sign_and_claim": true,
|
||||
"minimal_sign_text": true,
|
||||
"pink_block_texture": "sanctuary:block/pink_quest_request_sign",
|
||||
"pink_item_texture": "sanctuary:item/pink_quest_request_sign"
|
||||
},
|
||||
"distribution": {
|
||||
"prism_instance": "Sanctuary-26.2-dev",
|
||||
"packwiz_index_refreshed": true
|
||||
},
|
||||
"compatibility": {
|
||||
"sanctuary_data_version": 11,
|
||||
"sanctuary_source_network_protocol": 19,
|
||||
"sanctuary_target_network_protocol": 20,
|
||||
"existing_requests_preserved": true,
|
||||
"save_migration_monotone": true,
|
||||
"registry_ids_changed": false
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -14,15 +14,15 @@ hash = "41f4f4c88c71d0a23446d5014f7407d55ad477441847099cad24492b032335a0"
|
||||
|
||||
[[files]]
|
||||
file = "mods/ambiance-0.0.0-alpha.11.jar"
|
||||
hash = "70c23a4e4059eaf52f99e4a31585169c6599b4e33ad7554cddbbec536096cc64"
|
||||
hash = "12e63938bba723137faa9f3a416ab8e4068b0297230cfc39a2031cdd439aa784"
|
||||
|
||||
[[files]]
|
||||
file = "mods/anotherworld-0.0.0-alpha.49.jar"
|
||||
hash = "69f6c36628503f5abf04ec3f9e8351d7b3e5468829573733590641a9078760d0"
|
||||
hash = "da09dbbd260d913e6a6aebd7759883ccdb408481bc0392db8063e82b1b89c95b"
|
||||
|
||||
[[files]]
|
||||
file = "mods/events-0.0.0-alpha.0.jar"
|
||||
hash = "2cd283f8b85055a405947a41325f9780b98046b659a24a95c3279d96c97205d5"
|
||||
hash = "85ca0dafb7851077a0ab7fe86e9ec9897d73befe9b658f1871969c3a1ebacf59"
|
||||
|
||||
[[files]]
|
||||
file = "mods/fabric-api.pw.toml"
|
||||
@@ -31,7 +31,7 @@ metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/iliketomoveit-0.0.0-alpha.13.jar"
|
||||
hash = "b1b33c5fe7089b8d1baac4ce5fbd0ee386def1456b71af6f761d6ae800e61690"
|
||||
hash = "138350c1f085a97d3ff1119749024cc73c67f780ab359eed69d31d44a7e2471e"
|
||||
|
||||
[[files]]
|
||||
file = "mods/iris.pw.toml"
|
||||
@@ -40,7 +40,7 @@ metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/itsalive-0.0.0-alpha.30.jar"
|
||||
hash = "57a7a91b47c5648710fa165a894c785c5958afe07f7d7f4e3ef4d0cc38cacd8b"
|
||||
hash = "747e5e6d61c87f68c5b9efe3eaa54daa511f044dc964b0352d9212766c06f1bf"
|
||||
|
||||
[[files]]
|
||||
file = "mods/jei.pw.toml"
|
||||
@@ -49,23 +49,23 @@ metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/masterkey-0.0.0-alpha.8.jar"
|
||||
hash = "90803d3a67065ee02cca4fc32c8f18301e93e1ff2c4c8002feb5f28c7ec014da"
|
||||
hash = "3ab2dac208babbd6d503a25c7d41a91d337f15f30f9da5c25988b9a5daa1b3d3"
|
||||
|
||||
[[files]]
|
||||
file = "mods/onlyfun-0.0.0-alpha.19.jar"
|
||||
hash = "86c7f88ec348f678cb873d2386df38ca300928f4b0e7c350cae722ba42389986"
|
||||
hash = "be2b83a6033df420887d643b91c5bdfee5f3bb3933f156e36f256cd59c0fc083"
|
||||
|
||||
[[files]]
|
||||
file = "mods/ouch-0.0.0-alpha.8.jar"
|
||||
hash = "bd57342e13832fe67e7abeb0f2768170552fd868668a6f6940cd73f57dd7b37c"
|
||||
hash = "b77e0b00aa2be6bab0fb9d3d749758b492323e756d1a9848ee7d7776fedf8afb"
|
||||
|
||||
[[files]]
|
||||
file = "mods/redstoner-0.0.0-alpha.10.jar"
|
||||
hash = "2259c2a982c14d29f27c7a0908aeee11b7156b2823202a200aa89af24703eb23"
|
||||
hash = "a51b166afef4a687ca77a7a3e149b008adc94dbe6a5d387ed27ec5a01caaf2f9"
|
||||
|
||||
[[files]]
|
||||
file = "mods/sanctuary-0.0.0-alpha.114.jar"
|
||||
hash = "7e45eb1a6756ed9a95d79d794b7c2e7a6918388fd9e5286160cd890d1dfaf0f6"
|
||||
file = "mods/sanctuary-0.0.0-alpha.115.jar"
|
||||
hash = "d57eb30bd5235a0d9fe5f26eb486362bc71a2a90e01f6f248ae2e8ab7a8ba935"
|
||||
|
||||
[[files]]
|
||||
file = "mods/simple-voice-chat.pw.toml"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
name = "Sanctuary 26.2"
|
||||
author = "KOKA99CAB"
|
||||
version = "26.2.0-alpha.198"
|
||||
version = "26.2.0-alpha.199"
|
||||
pack-format = "packwiz:1.1.0"
|
||||
|
||||
[index]
|
||||
file = "index.toml"
|
||||
hash-format = "sha256"
|
||||
hash = "55cce7f3d86dbb8546626ea5f3ed5596efa656ab41f528d8b7ed963470b81219"
|
||||
hash = "4365a5e895a893ef3c81ba895412563fbb336b217cd2301a5830ec132efb8886"
|
||||
|
||||
[versions]
|
||||
fabric = "0.19.3"
|
||||
|
||||
@@ -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.198",
|
||||
"versionId": "26.2.0-alpha.199",
|
||||
"files": [
|
||||
{
|
||||
"path": "mods/fabric-api-0.158.0+26.2.jar",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"pack_version": "26.2.0-alpha.198",
|
||||
"pack_version": "26.2.0-alpha.199",
|
||||
"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.198.mrpack",
|
||||
"primary_file": "sanctuary-26.2.0-alpha.199.mrpack",
|
||||
"shared_client_server_pack": true,
|
||||
"update_owner": "packwiz-installer",
|
||||
"check_on_launch": true,
|
||||
|
||||
+80
-10
@@ -1052,12 +1052,12 @@ tasks.register("verifySanctuary") {
|
||||
|
||||
def manifest = new JsonSlurper().parse(file("src/main/resources/fabric.mod.json"))
|
||||
if (manifest.custom?.sanctuary26?.data_version != 11
|
||||
|| manifest.custom?.sanctuary26?.network_protocol != 19
|
||||
|| manifest.custom?.sanctuary26?.network_protocol != 20
|
||||
|| manifest.depends?.jei != ">=30.24.0.176"
|
||||
|| manifest.depends?."fabric-api" != ">=0.155.0+26.2"
|
||||
|| !manifest.entrypoints?.client?.contains("fr.koka99cab.sanctuary26.sanctuary.client.SanctuaryClient")
|
||||
|| !manifest.mixins?.contains("sanctuary.mixins.json")) {
|
||||
throw new GradleException("Sanctuary must expose data v11, protocol 19, JEI and the client entrypoint")
|
||||
throw new GradleException("Sanctuary must expose data v11, protocol 20, JEI and the client entrypoint")
|
||||
}
|
||||
def capeMigration = new JsonSlurper().parse(rootProject.file(
|
||||
"pack/migrations/26.2.0-alpha.155-cape-equipment-to-alpha.156.json"))
|
||||
@@ -2886,7 +2886,7 @@ tasks.register("verifyProgressivePauseMenu") {
|
||||
"pack/migrations/26.2.0-alpha.190-progressive-pause-menu-to-alpha.191.json"))
|
||||
def pauseMenu = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/PauseScreenMixin.java").text
|
||||
def costs = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/progression/SanctuaryProgressionCosts.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.191"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.109"
|
||||
|| migration.pause_menu?.progression_full_width != true
|
||||
@@ -2924,7 +2924,7 @@ tasks.register("verifyShopPricingLayout") {
|
||||
"pack/migrations/26.2.0-alpha.192-shop-pricing-layout-to-alpha.193.json"))
|
||||
def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryShopScreen.java").text
|
||||
def progression = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopProgression.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.110"
|
||||
|| migration.shop_layout?.locked_offer_buttons != 6
|
||||
|| migration.shop_layout?.button_slots != [4, 5, 6, 7, 8, 9]
|
||||
@@ -2955,7 +2955,7 @@ tasks.register("verifyShopCsvBossGates") {
|
||||
"pack/migrations/26.2.0-alpha.194-shop-csv-boss-gates-to-alpha.195.json"))
|
||||
def provider = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopCatalogProvider.java").text
|
||||
def catalog = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.195"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.111"
|
||||
|| migration.compatibility?.sanctuary_data_version != 11
|
||||
@@ -2986,7 +2986,7 @@ tasks.register("verifyDeliveryBoxOrientation") {
|
||||
def blockstate = new JsonSlurper().parse(
|
||||
file("src/main/resources/assets/sanctuary/blockstates/delivery_box.json"))
|
||||
def expectedVariants = ["facing=north", "facing=east", "facing=south", "facing=west"].toSet()
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.112"
|
||||
|| migration.mailbox?.id != "sanctuary:delivery_box"
|
||||
|| migration.mailbox?.horizontal_facing != true
|
||||
@@ -3014,7 +3014,7 @@ tasks.register("verifyInventoryShiftClick") {
|
||||
def mixin = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/AbstractContainerMenuMixin.java").text
|
||||
def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/AbstractContainerScreenMixin.java").text
|
||||
def gui = file("INVENTORY_GUI.md").text
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| !transfer.contains("shouldAppendOverflow")
|
||||
|| !transfer.contains("isVanillaStorageRange")
|
||||
|| !transfer.contains("hotbarStart")
|
||||
@@ -3060,7 +3060,7 @@ tasks.register("verifyQuestRequests") {
|
||||
new JsonSlurper().parse(file("src/main/resources/data/sanctuary/loot_table/blocks/${path}.json"))
|
||||
.pools[0].entries[0].name
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.114"
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.113"
|
||||
|| migration.quest_requests?.save_key != "quest_requests"
|
||||
|| migration.quest_requests?.data_version != 1
|
||||
@@ -3069,10 +3069,10 @@ tasks.register("verifyQuestRequests") {
|
||||
|| migration.quest_requests?.drops_recoverable_item != true
|
||||
|| migration.quest_requests?.payloads?.server_validated_and_bounded != true
|
||||
|| migration.compatibility?.sanctuary_target_network_protocol != 19
|
||||
|| !data.contains('SAVE_KEY = "quest_requests"') || !data.contains("DATA_VERSION = 1")
|
||||
|| !data.contains('SAVE_KEY = "quest_requests"') || !data.contains("DATA_VERSION = 2")
|
||||
|| !service.contains("PlayerBlockBreakEvents.BEFORE")
|
||||
|| !service.contains("player.blockPosition().distSqr(payload.pos()) > 64.0D")
|
||||
|| !network.contains("PROTOCOL_VERSION = 19")
|
||||
|| !network.contains("PROTOCOL_VERSION = 20")
|
||||
|| !network.contains("QuestRequestSubmitPayload.ID")
|
||||
|| !registry.contains('SanctuaryMod.id("quest_request_sign")')
|
||||
|| lootIds != ["sanctuary:quest_request_sign", "sanctuary:quest_request_sign"]
|
||||
@@ -3086,6 +3086,75 @@ tasks.register("verifyQuestRequests") {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("verifyQuestRequestContracts") {
|
||||
group = "verification"
|
||||
description = "Checks alpha.115 pink quest-request previews, player targets and promised rewards."
|
||||
inputs.file(rootProject.file("pack/migrations/26.2.0-alpha.198-quest-request-contracts-to-alpha.199.json"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestRequestData.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestRequestService.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestRequestEditorScreen.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/SanctuaryNetworking.java"))
|
||||
inputs.files(fileTree("src/main/resources/assets/sanctuary/lang") { include "*.json" })
|
||||
inputs.files(fileTree("src/main/resources/assets/sanctuary/models") { include "**/quest_request*.json" })
|
||||
inputs.files(file(
|
||||
"src/main/resources/assets/sanctuary/textures/block/pink_quest_request_sign.png"), file(
|
||||
"src/main/resources/assets/sanctuary/textures/item/pink_quest_request_sign.png"))
|
||||
doLast {
|
||||
def migration = new JsonSlurper().parse(rootProject.file(
|
||||
"pack/migrations/26.2.0-alpha.198-quest-request-contracts-to-alpha.199.json"))
|
||||
def data = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestRequestData.java").text
|
||||
def service = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestRequestService.java").text
|
||||
def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestRequestEditorScreen.java").text
|
||||
def network = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/SanctuaryNetworking.java").text
|
||||
def standingModel = new JsonSlurper().parse(file(
|
||||
"src/main/resources/assets/sanctuary/models/block/quest_request_sign_rot_0.json"))
|
||||
def itemModel = new JsonSlurper().parse(file(
|
||||
"src/main/resources/assets/sanctuary/models/item/quest_request_sign.json"))
|
||||
def blockTexture = ImageIO.read(file(
|
||||
"src/main/resources/assets/sanctuary/textures/block/pink_quest_request_sign.png"))
|
||||
def itemTexture = ImageIO.read(file(
|
||||
"src/main/resources/assets/sanctuary/textures/item/pink_quest_request_sign.png"))
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collectEntries { locale ->
|
||||
[(locale): new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${locale}.json"))]
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.115"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.198"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.114"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.199"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.115"
|
||||
|| migration.quest_request_contracts?.source_data_version != 1
|
||||
|| migration.quest_request_contracts?.target_data_version != 2
|
||||
|| migration.quest_request_contracts?.kill_target_kinds != ["mob", "player"]
|
||||
|| migration.quest_request_contracts?.reward_types != ["gift", "payment", "loan"]
|
||||
|| migration.quest_request_contracts?.right_click_shows_details_before_claim != true
|
||||
|| migration.quest_request_contracts?.chat_accept_revalidates_distance_owner_sign_and_claim != true
|
||||
|| migration.compatibility?.sanctuary_target_network_protocol != 20
|
||||
|| !data.contains("DATA_VERSION = 2")
|
||||
|| !data.contains('optionalFieldOf("reward_type"')
|
||||
|| !service.contains('Commands.literal("sanctuary_quest_accept")')
|
||||
|| !service.contains("new ClickEvent.RunCommand")
|
||||
|| !service.contains('REWARD_LOAN = "loan"')
|
||||
|| !service.contains('PLAYER.equals(targetKind)')
|
||||
|| !screen.contains("rewardQuantity") || !screen.contains("killTargetIndex")
|
||||
|| !network.contains("PROTOCOL_VERSION = 20")
|
||||
|| standingModel.textures?.all != "sanctuary:block/pink_quest_request_sign"
|
||||
|| itemModel.textures?.layer0 != "sanctuary:item/pink_quest_request_sign"
|
||||
|| blockTexture == null || blockTexture.width != 32 || blockTexture.height != 32
|
||||
|| !blockTexture.colorModel.hasAlpha()
|
||||
|| itemTexture == null || itemTexture.width != 16 || itemTexture.height != 16
|
||||
|| !itemTexture.colorModel.hasAlpha()
|
||||
|| locales.any { locale, values ->
|
||||
!values.containsKey("screen.sanctuary.quest_request.reward_type.loan")
|
||||
|| !values.containsKey("screen.sanctuary.quest_request.target_hint.kill.player")
|
||||
|| !values.containsKey("message.sanctuary.quest_request.accept")
|
||||
|| !values.containsKey("message.sanctuary.quest_request.details.reward")
|
||||
|| !values.containsKey("sign.sanctuary.quest_request.details")
|
||||
}) {
|
||||
throw new GradleException("Sanctuary alpha.115 quest-request contract is incomplete")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("verifySanctuary") {
|
||||
dependsOn tasks.named("verifyInventoryShiftClick")
|
||||
}
|
||||
@@ -3094,6 +3163,7 @@ tasks.named("check") {
|
||||
dependsOn tasks.named("verifySanctuary")
|
||||
dependsOn tasks.named("verifyDeliveryBoxOrientation")
|
||||
dependsOn tasks.named("verifyQuestRequests")
|
||||
dependsOn tasks.named("verifyQuestRequestContracts")
|
||||
dependsOn tasks.named("celestialGraphSmoke")
|
||||
dependsOn tasks.named("questRequestModelSmoke")
|
||||
}
|
||||
|
||||
+97
-29
@@ -10,20 +10,30 @@ import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
/** Bounded editor for community quest requests; the server remains authoritative. */
|
||||
/** Complete bounded editor for mission target and promised reward contracts. */
|
||||
public final class QuestRequestEditorScreen extends Screen {
|
||||
private static final String[] ACTIONS = {
|
||||
QuestRequestService.KILL, QuestRequestService.BRING, QuestRequestService.PAY
|
||||
};
|
||||
private static final String[] REWARDS = {
|
||||
QuestRequestService.REWARD_GIFT, QuestRequestService.REWARD_PAYMENT,
|
||||
QuestRequestService.REWARD_LOAN
|
||||
};
|
||||
private final Screen parent;
|
||||
private final QuestRequestEditorPayload payload;
|
||||
private EditBox alias;
|
||||
private EditBox objective;
|
||||
private EditBox target;
|
||||
private EditBox quantity;
|
||||
private EditBox rewardTarget;
|
||||
private EditBox rewardQuantity;
|
||||
private Button action;
|
||||
private Button targetKind;
|
||||
private Button reward;
|
||||
private Button submit;
|
||||
private int actionIndex;
|
||||
private int rewardIndex;
|
||||
private int killTargetIndex;
|
||||
|
||||
public QuestRequestEditorScreen(Screen parent, QuestRequestEditorPayload payload) {
|
||||
super(Component.translatable("screen.sanctuary.quest_request.title"));
|
||||
@@ -32,18 +42,22 @@ public final class QuestRequestEditorScreen extends Screen {
|
||||
for (int index = 0; index < ACTIONS.length; index++) {
|
||||
if (ACTIONS[index].equals(payload.action())) actionIndex = index;
|
||||
}
|
||||
for (int index = 0; index < REWARDS.length; index++) {
|
||||
if (REWARDS[index].equals(payload.rewardType())) rewardIndex = index;
|
||||
}
|
||||
killTargetIndex = QuestRequestService.PLAYER.equals(payload.targetKind()) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
int center = width / 2;
|
||||
alias = addRenderableWidget(new EditBox(font, center - 116, 61, 232, 20,
|
||||
alias = addRenderableWidget(new EditBox(font, center - 152, 48, 304, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.alias")));
|
||||
alias.setMaxLength(QuestRequestService.MAX_ALIAS_LENGTH);
|
||||
alias.setValue(payload.alias());
|
||||
alias.setHint(Component.translatable("screen.sanctuary.quest_request.alias_hint"));
|
||||
|
||||
objective = addRenderableWidget(new EditBox(font, center - 116, 101, 232, 20,
|
||||
objective = addRenderableWidget(new EditBox(font, center - 152, 83, 304, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.objective")));
|
||||
objective.setMaxLength(QuestRequestService.MAX_OBJECTIVE_LENGTH);
|
||||
objective.setValue(payload.objective());
|
||||
@@ -52,24 +66,47 @@ public final class QuestRequestEditorScreen extends Screen {
|
||||
action = addRenderableWidget(Button.builder(actionLabel(), button -> {
|
||||
actionIndex = (actionIndex + 1) % ACTIONS.length;
|
||||
button.setMessage(actionLabel());
|
||||
target.setHint(targetHint());
|
||||
}).bounds(center - 116, 141, 76, 20).build());
|
||||
refreshMissionControls();
|
||||
}).bounds(center - 152, 118, 76, 20).build());
|
||||
|
||||
quantity = addRenderableWidget(new EditBox(font, center - 34, 141, 48, 20,
|
||||
targetKind = addRenderableWidget(Button.builder(targetKindLabel(), button -> {
|
||||
if (!QuestRequestService.KILL.equals(currentAction())) return;
|
||||
killTargetIndex = (killTargetIndex + 1) % 2;
|
||||
refreshMissionControls();
|
||||
}).bounds(center - 72, 118, 70, 20).build());
|
||||
|
||||
quantity = addRenderableWidget(new EditBox(font, center + 2, 118, 46, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.quantity")));
|
||||
quantity.setMaxLength(4);
|
||||
quantity.setValue(Integer.toString(payload.quantity()));
|
||||
|
||||
target = addRenderableWidget(new EditBox(font, center + 20, 141, 96, 20,
|
||||
target = addRenderableWidget(new EditBox(font, center + 52, 118, 100, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.target")));
|
||||
target.setMaxLength(QuestRequestService.MAX_TARGET_LENGTH);
|
||||
target.setValue(payload.target());
|
||||
target.setHint(targetHint());
|
||||
|
||||
reward = addRenderableWidget(Button.builder(rewardLabel(), button -> {
|
||||
rewardIndex = (rewardIndex + 1) % REWARDS.length;
|
||||
button.setMessage(rewardLabel());
|
||||
rewardTarget.setHint(rewardHint());
|
||||
}).bounds(center - 152, 157, 84, 20).build());
|
||||
|
||||
rewardQuantity = addRenderableWidget(new EditBox(font, center - 64, 157, 46, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.reward_quantity")));
|
||||
rewardQuantity.setMaxLength(4);
|
||||
rewardQuantity.setValue(Integer.toString(payload.rewardQuantity()));
|
||||
|
||||
rewardTarget = addRenderableWidget(new EditBox(font, center - 14, 157, 166, 20,
|
||||
Component.translatable("screen.sanctuary.quest_request.reward_target")));
|
||||
rewardTarget.setMaxLength(QuestRequestService.MAX_TARGET_LENGTH);
|
||||
rewardTarget.setValue(payload.rewardTarget());
|
||||
rewardTarget.setHint(rewardHint());
|
||||
|
||||
submit = addRenderableWidget(Button.builder(Component.translatable("screen.sanctuary.quest_request.publish"),
|
||||
button -> submit()).bounds(center - 116, 178, 113, 20).build());
|
||||
button -> submit()).bounds(center - 152, 199, 149, 20).build());
|
||||
addRenderableWidget(Button.builder(Component.translatable("gui.cancel"), button -> onClose())
|
||||
.bounds(center + 3, 178, 113, 20).build());
|
||||
.bounds(center + 3, 199, 149, 20).build());
|
||||
refreshMissionControls();
|
||||
setInitialFocus(alias);
|
||||
}
|
||||
|
||||
@@ -81,38 +118,68 @@ public final class QuestRequestEditorScreen extends Screen {
|
||||
@Override
|
||||
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float tickDelta) {
|
||||
int center = width / 2;
|
||||
graphics.fill(center - 128, 24, center + 128, 210, 0xD0101010);
|
||||
graphics.outline(center - 128, 24, 256, 186, 0xFF4E9B62);
|
||||
graphics.centeredText(font, title, center, 33, 0xFF7BE495);
|
||||
graphics.fill(center - 164, 18, center + 164, 226, 0xD0101010);
|
||||
graphics.outline(center - 164, 18, 328, 208, 0xFFE83E8C);
|
||||
graphics.centeredText(font, title, center, 25, 0xFFFF74B8);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.alias"),
|
||||
center - 116, 50, 0xFFB9B9B9);
|
||||
center - 152, 37, 0xFFDBB7CA);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.objective"),
|
||||
center - 116, 90, 0xFFB9B9B9);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.action"),
|
||||
center - 116, 130, 0xFFB9B9B9);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.quantity"),
|
||||
center - 34, 130, 0xFFB9B9B9);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.target"),
|
||||
center + 20, 130, 0xFFB9B9B9);
|
||||
center - 152, 72, 0xFFDBB7CA);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.mission"),
|
||||
center - 152, 107, 0xFFDBB7CA);
|
||||
graphics.text(font, Component.translatable("screen.sanctuary.quest_request.reward"),
|
||||
center - 152, 146, 0xFFFF74B8);
|
||||
graphics.centeredText(font, Component.translatable("screen.sanctuary.quest_request.help"),
|
||||
center, 164, 0xFF8F8F8F);
|
||||
center, 183, 0xFF9F8B95);
|
||||
super.extractRenderState(graphics, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
|
||||
private void refreshMissionControls() {
|
||||
if (targetKind == null || target == null) return;
|
||||
targetKind.setMessage(targetKindLabel());
|
||||
targetKind.active = QuestRequestService.KILL.equals(currentAction());
|
||||
target.setHint(targetHint());
|
||||
}
|
||||
|
||||
private String currentAction() { return ACTIONS[actionIndex]; }
|
||||
private String currentReward() { return REWARDS[rewardIndex]; }
|
||||
|
||||
private String currentTargetKind() {
|
||||
if (QuestRequestService.BRING.equals(currentAction())) return QuestRequestService.ITEM;
|
||||
if (QuestRequestService.PAY.equals(currentAction())) return QuestRequestService.PLAYER;
|
||||
return killTargetIndex == 1 ? QuestRequestService.PLAYER : QuestRequestService.MOB;
|
||||
}
|
||||
|
||||
private Component actionLabel() {
|
||||
return Component.translatable("screen.sanctuary.quest_request.action." + ACTIONS[actionIndex]);
|
||||
return Component.translatable("screen.sanctuary.quest_request.action." + currentAction());
|
||||
}
|
||||
|
||||
private Component targetKindLabel() {
|
||||
return Component.translatable("screen.sanctuary.quest_request.target_kind." + currentTargetKind());
|
||||
}
|
||||
|
||||
private Component rewardLabel() {
|
||||
return Component.translatable("screen.sanctuary.quest_request.reward_type." + currentReward());
|
||||
}
|
||||
|
||||
private Component targetHint() {
|
||||
return Component.translatable("screen.sanctuary.quest_request.target_hint." + ACTIONS[actionIndex]);
|
||||
return Component.translatable("screen.sanctuary.quest_request.target_hint."
|
||||
+ currentAction() + "." + currentTargetKind());
|
||||
}
|
||||
|
||||
private Component rewardHint() {
|
||||
return Component.translatable("screen.sanctuary.quest_request.reward_hint." + currentReward());
|
||||
}
|
||||
|
||||
private Values values() {
|
||||
if (objective.getValue().isBlank() || target.getValue().isBlank()) return null;
|
||||
if (objective.getValue().isBlank() || target.getValue().isBlank()
|
||||
|| rewardTarget.getValue().isBlank()) return null;
|
||||
try {
|
||||
int amount = Integer.parseInt(quantity.getValue());
|
||||
if (amount < 1 || amount > QuestRequestService.MAX_QUANTITY) return null;
|
||||
return new Values(amount);
|
||||
int rewardAmount = Integer.parseInt(rewardQuantity.getValue());
|
||||
if (amount < 1 || amount > QuestRequestService.MAX_QUANTITY
|
||||
|| rewardAmount < 1 || rewardAmount > QuestRequestService.MAX_QUANTITY) return null;
|
||||
return new Values(amount, rewardAmount);
|
||||
} catch (NumberFormatException exception) {
|
||||
return null;
|
||||
}
|
||||
@@ -122,12 +189,13 @@ public final class QuestRequestEditorScreen extends Screen {
|
||||
Values values = values();
|
||||
if (values == null || !ClientPlayNetworking.canSend(QuestRequestSubmitPayload.ID)) return;
|
||||
ClientPlayNetworking.send(new QuestRequestSubmitPayload(payload.pos(), alias.getValue(),
|
||||
objective.getValue(), ACTIONS[actionIndex], target.getValue(), values.quantity()));
|
||||
objective.getValue(), currentAction(), currentTargetKind(), target.getValue(), values.quantity(),
|
||||
currentReward(), rewardTarget.getValue(), values.rewardQuantity()));
|
||||
onClose();
|
||||
}
|
||||
|
||||
@Override public void onClose() { if (minecraft != null) minecraft.gui.setScreen(parent); }
|
||||
@Override public boolean isPauseScreen() { return false; }
|
||||
|
||||
private record Values(int quantity) {}
|
||||
private record Values(int quantity, int rewardQuantity) {}
|
||||
}
|
||||
|
||||
+11
-1
@@ -8,7 +8,8 @@ import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/** Opens the bounded client editor for one server-owned quest-request sign. */
|
||||
public record QuestRequestEditorPayload(BlockPos pos, String alias, String objective,
|
||||
String action, String target, int quantity) implements CustomPacketPayload {
|
||||
String action, String targetKind, String target, int quantity, String rewardType,
|
||||
String rewardTarget, int rewardQuantity) implements CustomPacketPayload {
|
||||
public static final Type<QuestRequestEditorPayload> ID =
|
||||
new Type<>(SanctuaryMod.id("s2c/quest_request_editor"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, QuestRequestEditorPayload> CODEC =
|
||||
@@ -19,12 +20,17 @@ public record QuestRequestEditorPayload(BlockPos pos, String alias, String objec
|
||||
alias = alias == null ? "" : alias;
|
||||
objective = objective == null ? "" : objective;
|
||||
action = action == null ? "kill" : action;
|
||||
targetKind = targetKind == null ? "mob" : targetKind;
|
||||
target = target == null ? "" : target;
|
||||
quantity = Math.max(1, quantity);
|
||||
rewardType = rewardType == null ? "gift" : rewardType;
|
||||
rewardTarget = rewardTarget == null ? "" : rewardTarget;
|
||||
rewardQuantity = Math.max(1, rewardQuantity);
|
||||
}
|
||||
|
||||
private QuestRequestEditorPayload(RegistryFriendlyByteBuf buffer) {
|
||||
this(buffer.readBlockPos(), buffer.readUtf(32), buffer.readUtf(96), buffer.readUtf(8),
|
||||
buffer.readUtf(8), buffer.readUtf(64), buffer.readVarInt(), buffer.readUtf(8),
|
||||
buffer.readUtf(64), buffer.readVarInt());
|
||||
}
|
||||
|
||||
@@ -33,8 +39,12 @@ public record QuestRequestEditorPayload(BlockPos pos, String alias, String objec
|
||||
buffer.writeUtf(alias, 32);
|
||||
buffer.writeUtf(objective, 96);
|
||||
buffer.writeUtf(action, 8);
|
||||
buffer.writeUtf(targetKind, 8);
|
||||
buffer.writeUtf(target, 64);
|
||||
buffer.writeVarInt(quantity);
|
||||
buffer.writeUtf(rewardType, 8);
|
||||
buffer.writeUtf(rewardTarget, 64);
|
||||
buffer.writeVarInt(rewardQuantity);
|
||||
}
|
||||
|
||||
@Override public Type<? extends CustomPacketPayload> type() { return ID; }
|
||||
|
||||
+7
-1
@@ -8,7 +8,8 @@ import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/** Bounded player-authored quest request; every field is revalidated by the server. */
|
||||
public record QuestRequestSubmitPayload(BlockPos pos, String alias, String objective,
|
||||
String action, String target, int quantity) implements CustomPacketPayload {
|
||||
String action, String targetKind, String target, int quantity, String rewardType,
|
||||
String rewardTarget, int rewardQuantity) implements CustomPacketPayload {
|
||||
public static final Type<QuestRequestSubmitPayload> ID =
|
||||
new Type<>(SanctuaryMod.id("c2s/quest_request_submit"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, QuestRequestSubmitPayload> CODEC =
|
||||
@@ -16,6 +17,7 @@ public record QuestRequestSubmitPayload(BlockPos pos, String alias, String objec
|
||||
|
||||
private QuestRequestSubmitPayload(RegistryFriendlyByteBuf buffer) {
|
||||
this(buffer.readBlockPos(), buffer.readUtf(32), buffer.readUtf(96), buffer.readUtf(8),
|
||||
buffer.readUtf(8), buffer.readUtf(64), buffer.readVarInt(), buffer.readUtf(8),
|
||||
buffer.readUtf(64), buffer.readVarInt());
|
||||
}
|
||||
|
||||
@@ -24,8 +26,12 @@ public record QuestRequestSubmitPayload(BlockPos pos, String alias, String objec
|
||||
buffer.writeUtf(alias == null ? "" : alias, 32);
|
||||
buffer.writeUtf(objective == null ? "" : objective, 96);
|
||||
buffer.writeUtf(action == null ? "" : action, 8);
|
||||
buffer.writeUtf(targetKind == null ? "" : targetKind, 8);
|
||||
buffer.writeUtf(target == null ? "" : target, 64);
|
||||
buffer.writeVarInt(quantity);
|
||||
buffer.writeUtf(rewardType == null ? "" : rewardType, 8);
|
||||
buffer.writeUtf(rewardTarget == null ? "" : rewardTarget, 64);
|
||||
buffer.writeVarInt(rewardQuantity);
|
||||
}
|
||||
|
||||
@Override public Type<? extends CustomPacketPayload> type() { return ID; }
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
* Networking contract for Sanctuary. Payload IDs must use the module namespace.
|
||||
*/
|
||||
public final class SanctuaryNetworking {
|
||||
public static final int PROTOCOL_VERSION = 19;
|
||||
public static final int PROTOCOL_VERSION = 20;
|
||||
private static boolean initialized;
|
||||
|
||||
private SanctuaryNetworking() {
|
||||
|
||||
+2
-2
@@ -131,13 +131,13 @@ public final class SanctuaryRegistries {
|
||||
StandingSignBlock standing = registerBlock(
|
||||
standingId,
|
||||
properties -> new StandingSignBlock(WoodType.OAK, properties),
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN).mapColor(MapColor.COLOR_GREEN)
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN).mapColor(MapColor.COLOR_PINK)
|
||||
.setId(blockKey(standingId))
|
||||
);
|
||||
WallSignBlock wall = registerBlock(
|
||||
wallId,
|
||||
properties -> new WallSignBlock(WoodType.OAK, properties),
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN).mapColor(MapColor.COLOR_GREEN)
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN).mapColor(MapColor.COLOR_PINK)
|
||||
.setId(blockKey(wallId))
|
||||
);
|
||||
ResourceKey<Item> itemKey = ResourceKey.create(Registries.ITEM, standingId);
|
||||
|
||||
+14
-7
@@ -16,7 +16,7 @@ import net.minecraft.world.level.saveddata.SavedDataType;
|
||||
/** Versioned server state for player-authored quest requests attached to physical signs. */
|
||||
public final class QuestRequestData extends SavedData {
|
||||
public static final String SAVE_KEY = "quest_requests";
|
||||
public static final int DATA_VERSION = 1;
|
||||
public static final int DATA_VERSION = 2;
|
||||
|
||||
private static final Codec<Claim> CLAIM_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("player").forGetter(Claim::player),
|
||||
@@ -33,8 +33,12 @@ public final class QuestRequestData extends SavedData {
|
||||
Codec.STRING.optionalFieldOf("alias", "").forGetter(Request::alias),
|
||||
Codec.STRING.optionalFieldOf("objective", "").forGetter(Request::objective),
|
||||
Codec.STRING.optionalFieldOf("action", QuestRequestService.KILL).forGetter(Request::action),
|
||||
Codec.STRING.optionalFieldOf("target_kind", QuestRequestService.MOB).forGetter(Request::targetKind),
|
||||
Codec.STRING.optionalFieldOf("target", "").forGetter(Request::target),
|
||||
Codec.INT.optionalFieldOf("quantity", 1).forGetter(Request::quantity),
|
||||
Codec.STRING.optionalFieldOf("reward_type", QuestRequestService.REWARD_NONE).forGetter(Request::rewardType),
|
||||
Codec.STRING.optionalFieldOf("reward_target", "").forGetter(Request::rewardTarget),
|
||||
Codec.INT.optionalFieldOf("reward_quantity", 0).forGetter(Request::rewardQuantity),
|
||||
Codec.BOOL.optionalFieldOf("configured", false).forGetter(Request::configured),
|
||||
CLAIM_CODEC.optionalFieldOf("claim").forGetter(Request::claim)
|
||||
).apply(instance, Request::new));
|
||||
@@ -112,10 +116,11 @@ public final class QuestRequestData extends SavedData {
|
||||
}
|
||||
|
||||
public record Request(String id, String dimension, long pos, boolean front, String owner,
|
||||
String alias, String objective, String action, String target, int quantity, boolean configured,
|
||||
Optional<Claim> claim) {
|
||||
String alias, String objective, String action, String targetKind, String target, int quantity,
|
||||
String rewardType, String rewardTarget, int rewardQuantity, boolean configured, Optional<Claim> claim) {
|
||||
public Request {
|
||||
quantity = Math.max(1, quantity);
|
||||
rewardQuantity = Math.max(0, rewardQuantity);
|
||||
claim = claim == null ? Optional.empty() : claim;
|
||||
}
|
||||
|
||||
@@ -124,14 +129,16 @@ public final class QuestRequestData extends SavedData {
|
||||
}
|
||||
|
||||
public Request withDetails(String newAlias, String newObjective, String newAction,
|
||||
String newTarget, int newQuantity) {
|
||||
String newTargetKind, String newTarget, int newQuantity, String newRewardType,
|
||||
String newRewardTarget, int newRewardQuantity) {
|
||||
return new Request(id, dimension, pos, front, owner, newAlias, newObjective, newAction,
|
||||
newTarget, newQuantity, true, Optional.empty());
|
||||
newTargetKind, newTarget, newQuantity, newRewardType, newRewardTarget,
|
||||
newRewardQuantity, true, Optional.empty());
|
||||
}
|
||||
|
||||
public Request withClaim(Optional<Claim> newClaim) {
|
||||
return new Request(id, dimension, pos, front, owner, alias, objective, action, target,
|
||||
quantity, configured, newClaim);
|
||||
return new Request(id, dimension, pos, front, owner, alias, objective, action, targetKind,
|
||||
target, quantity, rewardType, rewardTarget, rewardQuantity, configured, newClaim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+149
-37
@@ -1,5 +1,6 @@
|
||||
package fr.koka99cab.sanctuary26.sanctuary.shop;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.QuestRequestEditorPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.QuestRequestSubmitPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.registry.SanctuaryRegistries;
|
||||
@@ -8,14 +9,18 @@ import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -34,11 +39,19 @@ public final class QuestRequestService {
|
||||
public static final String KILL = "kill";
|
||||
public static final String BRING = "bring";
|
||||
public static final String PAY = "pay";
|
||||
public static final String MOB = "mob";
|
||||
public static final String PLAYER = "player";
|
||||
public static final String ITEM = "item";
|
||||
public static final String REWARD_GIFT = "gift";
|
||||
public static final String REWARD_PAYMENT = "payment";
|
||||
public static final String REWARD_LOAN = "loan";
|
||||
public static final String REWARD_NONE = "none";
|
||||
public static final int MAX_ALIAS_LENGTH = 32;
|
||||
public static final int MAX_OBJECTIVE_LENGTH = 96;
|
||||
public static final int MAX_TARGET_LENGTH = 64;
|
||||
public static final int MAX_QUANTITY = 9_999;
|
||||
private static final Set<String> ACTIONS = Set.of(KILL, BRING, PAY);
|
||||
private static final Set<String> REWARD_TYPES = Set.of(REWARD_GIFT, REWARD_PAYMENT, REWARD_LOAN);
|
||||
private static final Set<String> refreshedLayouts = new HashSet<>();
|
||||
private static int tickCounter;
|
||||
private static boolean initialized;
|
||||
@@ -76,6 +89,12 @@ public final class QuestRequestService {
|
||||
data.requestAt(dimension(serverLevel), pos.asLong()).ifPresent(data::remove);
|
||||
});
|
||||
ServerTickEvents.END_SERVER_TICK.register(QuestRequestService::tick);
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) ->
|
||||
dispatcher.register(Commands.literal("sanctuary_quest_accept")
|
||||
.requires(source -> source.getPlayer() != null)
|
||||
.then(Commands.argument("request", StringArgumentType.word())
|
||||
.executes(context -> acceptFromChat(context.getSource().getPlayer(),
|
||||
StringArgumentType.getString(context, "request"))))));
|
||||
}
|
||||
|
||||
/** Creates an owned draft and opens its editor after the custom sign is placed. */
|
||||
@@ -90,8 +109,8 @@ public final class QuestRequestService {
|
||||
}
|
||||
QuestRequestData.Request draft = new QuestRequestData.Request(
|
||||
UUID.randomUUID().toString(), dimension(level), pos.asLong(), sign.isFacingFrontText(player),
|
||||
player.getUUID().toString(), player.getGameProfile().name(), "", KILL, "", 1,
|
||||
false, Optional.empty());
|
||||
player.getUUID().toString(), player.getGameProfile().name(), "", KILL, MOB, "", 1,
|
||||
REWARD_GIFT, "", 1, false, Optional.empty());
|
||||
if (!data.add(draft)) {
|
||||
message(player, "occupied");
|
||||
return;
|
||||
@@ -121,9 +140,9 @@ public final class QuestRequestService {
|
||||
QuestRequestData.Claim claim = request.claim().orElse(null);
|
||||
if (claim == null) {
|
||||
if (request.ownerId().equals(player.getUUID())) {
|
||||
inspect(player, request);
|
||||
inspect(player, request, false);
|
||||
message(player, "owner_cannot_claim");
|
||||
} else claim(player, level, sign, data, request);
|
||||
} else inspect(player, request, true);
|
||||
return InteractionResult.SUCCESS_SERVER;
|
||||
}
|
||||
if (claim.playerId().equals(player.getUUID()) && player.isSecondaryUseActive()) {
|
||||
@@ -134,10 +153,40 @@ public final class QuestRequestService {
|
||||
}
|
||||
return InteractionResult.SUCCESS_SERVER;
|
||||
}
|
||||
inspect(player, request);
|
||||
inspect(player, request, false);
|
||||
return InteractionResult.SUCCESS_SERVER;
|
||||
}
|
||||
|
||||
private static int acceptFromChat(ServerPlayer player, String requestId) {
|
||||
QuestRequestData data = QuestRequestData.get(player.level().getServer());
|
||||
QuestRequestData.Request request = data.request(requestId).orElse(null);
|
||||
if (request == null || !request.configured()) {
|
||||
message(player, "missing");
|
||||
return 0;
|
||||
}
|
||||
if (request.ownerId().equals(player.getUUID())) {
|
||||
message(player, "owner_cannot_claim");
|
||||
return 0;
|
||||
}
|
||||
if (request.claim().isPresent()) {
|
||||
message(player, "already_claimed");
|
||||
return 0;
|
||||
}
|
||||
ServerLevel level = level(player.level().getServer(), request.dimension());
|
||||
BlockPos pos = BlockPos.of(request.pos());
|
||||
if (level == null || player.level() != level || player.blockPosition().distSqr(pos) > 64.0D) {
|
||||
message(player, "too_far");
|
||||
return 0;
|
||||
}
|
||||
if (!SanctuaryRegistries.isQuestRequestSign(level.getBlockState(pos).getBlock())
|
||||
|| !(level.getBlockEntity(pos) instanceof SignBlockEntity sign)) {
|
||||
message(player, "missing");
|
||||
return 0;
|
||||
}
|
||||
claim(player, level, sign, data, request);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void claim(ServerPlayer player, ServerLevel level, SignBlockEntity sign,
|
||||
QuestRequestData data, QuestRequestData.Request request) {
|
||||
QuestRequestData.Claim claim = new QuestRequestData.Claim(player.getUUID().toString(),
|
||||
@@ -151,7 +200,7 @@ public final class QuestRequestService {
|
||||
level.playSound(null, sign.getBlockPos(), SoundEvents.VILLAGER_YES, SoundSource.BLOCKS, 0.7F, 1.1F);
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.claimed",
|
||||
describeAction(claimed.action()), claimed.quantity(), describeTarget(claimed)));
|
||||
inspect(player, claimed);
|
||||
inspect(player, claimed, false);
|
||||
}
|
||||
|
||||
/** Accepts one bounded editor submission after revalidating ownership, distance and targets. */
|
||||
@@ -175,20 +224,27 @@ public final class QuestRequestService {
|
||||
String alias = clean(payload.alias(), MAX_ALIAS_LENGTH);
|
||||
String objective = clean(payload.objective(), MAX_OBJECTIVE_LENGTH);
|
||||
String action = clean(payload.action(), 8).toLowerCase(Locale.ROOT);
|
||||
String targetKind = clean(payload.targetKind(), 8).toLowerCase(Locale.ROOT);
|
||||
String target = clean(payload.target(), MAX_TARGET_LENGTH);
|
||||
String rewardType = clean(payload.rewardType(), 8).toLowerCase(Locale.ROOT);
|
||||
String rewardTarget = clean(payload.rewardTarget(), MAX_TARGET_LENGTH);
|
||||
if (alias.isBlank()) alias = player.getGameProfile().name();
|
||||
if (objective.isBlank() || target.isBlank() || !ACTIONS.contains(action)
|
||||
|| payload.quantity() < 1 || payload.quantity() > MAX_QUANTITY) {
|
||||
if (objective.isBlank() || target.isBlank() || rewardTarget.isBlank()
|
||||
|| !ACTIONS.contains(action) || !REWARD_TYPES.contains(rewardType)
|
||||
|| payload.quantity() < 1 || payload.quantity() > MAX_QUANTITY
|
||||
|| payload.rewardQuantity() < 1 || payload.rewardQuantity() > MAX_QUANTITY) {
|
||||
message(player, "invalid");
|
||||
return;
|
||||
}
|
||||
String canonicalTarget = canonicalTarget(action, target);
|
||||
if (canonicalTarget == null) {
|
||||
String canonicalTarget = canonicalTarget(action, targetKind, target);
|
||||
String canonicalReward = canonicalItem(rewardTarget);
|
||||
if (canonicalTarget == null || canonicalReward == null) {
|
||||
message(player, "invalid_target");
|
||||
return;
|
||||
}
|
||||
QuestRequestData.Request configured = request.withDetails(alias, objective, action,
|
||||
canonicalTarget, payload.quantity());
|
||||
normalizedTargetKind(action, targetKind), canonicalTarget, payload.quantity(), rewardType,
|
||||
canonicalReward, payload.rewardQuantity());
|
||||
if (!data.replace(configured)) {
|
||||
message(player, "missing");
|
||||
return;
|
||||
@@ -197,17 +253,37 @@ public final class QuestRequestService {
|
||||
level.playSound(null, payload.pos(), SoundEvents.AMETHYST_BLOCK_CHIME,
|
||||
SoundSource.BLOCKS, 0.8F, 1.0F);
|
||||
message(player, "created");
|
||||
inspect(player, configured);
|
||||
inspect(player, configured, false);
|
||||
}
|
||||
|
||||
private static String canonicalTarget(String action, String value) {
|
||||
if (PAY.equals(action)) return clean(value, MAX_TARGET_LENGTH);
|
||||
String candidate = value.indexOf(':') < 0 ? "minecraft:" + value.toLowerCase(Locale.ROOT) : value;
|
||||
Identifier id = Identifier.tryParse(candidate.toLowerCase(Locale.ROOT));
|
||||
if (id == null) return null;
|
||||
if (KILL.equals(action) && BuiltInRegistries.ENTITY_TYPE.getOptional(id).isEmpty()) return null;
|
||||
if (BRING.equals(action) && BuiltInRegistries.ITEM.getOptional(id).isEmpty()) return null;
|
||||
return id.toString();
|
||||
private static String canonicalTarget(String action, String targetKind, String value) {
|
||||
if (PAY.equals(action)) return validPlayerName(value) ? value : null;
|
||||
if (KILL.equals(action) && PLAYER.equals(targetKind)) return validPlayerName(value) ? value : null;
|
||||
if (BRING.equals(action)) return ITEM.equals(targetKind) ? canonicalItem(value) : null;
|
||||
if (!KILL.equals(action) || !MOB.equals(targetKind)) return null;
|
||||
String candidate = namespaced(value);
|
||||
Identifier id = Identifier.tryParse(candidate);
|
||||
return id != null && BuiltInRegistries.ENTITY_TYPE.getOptional(id).isPresent() ? id.toString() : null;
|
||||
}
|
||||
|
||||
private static String canonicalItem(String value) {
|
||||
Identifier id = Identifier.tryParse(namespaced(value));
|
||||
return id != null && BuiltInRegistries.ITEM.getOptional(id).isPresent() ? id.toString() : null;
|
||||
}
|
||||
|
||||
private static String namespaced(String value) {
|
||||
String lowered = value.toLowerCase(Locale.ROOT);
|
||||
return lowered.indexOf(':') < 0 ? "minecraft:" + lowered : lowered;
|
||||
}
|
||||
|
||||
private static boolean validPlayerName(String value) {
|
||||
return value.matches("[A-Za-z0-9_]{1,16}");
|
||||
}
|
||||
|
||||
private static String normalizedTargetKind(String action, String targetKind) {
|
||||
if (BRING.equals(action)) return ITEM;
|
||||
if (PAY.equals(action)) return PLAYER;
|
||||
return PLAYER.equals(targetKind) ? PLAYER : MOB;
|
||||
}
|
||||
|
||||
private static void openEditor(ServerPlayer player, QuestRequestData.Request request) {
|
||||
@@ -216,15 +292,38 @@ public final class QuestRequestService {
|
||||
return;
|
||||
}
|
||||
ServerPlayNetworking.send(player, new QuestRequestEditorPayload(BlockPos.of(request.pos()),
|
||||
request.alias(), request.objective(), request.action(), request.target(), request.quantity()));
|
||||
request.alias(), request.objective(), request.action(), request.targetKind(), request.target(),
|
||||
request.quantity(), legacyRewardType(request), request.rewardTarget(),
|
||||
Math.max(1, request.rewardQuantity())));
|
||||
}
|
||||
|
||||
private static void inspect(ServerPlayer player, QuestRequestData.Request request) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.details",
|
||||
request.alias(), describeAction(request.action()), request.quantity(), describeTarget(request),
|
||||
private static String legacyRewardType(QuestRequestData.Request request) {
|
||||
return REWARD_TYPES.contains(request.rewardType()) ? request.rewardType() : REWARD_GIFT;
|
||||
}
|
||||
|
||||
private static void inspect(ServerPlayer player, QuestRequestData.Request request, boolean offerAcceptance) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.details.header",
|
||||
request.alias()).withStyle(ChatFormatting.LIGHT_PURPLE, ChatFormatting.BOLD));
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.details.objective",
|
||||
request.objective()));
|
||||
request.claim().ifPresent(claim -> player.sendSystemMessage(Component.translatable(
|
||||
"message.sanctuary.quest_request.claimed_by", claim.playerName())));
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.details.mission",
|
||||
describeAction(request.action()), request.quantity(), describeTarget(request)));
|
||||
if (REWARD_TYPES.contains(request.rewardType()) && !request.rewardTarget().isBlank()) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.details.reward",
|
||||
describeRewardType(request.rewardType()), request.rewardQuantity(), describeReward(request)));
|
||||
} else player.sendSystemMessage(Component.translatable(
|
||||
"message.sanctuary.quest_request.details.reward_legacy").withStyle(ChatFormatting.GRAY));
|
||||
QuestRequestData.Claim claim = request.claim().orElse(null);
|
||||
if (claim != null) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.claimed_by",
|
||||
claim.playerName()).withStyle(ChatFormatting.GRAY));
|
||||
} else if (offerAcceptance) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.quest_request.accept")
|
||||
.withStyle(style -> style.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true)
|
||||
.withClickEvent(new ClickEvent.RunCommand("/sanctuary_quest_accept " + request.id()))
|
||||
.withHoverEvent(new HoverEvent.ShowText(Component.translatable(
|
||||
"message.sanctuary.quest_request.accept_hover")))));
|
||||
}
|
||||
}
|
||||
|
||||
private static Component describeAction(String action) {
|
||||
@@ -232,7 +331,9 @@ public final class QuestRequestService {
|
||||
}
|
||||
|
||||
private static Component describeTarget(QuestRequestData.Request request) {
|
||||
if (PAY.equals(request.action())) return Component.literal(request.target());
|
||||
if (PAY.equals(request.action()) || PLAYER.equals(request.targetKind())) {
|
||||
return Component.literal(request.target());
|
||||
}
|
||||
Identifier id = Identifier.tryParse(request.target());
|
||||
if (id == null) return Component.literal(request.target());
|
||||
if (KILL.equals(request.action())) return BuiltInRegistries.ENTITY_TYPE.getOptional(id)
|
||||
@@ -241,26 +342,37 @@ public final class QuestRequestService {
|
||||
.map(item -> new ItemStack(item).getHoverName()).orElse(Component.literal(request.target()));
|
||||
}
|
||||
|
||||
private static Component describeRewardType(String rewardType) {
|
||||
return Component.translatable("message.sanctuary.quest_request.reward." + rewardType);
|
||||
}
|
||||
|
||||
private static Component describeReward(QuestRequestData.Request request) {
|
||||
Identifier id = Identifier.tryParse(request.rewardTarget());
|
||||
if (id == null) return Component.literal(request.rewardTarget());
|
||||
return BuiltInRegistries.ITEM.getOptional(id)
|
||||
.map(item -> new ItemStack(item).getHoverName()).orElse(Component.literal(request.rewardTarget()));
|
||||
}
|
||||
|
||||
private static void writeSign(ServerLevel level, SignBlockEntity sign, QuestRequestData.Request request) {
|
||||
SignText text;
|
||||
if (!request.configured()) {
|
||||
text = new SignText()
|
||||
.setMessage(0, Component.translatable("sign.sanctuary.quest_request.title")
|
||||
.withStyle(ChatFormatting.DARK_GREEN, ChatFormatting.BOLD))
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE, ChatFormatting.BOLD))
|
||||
.setMessage(1, Component.translatable("sign.sanctuary.quest_request.configure")
|
||||
.withStyle(ChatFormatting.GRAY));
|
||||
} else {
|
||||
text = new SignText()
|
||||
.setMessage(0, Component.literal(shortText(request.alias(), 24))
|
||||
.withStyle(ChatFormatting.DARK_GREEN, ChatFormatting.BOLD))
|
||||
.setMessage(1, Component.translatable("sign.sanctuary.quest_request.action." + request.action())
|
||||
.append(Component.literal(" ×" + request.quantity())))
|
||||
.setMessage(2, describeTarget(request).copy().withStyle(ChatFormatting.DARK_GRAY));
|
||||
.setMessage(0, Component.translatable("sign.sanctuary.quest_request.title")
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE, ChatFormatting.BOLD))
|
||||
.setMessage(1, Component.literal(shortText(request.alias(), 24))
|
||||
.withStyle(ChatFormatting.DARK_PURPLE));
|
||||
if (request.claim().isPresent()) {
|
||||
QuestRequestData.Claim claim = request.claim().get();
|
||||
text = text.setMessage(3, Component.literal(shortText(claim.playerName(), 24))
|
||||
.withStyle(style -> style.withColor(claim.playerColor())));
|
||||
} else text = text.setMessage(3, Component.translatable("sign.sanctuary.quest_request.available")
|
||||
text = text.setMessage(2, Component.translatable("sign.sanctuary.quest_request.claimed")
|
||||
.withStyle(ChatFormatting.DARK_GRAY));
|
||||
} else text = text.setMessage(2, Component.translatable("sign.sanctuary.quest_request.available")
|
||||
.withStyle(ChatFormatting.DARK_GRAY));
|
||||
text = text.setMessage(3, Component.translatable("sign.sanctuary.quest_request.details")
|
||||
.withStyle(ChatFormatting.GRAY));
|
||||
}
|
||||
sign.setText(text, request.front());
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"variants": {
|
||||
"rotation=0": { "model": "sanctuary:block/emerald_quest_sign_rot_0" },
|
||||
"rotation=1": { "model": "sanctuary:block/emerald_quest_sign_rot_1" },
|
||||
"rotation=2": { "model": "sanctuary:block/emerald_quest_sign_rot_2" },
|
||||
"rotation=3": { "model": "sanctuary:block/emerald_quest_sign_rot_3" },
|
||||
"rotation=4": { "model": "sanctuary:block/emerald_quest_sign_rot_0", "y": 90 },
|
||||
"rotation=5": { "model": "sanctuary:block/emerald_quest_sign_rot_1", "y": 90 },
|
||||
"rotation=6": { "model": "sanctuary:block/emerald_quest_sign_rot_2", "y": 90 },
|
||||
"rotation=7": { "model": "sanctuary:block/emerald_quest_sign_rot_3", "y": 90 },
|
||||
"rotation=8": { "model": "sanctuary:block/emerald_quest_sign_rot_0", "y": 180 },
|
||||
"rotation=9": { "model": "sanctuary:block/emerald_quest_sign_rot_1", "y": 180 },
|
||||
"rotation=10": { "model": "sanctuary:block/emerald_quest_sign_rot_2", "y": 180 },
|
||||
"rotation=11": { "model": "sanctuary:block/emerald_quest_sign_rot_3", "y": 180 },
|
||||
"rotation=12": { "model": "sanctuary:block/emerald_quest_sign_rot_0", "y": 270 },
|
||||
"rotation=13": { "model": "sanctuary:block/emerald_quest_sign_rot_1", "y": 270 },
|
||||
"rotation=14": { "model": "sanctuary:block/emerald_quest_sign_rot_2", "y": 270 },
|
||||
"rotation=15": { "model": "sanctuary:block/emerald_quest_sign_rot_3", "y": 270 }
|
||||
"rotation=0": { "model": "sanctuary:block/quest_request_sign_rot_0" },
|
||||
"rotation=1": { "model": "sanctuary:block/quest_request_sign_rot_1" },
|
||||
"rotation=2": { "model": "sanctuary:block/quest_request_sign_rot_2" },
|
||||
"rotation=3": { "model": "sanctuary:block/quest_request_sign_rot_3" },
|
||||
"rotation=4": { "model": "sanctuary:block/quest_request_sign_rot_0", "y": 90 },
|
||||
"rotation=5": { "model": "sanctuary:block/quest_request_sign_rot_1", "y": 90 },
|
||||
"rotation=6": { "model": "sanctuary:block/quest_request_sign_rot_2", "y": 90 },
|
||||
"rotation=7": { "model": "sanctuary:block/quest_request_sign_rot_3", "y": 90 },
|
||||
"rotation=8": { "model": "sanctuary:block/quest_request_sign_rot_0", "y": 180 },
|
||||
"rotation=9": { "model": "sanctuary:block/quest_request_sign_rot_1", "y": 180 },
|
||||
"rotation=10": { "model": "sanctuary:block/quest_request_sign_rot_2", "y": 180 },
|
||||
"rotation=11": { "model": "sanctuary:block/quest_request_sign_rot_3", "y": 180 },
|
||||
"rotation=12": { "model": "sanctuary:block/quest_request_sign_rot_0", "y": 270 },
|
||||
"rotation=13": { "model": "sanctuary:block/quest_request_sign_rot_1", "y": 270 },
|
||||
"rotation=14": { "model": "sanctuary:block/quest_request_sign_rot_2", "y": 270 },
|
||||
"rotation=15": { "model": "sanctuary:block/quest_request_sign_rot_3", "y": 270 }
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=east": { "model": "sanctuary:block/emerald_quest_wall_sign", "y": 270 },
|
||||
"facing=north": { "model": "sanctuary:block/emerald_quest_wall_sign", "y": 180 },
|
||||
"facing=south": { "model": "sanctuary:block/emerald_quest_wall_sign" },
|
||||
"facing=west": { "model": "sanctuary:block/emerald_quest_wall_sign", "y": 90 }
|
||||
"facing=east": { "model": "sanctuary:block/quest_request_wall_sign", "y": 270 },
|
||||
"facing=north": { "model": "sanctuary:block/quest_request_wall_sign", "y": 180 },
|
||||
"facing=south": { "model": "sanctuary:block/quest_request_wall_sign" },
|
||||
"facing=west": { "model": "sanctuary:block/quest_request_wall_sign", "y": 90 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "sanctuary:item/emerald_quest_sign"
|
||||
"model": "sanctuary:item/quest_request_sign"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,30 @@
|
||||
"screen.sanctuary.quest_request.objective": "Objective",
|
||||
"screen.sanctuary.quest_request.objective_hint": "Briefly describe the request",
|
||||
"screen.sanctuary.quest_request.action": "Type",
|
||||
"screen.sanctuary.quest_request.mission": "Mission: type · target · quantity",
|
||||
"screen.sanctuary.quest_request.action.kill": "KILL",
|
||||
"screen.sanctuary.quest_request.action.bring": "BRING",
|
||||
"screen.sanctuary.quest_request.action.pay": "PAY",
|
||||
"screen.sanctuary.quest_request.quantity": "Quantity",
|
||||
"screen.sanctuary.quest_request.target": "Target",
|
||||
"screen.sanctuary.quest_request.target_hint.kill": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.bring": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay": "Player name",
|
||||
"screen.sanctuary.quest_request.target_kind.mob": "MOB",
|
||||
"screen.sanctuary.quest_request.target_kind.player": "PLAYER",
|
||||
"screen.sanctuary.quest_request.target_kind.item": "ITEM",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.mob": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.player": "Player name to eliminate",
|
||||
"screen.sanctuary.quest_request.target_hint.bring.item": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay.player": "Player name to pay",
|
||||
"screen.sanctuary.quest_request.reward": "Promised reward: form · quantity · item",
|
||||
"screen.sanctuary.quest_request.reward_type.gift": "GIFT",
|
||||
"screen.sanctuary.quest_request.reward_type.payment": "PAYMENT",
|
||||
"screen.sanctuary.quest_request.reward_type.loan": "LOAN",
|
||||
"screen.sanctuary.quest_request.reward_quantity": "Reward quantity",
|
||||
"screen.sanctuary.quest_request.reward_target": "Reward item",
|
||||
"screen.sanctuary.quest_request.reward_hint.gift": "minecraft:diamond",
|
||||
"screen.sanctuary.quest_request.reward_hint.payment": "anotherworld:ruby",
|
||||
"screen.sanctuary.quest_request.reward_hint.loan": "minecraft:elytra",
|
||||
"screen.sanctuary.quest_request.publish": "Publish",
|
||||
"screen.sanctuary.quest_request.help": "Right click: take · Shift + right click: abandon",
|
||||
"screen.sanctuary.quest_request.help": "Right click: details · then accept in chat",
|
||||
"message.sanctuary.black_market.banned": "You are banned from the Black Market.",
|
||||
"message.sanctuary.black_market.protected_sign": "Only the seller or an operator can remove this listing sign.",
|
||||
"message.sanctuary.black_market.modified": "Listing %s updated.",
|
||||
@@ -68,17 +82,27 @@
|
||||
"message.sanctuary.quest_request.already_claimed": "This request was just taken.",
|
||||
"message.sanctuary.quest_request.claimed": "Request taken: %s · %s × %s.",
|
||||
"message.sanctuary.quest_request.details": "%s requests: %s · %s × %s · %s",
|
||||
"message.sanctuary.quest_request.details.header": "— Request from %s —",
|
||||
"message.sanctuary.quest_request.details.objective": "Objective: %s",
|
||||
"message.sanctuary.quest_request.details.mission": "Mission: %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward": "Promised reward: %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward_legacy": "No reward was specified on this legacy request.",
|
||||
"message.sanctuary.quest_request.accept": "[ACCEPT QUEST]",
|
||||
"message.sanctuary.quest_request.accept_hover": "Click to confirm after reading every detail.",
|
||||
"message.sanctuary.quest_request.claimed_by": "Taken by %s.",
|
||||
"message.sanctuary.quest_request.too_far": "You are too far from the request sign.",
|
||||
"message.sanctuary.quest_request.missing": "This request sign no longer exists.",
|
||||
"message.sanctuary.quest_request.not_owner": "Only the requester can edit this available sign.",
|
||||
"message.sanctuary.quest_request.invalid": "The request contains an empty or out-of-range value.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Unknown target: use a valid mob/item ID, or a player name for PAY.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Unknown target: use a valid mob/item ID or a valid player name.",
|
||||
"message.sanctuary.quest_request.client_required": "An up-to-date Sanctuary 26.2 client is required to configure this sign.",
|
||||
"message.sanctuary.quest_request.created": "Quest request published.",
|
||||
"message.sanctuary.quest_request.action.kill": "Kill",
|
||||
"message.sanctuary.quest_request.action.bring": "Bring",
|
||||
"message.sanctuary.quest_request.action.pay": "Pay",
|
||||
"message.sanctuary.quest_request.reward.gift": "Permanent gift",
|
||||
"message.sanctuary.quest_request.reward.payment": "Payment",
|
||||
"message.sanctuary.quest_request.reward.loan": "Loan to be returned",
|
||||
"mod.sanctuary.description": "Owns progression and gives meaning to the adventure.",
|
||||
"screen.sanctuary.atlas": "Atlas",
|
||||
"screen.sanctuary.atlas.chunk_count": "Visited chunks: %s (%s visible)",
|
||||
@@ -397,7 +421,9 @@
|
||||
"sign.sanctuary.quest_request.action.kill": "KILL",
|
||||
"sign.sanctuary.quest_request.action.bring": "BRING",
|
||||
"sign.sanctuary.quest_request.action.pay": "PAY",
|
||||
"sign.sanctuary.quest_request.available": "Right click",
|
||||
"sign.sanctuary.quest_request.available": "AVAILABLE",
|
||||
"sign.sanctuary.quest_request.claimed": "TAKEN",
|
||||
"sign.sanctuary.quest_request.details": "Click: details",
|
||||
"message.sanctuary.companion.active_locked": "Unlock the active companion power in Progression for %s XP levels.",
|
||||
"message.sanctuary.shop.delivery_box_registered": "Mailbox registered at %s, %s, %s.",
|
||||
"message.sanctuary.shop.delivery_box_not_owner": "This Mailbox belongs to another player.",
|
||||
|
||||
@@ -14,16 +14,30 @@
|
||||
"screen.sanctuary.quest_request.objective": "Objectif",
|
||||
"screen.sanctuary.quest_request.objective_hint": "Décris brièvement la demande",
|
||||
"screen.sanctuary.quest_request.action": "Type",
|
||||
"screen.sanctuary.quest_request.mission": "Mission : type · cible · quantité",
|
||||
"screen.sanctuary.quest_request.action.kill": "KILL",
|
||||
"screen.sanctuary.quest_request.action.bring": "BRING",
|
||||
"screen.sanctuary.quest_request.action.pay": "PAY",
|
||||
"screen.sanctuary.quest_request.quantity": "Quantité",
|
||||
"screen.sanctuary.quest_request.target": "Cible",
|
||||
"screen.sanctuary.quest_request.target_hint.kill": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.bring": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay": "Pseudonyme du joueur",
|
||||
"screen.sanctuary.quest_request.target_kind.mob": "MOB",
|
||||
"screen.sanctuary.quest_request.target_kind.player": "JOUEUR",
|
||||
"screen.sanctuary.quest_request.target_kind.item": "ITEM",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.mob": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.player": "Pseudonyme à éliminer",
|
||||
"screen.sanctuary.quest_request.target_hint.bring.item": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay.player": "Pseudonyme à payer",
|
||||
"screen.sanctuary.quest_request.reward": "Récompense promise : forme · quantité · item",
|
||||
"screen.sanctuary.quest_request.reward_type.gift": "DON",
|
||||
"screen.sanctuary.quest_request.reward_type.payment": "PAIEMENT",
|
||||
"screen.sanctuary.quest_request.reward_type.loan": "PRÊT",
|
||||
"screen.sanctuary.quest_request.reward_quantity": "Quantité de la récompense",
|
||||
"screen.sanctuary.quest_request.reward_target": "Item de la récompense",
|
||||
"screen.sanctuary.quest_request.reward_hint.gift": "minecraft:diamond",
|
||||
"screen.sanctuary.quest_request.reward_hint.payment": "anotherworld:ruby",
|
||||
"screen.sanctuary.quest_request.reward_hint.loan": "minecraft:elytra",
|
||||
"screen.sanctuary.quest_request.publish": "Publier",
|
||||
"screen.sanctuary.quest_request.help": "Clic droit : prendre · Maj + clic droit : abandonner",
|
||||
"screen.sanctuary.quest_request.help": "Clic droit : détails · accepter ensuite dans le chat",
|
||||
"message.sanctuary.black_market.banned": "Vous êtes banni du Black Market.",
|
||||
"message.sanctuary.black_market.protected_sign": "Seuls le vendeur et les opérateurs peuvent retirer ce panneau d'annonce.",
|
||||
"message.sanctuary.black_market.modified": "Annonce %s modifiée.",
|
||||
@@ -68,17 +82,27 @@
|
||||
"message.sanctuary.quest_request.already_claimed": "Cette demande vient d'être prise.",
|
||||
"message.sanctuary.quest_request.claimed": "Demande prise : %s · %s × %s.",
|
||||
"message.sanctuary.quest_request.details": "%s demande : %s · %s × %s · %s",
|
||||
"message.sanctuary.quest_request.details.header": "— Demande de %s —",
|
||||
"message.sanctuary.quest_request.details.objective": "Objectif : %s",
|
||||
"message.sanctuary.quest_request.details.mission": "Mission : %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward": "Récompense promise : %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward_legacy": "Aucune récompense indiquée sur cette ancienne demande.",
|
||||
"message.sanctuary.quest_request.accept": "[ACCEPTER LA QUÊTE]",
|
||||
"message.sanctuary.quest_request.accept_hover": "Clique pour confirmer après avoir lu tous les détails.",
|
||||
"message.sanctuary.quest_request.claimed_by": "Prise par %s.",
|
||||
"message.sanctuary.quest_request.too_far": "Tu es trop loin du panneau de demande.",
|
||||
"message.sanctuary.quest_request.missing": "Ce panneau de demande n'existe plus.",
|
||||
"message.sanctuary.quest_request.not_owner": "Seul le demandeur peut modifier ce panneau libre.",
|
||||
"message.sanctuary.quest_request.invalid": "La demande contient une valeur vide ou hors limites.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Cible inconnue : utilise un ID de mob/item valide, ou un pseudonyme pour PAY.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Cible inconnue : utilise un ID de mob/item valide ou un pseudonyme de joueur valide.",
|
||||
"message.sanctuary.quest_request.client_required": "Le client Sanctuary 26.2 à jour est requis pour configurer ce panneau.",
|
||||
"message.sanctuary.quest_request.created": "Demande de quête publiée.",
|
||||
"message.sanctuary.quest_request.action.kill": "Tuer",
|
||||
"message.sanctuary.quest_request.action.bring": "Ramener",
|
||||
"message.sanctuary.quest_request.action.pay": "Payer",
|
||||
"message.sanctuary.quest_request.reward.gift": "Don définitif",
|
||||
"message.sanctuary.quest_request.reward.payment": "Paiement",
|
||||
"message.sanctuary.quest_request.reward.loan": "Prêt à restituer",
|
||||
"mod.sanctuary.description": "Possède la progression et donne un sens à l'aventure.",
|
||||
"screen.sanctuary.atlas": "Atlas",
|
||||
"screen.sanctuary.atlas.chunk_count": "Chunks visités : %s (%s visibles)",
|
||||
@@ -397,7 +421,9 @@
|
||||
"sign.sanctuary.quest_request.action.kill": "TUER",
|
||||
"sign.sanctuary.quest_request.action.bring": "RAMENER",
|
||||
"sign.sanctuary.quest_request.action.pay": "PAYER",
|
||||
"sign.sanctuary.quest_request.available": "Clic droit",
|
||||
"sign.sanctuary.quest_request.available": "DISPONIBLE",
|
||||
"sign.sanctuary.quest_request.claimed": "PRISE",
|
||||
"sign.sanctuary.quest_request.details": "Clic : détails",
|
||||
"message.sanctuary.companion.active_locked": "Débloquez le pouvoir actif du familier dans Progression pour %s niveaux d'XP.",
|
||||
"message.sanctuary.shop.delivery_box_registered": "Boîte aux lettres enregistrée en %s, %s, %s.",
|
||||
"message.sanctuary.shop.delivery_box_not_owner": "Cette boîte aux lettres appartient à un autre joueur.",
|
||||
|
||||
@@ -7,16 +7,30 @@
|
||||
"screen.sanctuary.quest_request.objective": "Цель",
|
||||
"screen.sanctuary.quest_request.objective_hint": "Кратко опишите запрос",
|
||||
"screen.sanctuary.quest_request.action": "Тип",
|
||||
"screen.sanctuary.quest_request.mission": "Задание: тип · цель · количество",
|
||||
"screen.sanctuary.quest_request.action.kill": "УБИТЬ",
|
||||
"screen.sanctuary.quest_request.action.bring": "ПРИНЕСТИ",
|
||||
"screen.sanctuary.quest_request.action.pay": "ЗАПЛАТИТЬ",
|
||||
"screen.sanctuary.quest_request.quantity": "Количество",
|
||||
"screen.sanctuary.quest_request.target": "Цель",
|
||||
"screen.sanctuary.quest_request.target_hint.kill": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.bring": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay": "Имя игрока",
|
||||
"screen.sanctuary.quest_request.target_kind.mob": "МОБ",
|
||||
"screen.sanctuary.quest_request.target_kind.player": "ИГРОК",
|
||||
"screen.sanctuary.quest_request.target_kind.item": "ПРЕДМЕТ",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.mob": "minecraft:zombie",
|
||||
"screen.sanctuary.quest_request.target_hint.kill.player": "Имя игрока-цели",
|
||||
"screen.sanctuary.quest_request.target_hint.bring.item": "minecraft:wheat",
|
||||
"screen.sanctuary.quest_request.target_hint.pay.player": "Имя получателя",
|
||||
"screen.sanctuary.quest_request.reward": "Обещанная награда: вид · количество · предмет",
|
||||
"screen.sanctuary.quest_request.reward_type.gift": "ПОДАРОК",
|
||||
"screen.sanctuary.quest_request.reward_type.payment": "ОПЛАТА",
|
||||
"screen.sanctuary.quest_request.reward_type.loan": "ВЗАЙМЫ",
|
||||
"screen.sanctuary.quest_request.reward_quantity": "Количество награды",
|
||||
"screen.sanctuary.quest_request.reward_target": "Предмет награды",
|
||||
"screen.sanctuary.quest_request.reward_hint.gift": "minecraft:diamond",
|
||||
"screen.sanctuary.quest_request.reward_hint.payment": "anotherworld:ruby",
|
||||
"screen.sanctuary.quest_request.reward_hint.loan": "minecraft:elytra",
|
||||
"screen.sanctuary.quest_request.publish": "Опубликовать",
|
||||
"screen.sanctuary.quest_request.help": "ПКМ: взять · Shift + ПКМ: отказаться",
|
||||
"screen.sanctuary.quest_request.help": "ПКМ: подробности · затем принять в чате",
|
||||
"screen.sanctuary.atlas": "Атлас",
|
||||
"screen.sanctuary.atlas.chunk_count": "Посещённые чанки: %s (видно: %s)",
|
||||
"screen.sanctuary.atlas.marker_count": "Видимые этапы: %s",
|
||||
@@ -334,7 +348,9 @@
|
||||
"sign.sanctuary.quest_request.action.kill": "УБИТЬ",
|
||||
"sign.sanctuary.quest_request.action.bring": "ПРИНЕСТИ",
|
||||
"sign.sanctuary.quest_request.action.pay": "ПЛАТИТЬ",
|
||||
"sign.sanctuary.quest_request.available": "ПКМ",
|
||||
"sign.sanctuary.quest_request.available": "СВОБОДНО",
|
||||
"sign.sanctuary.quest_request.claimed": "ЗАНЯТО",
|
||||
"sign.sanctuary.quest_request.details": "ПКМ: детали",
|
||||
"message.sanctuary.quest_request.occupied": "На этой табличке уже есть запрос.",
|
||||
"message.sanctuary.quest_request.protected": "Только заказчик или оператор может забрать эту табличку.",
|
||||
"message.sanctuary.quest_request.configuring": "Заказчик ещё настраивает это задание.",
|
||||
@@ -343,17 +359,27 @@
|
||||
"message.sanctuary.quest_request.already_claimed": "Этот запрос только что взяли.",
|
||||
"message.sanctuary.quest_request.claimed": "Запрос взят: %s · %s × %s.",
|
||||
"message.sanctuary.quest_request.details": "%s просит: %s · %s × %s · %s",
|
||||
"message.sanctuary.quest_request.details.header": "— Запрос от %s —",
|
||||
"message.sanctuary.quest_request.details.objective": "Цель: %s",
|
||||
"message.sanctuary.quest_request.details.mission": "Задание: %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward": "Обещанная награда: %s · %s × %s",
|
||||
"message.sanctuary.quest_request.details.reward_legacy": "В этом старом запросе награда не указана.",
|
||||
"message.sanctuary.quest_request.accept": "[ПРИНЯТЬ ЗАДАНИЕ]",
|
||||
"message.sanctuary.quest_request.accept_hover": "Нажмите, чтобы подтвердить после чтения всех подробностей.",
|
||||
"message.sanctuary.quest_request.claimed_by": "Взял: %s.",
|
||||
"message.sanctuary.quest_request.too_far": "Вы слишком далеко от таблички запроса.",
|
||||
"message.sanctuary.quest_request.missing": "Этой таблички запроса больше нет.",
|
||||
"message.sanctuary.quest_request.not_owner": "Только заказчик может изменять свободную табличку.",
|
||||
"message.sanctuary.quest_request.invalid": "В запросе есть пустое или недопустимое значение.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Неизвестная цель: укажите ID моба/предмета или имя игрока для PAY.",
|
||||
"message.sanctuary.quest_request.invalid_target": "Неизвестная цель: укажите ID моба/предмета или допустимое имя игрока.",
|
||||
"message.sanctuary.quest_request.client_required": "Для настройки нужен актуальный клиент Sanctuary 26.2.",
|
||||
"message.sanctuary.quest_request.created": "Запрос задания опубликован.",
|
||||
"message.sanctuary.quest_request.action.kill": "Убить",
|
||||
"message.sanctuary.quest_request.action.bring": "Принести",
|
||||
"message.sanctuary.quest_request.action.pay": "Заплатить",
|
||||
"message.sanctuary.quest_request.reward.gift": "Подарок навсегда",
|
||||
"message.sanctuary.quest_request.reward.payment": "Оплата",
|
||||
"message.sanctuary.quest_request.reward.loan": "Взаймы с возвратом",
|
||||
"message.sanctuary.companion.active_locked": "Откройте активную силу спутника в Прогрессе за %s уровней опыта.",
|
||||
"message.sanctuary.shop.delivery_box_registered": "Почтовый ящик зарегистрирован: %s, %s, %s.",
|
||||
"message.sanctuary.shop.delivery_box_not_owner": "Этот почтовый ящик принадлежит другому игроку.",
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:block/template_sign_rot_0",
|
||||
"textures": {
|
||||
"all": "sanctuary:block/pink_quest_request_sign",
|
||||
"particle": "minecraft:block/oak_planks"
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:block/template_sign_rot_1",
|
||||
"textures": {
|
||||
"all": "sanctuary:block/pink_quest_request_sign",
|
||||
"particle": "minecraft:block/oak_planks"
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:block/template_sign_rot_2",
|
||||
"textures": {
|
||||
"all": "sanctuary:block/pink_quest_request_sign",
|
||||
"particle": "minecraft:block/oak_planks"
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:block/template_sign_rot_3",
|
||||
"textures": {
|
||||
"all": "sanctuary:block/pink_quest_request_sign",
|
||||
"particle": "minecraft:block/oak_planks"
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:block/template_wall_sign",
|
||||
"textures": {
|
||||
"all": "sanctuary:block/pink_quest_request_sign",
|
||||
"particle": "minecraft:block/oak_planks"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "sanctuary:item/pink_quest_request_sign"
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 667 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 429 B |
@@ -33,7 +33,7 @@
|
||||
"system_type": "gameplay-system",
|
||||
"namespace": "sanctuary",
|
||||
"data_version": 11,
|
||||
"network_protocol": 19,
|
||||
"network_protocol": 20,
|
||||
"lifecycle": "${lifecycle}",
|
||||
"pack_version": "${pack_version}",
|
||||
"descriptions": {
|
||||
|
||||
+9
-2
@@ -11,14 +11,21 @@ public final class QuestRequestModelSmoke {
|
||||
UUID owner = UUID.fromString("6c43c35a-3498-41bb-a77e-10c679e635d1");
|
||||
UUID claimant = UUID.fromString("8ff11ade-a604-4d77-a770-d487684367a1");
|
||||
QuestRequestData.Request draft = new QuestRequestData.Request("request", "minecraft:overworld",
|
||||
42L, true, owner.toString(), "Koka", "", QuestRequestService.KILL, "", 1,
|
||||
42L, true, owner.toString(), "Koka", "", QuestRequestService.KILL,
|
||||
QuestRequestService.MOB, "", 1, QuestRequestService.REWARD_GIFT, "", 1,
|
||||
false, Optional.empty());
|
||||
QuestRequestData data = new QuestRequestData();
|
||||
require(data.add(draft), "Request draft creation failed");
|
||||
require(!data.add(draft), "Duplicate request position accepted");
|
||||
QuestRequestData.Request configured = draft.withDetails("Koka", "Nettoyer les ruines",
|
||||
QuestRequestService.KILL, "minecraft:zombie", 20);
|
||||
QuestRequestService.KILL, QuestRequestService.PLAYER, "Hunter", 1,
|
||||
QuestRequestService.REWARD_LOAN, "minecraft:elytra", 1);
|
||||
require(data.replace(configured), "Request configuration failed");
|
||||
require(configured.targetKind().equals(QuestRequestService.PLAYER),
|
||||
"Player kill targets must be preserved");
|
||||
require(configured.rewardType().equals(QuestRequestService.REWARD_LOAN)
|
||||
&& configured.rewardTarget().equals("minecraft:elytra"),
|
||||
"Loan rewards must be preserved");
|
||||
QuestRequestData.Claim claim = new QuestRequestData.Claim(claimant.toString(), "Hunter",
|
||||
0x44AAFF, 10L);
|
||||
QuestRequestData.Request claimed = configured.withClaim(Optional.of(claim));
|
||||
|
||||
Reference in New Issue
Block a user