feat(sanctuary): rétablir le Black Market au clic molette (#68) #74
+3
-1
@@ -8,10 +8,12 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
|
||||
|
||||
## Non distribué
|
||||
|
||||
Module modifié : **It's Alive `0.0.0-alpha.36`**. Le pack distribué reste en `26.2.0-alpha.210` jusqu’à la prochaine release.
|
||||
Modules modifiés : **It's Alive `0.0.0-alpha.36`** et **Sanctuary `0.0.0-alpha.119`**. Le pack distribué reste en `26.2.0-alpha.210` jusqu’à la prochaine release.
|
||||
|
||||
- remplace les pages noires du Livre interdit par l’affichage clair du livre vanilla ;
|
||||
- conserve les seize entrées, les découvertes personnelles, le partage sur pupitre, les IDs, les données v3 et le protocole réseau 4.
|
||||
- rétablit l'accès au Black Market par clic molette sur un panneau, avec une intention vide et une nouvelle validation complète de la cible côté serveur ;
|
||||
- conserve les données Sanctuary v11 et porte son protocole réseau de 21 à 22, sans nouvel ID persistant.
|
||||
|
||||
## `26.2.0-alpha.210`
|
||||
|
||||
|
||||
+14
-14
@@ -3429,7 +3429,7 @@ tasks.register("verifyProgressivePauseMenuRelease") {
|
||||
"sanctuary/src/main/resources/assets/sanctuary/lang/${locale}.json"))]
|
||||
}
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.21"
|
||||
|| 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"]
|
||||
@@ -4128,7 +4128,7 @@ tasks.register("verifyShopPricingLayoutRelease") {
|
||||
def index = new JsonSlurper().parse(file("pack/prism/modrinth.index.json"))
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.21"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| 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"
|
||||
@@ -4222,7 +4222,7 @@ tasks.register("verifyShopCsvBossGatesRelease") {
|
||||
def offerCatalog = file("sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.onlyfun_version != "0.0.0-alpha.21"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| 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"]
|
||||
@@ -4314,7 +4314,7 @@ tasks.register("verifyQuestRequestsCauldronBatchesRelease") {
|
||||
def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json"))
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| 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"]
|
||||
@@ -4331,7 +4331,7 @@ 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 != 21
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 22
|
||||
|| release.pack_version != "26.2.0-alpha.210"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.210.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.210"
|
||||
@@ -4414,7 +4414,7 @@ tasks.register("verifyQuestRequestContractsRelease") {
|
||||
def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json"))
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| 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"
|
||||
@@ -4425,7 +4425,7 @@ tasks.register("verifyQuestRequestContractsRelease") {
|
||||
|| 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 != 21
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 22
|
||||
|| release.pack_version != "26.2.0-alpha.210"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.210.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.210"
|
||||
@@ -4534,7 +4534,7 @@ tasks.register("verifyQuestRequestEscrowRelease") {
|
||||
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.210"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.200"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.115"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.201"
|
||||
@@ -4547,7 +4547,7 @@ tasks.register("verifyQuestRequestEscrowRelease") {
|
||||
|| migration.quest_request_escrow?.reward_delivery_to_claimant_mailbox != true
|
||||
|| migration.compatibility?.sanctuary_target_network_protocol != 21
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.data_version != 11
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 21
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 22
|
||||
|| release.pack_version != "26.2.0-alpha.210"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.210.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.210"
|
||||
@@ -4591,7 +4591,7 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") {
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
|| rootProject.iliketomoveit_version != "0.0.0-alpha.15"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.201"
|
||||
|| migration.source?.modules != [
|
||||
itsalive: "0.0.0-alpha.30",
|
||||
@@ -4626,7 +4626,7 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") {
|
||||
|| moveItManifest.custom?.sanctuary26?.data_version != 3
|
||||
|| moveItManifest.custom?.sanctuary26?.network_protocol != 5
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.data_version != 11
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 21
|
||||
|| sanctuaryManifest.custom?.sanctuary26?.network_protocol != 22
|
||||
|| release.pack_version != "26.2.0-alpha.210"
|
||||
|| release.modrinth?.primary_file != "sanctuary-26.2.0-alpha.210.mrpack"
|
||||
|| prism.versionId != "26.2.0-alpha.210"
|
||||
@@ -4749,7 +4749,7 @@ tasks.register("verifySafeVaultFeature") {
|
||||
}.keySet()
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.118"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| migration.schema_version != 1
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.201"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.202"
|
||||
@@ -5597,7 +5597,7 @@ tasks.register("verifyAlpha210Release") {
|
||||
it.path == "mods/jei-26.2-fabric-30.28.0.193.jar"
|
||||
}
|
||||
if (rootProject.pack_version != "26.2.0-alpha.210"
|
||||
|| rootProject.sanctuary_version != expectedTarget.sanctuary
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.119"
|
||||
|| rootProject.onlyfun_version != expectedTarget.onlyfun
|
||||
|| rootProject.iliketomoveit_version != expectedTarget.iliketomoveit
|
||||
|| rootProject.itsalive_version != "0.0.0-alpha.36"
|
||||
@@ -5635,7 +5635,7 @@ tasks.register("verifyAlpha210Release") {
|
||||
|| migration.distribution?.jei?.modrinth_version_id != "qaCQ7LGO"
|
||||
|| migration.distribution?.jei?.packwiz_and_prism_synchronized != true
|
||||
|| manifests.sanctuary.custom?.sanctuary26?.data_version != 11
|
||||
|| manifests.sanctuary.custom?.sanctuary26?.network_protocol != 21
|
||||
|| manifests.sanctuary.custom?.sanctuary26?.network_protocol != 22
|
||||
|| manifests.onlyfun.custom?.sanctuary26?.data_version != 2
|
||||
|| manifests.onlyfun.custom?.sanctuary26?.network_protocol != 2
|
||||
|| manifests.iliketomoveit.custom?.sanctuary26?.data_version != 3
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ iliketomoveit_version=0.0.0-alpha.15
|
||||
iliketomoveit_lifecycle=active
|
||||
onlyfun_version=0.0.0-alpha.21
|
||||
onlyfun_lifecycle=active
|
||||
sanctuary_version=0.0.0-alpha.118
|
||||
sanctuary_version=0.0.0-alpha.119
|
||||
sanctuary_lifecycle=active
|
||||
pack_version=26.2.0-alpha.210
|
||||
maven_group=fr.koka99cab.sanctuary26
|
||||
|
||||
@@ -9,18 +9,23 @@ n'importe aucune donnée du Shop.
|
||||
## Utilisation
|
||||
|
||||
1. Le vendeur pose une Mailbox dans sa dimension et reste dans un rayon de 256 blocs.
|
||||
2. Il tient le stack à vendre, s'accroupit et fait clic droit sur un panneau libre.
|
||||
2. Il tient le stack à vendre et fait un clic molette sur un panneau libre. L'ancien
|
||||
raccourci accroupi + clic droit reste accepté pour les habitudes existantes.
|
||||
3. L'éditeur du panneau choisit quantité, prix libre et devise (`ruby` ou `sapphire`).
|
||||
4. Un clic droit du vendeur rouvre l'éditeur. Il peut modifier prix, devise et quantité.
|
||||
4. Un clic molette du vendeur rouvre l'éditeur. Il peut modifier prix, devise et quantité.
|
||||
Pour augmenter la quantité, il doit tenir des objets aux composants strictement
|
||||
identiques. La diminution retourne par colis. Shift + clic droit annule l'annonce.
|
||||
5. Un autre joueur fait clic droit pour acheter. Paiement, retrait de l'annonce,
|
||||
5. Un autre joueur fait clic molette pour acheter. Paiement, retrait de l'annonce,
|
||||
séquestre et création des colis s'exécutent atomiquement sur le thread serveur.
|
||||
|
||||
Le panneau affiche l'objet, le prix et le pseudonyme coloré du vendeur. Il est protégé :
|
||||
seuls le vendeur et un opérateur peuvent le casser. Il n'existe aucune limite arbitraire
|
||||
d'annonces et aucune expiration tant que le panneau existe.
|
||||
|
||||
Le clic molette remplace uniquement l'action vanilla « choisir le bloc » lorsque la cible
|
||||
est un panneau. Le client n'envoie ni position, ni objet, ni prix : le serveur refait son
|
||||
propre rayon, vérifie la portée et résout le panneau avant toute opération.
|
||||
|
||||
## Économie et livraison
|
||||
|
||||
- Mise en vente : 1 rubis versé à la trésorerie serveur.
|
||||
|
||||
+41
-15
@@ -92,7 +92,12 @@ tasks.register("verifyBlackMarket") {
|
||||
inputs.file(file("BLACK_MARKET.md"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketData.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketInteractionRules.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketItemPolicy.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/MinecraftMixin.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/BlackMarketInteractPayload.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/SanctuaryNetworking.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java"))
|
||||
inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java"))
|
||||
@@ -102,15 +107,36 @@ tasks.register("verifyBlackMarket") {
|
||||
doLast {
|
||||
def data = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketData.java").text
|
||||
def service = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java").text
|
||||
def interactionRules = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketInteractionRules.java").text
|
||||
def policy = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketItemPolicy.java").text
|
||||
def client = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java").text
|
||||
def minecraftMixin = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/MinecraftMixin.java").text
|
||||
def middleClickPayload = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/BlackMarketInteractPayload.java").text
|
||||
def network = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/network/SanctuaryNetworking.java").text
|
||||
def shop = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java").text
|
||||
def questData = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java").text
|
||||
def quests = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardService.java").text
|
||||
def inventoryView = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java").text
|
||||
if (!data.contains('SAVE_KEY = "black_market"') || !data.contains("DATA_VERSION = 2")
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| !data.contains('SAVE_KEY = "black_market"') || !data.contains("DATA_VERSION = 2")
|
||||
|| !data.contains("ItemStack.CODEC.fieldOf(\"item\")") || !data.contains("replaceListing")
|
||||
|| !service.contains("LISTING_FEE_RUBIES = 1") || !service.contains("COMMISSION_PERCENT = 5")
|
||||
|| !service.contains("PlayerBlockBreakEvents.BEFORE") || !service.contains('"modify"')
|
||||
|| !service.contains("public static void middleClick(ServerPlayer player)")
|
||||
|| !service.contains("player.pick(")
|
||||
|| !service.contains("player.blockInteractionRange() + 1.0D")
|
||||
|| !interactionRules.contains("middleClick || secondaryUse")
|
||||
|| !client.contains("handleBlackMarketMiddleClick")
|
||||
|| !client.contains("ClientPlayNetworking.send(new BlackMarketInteractPayload())")
|
||||
|| !minecraftMixin.contains('method = "pickBlock"')
|
||||
|| !middleClickPayload.contains('SanctuaryMod.id("c2s/black_market_interact")')
|
||||
|| !middleClickPayload.contains("No client position, listing ID, item or price is trusted")
|
||||
|| !network.contains("PROTOCOL_VERSION = 22")
|
||||
|| !network.contains("BlackMarketService.middleClick(context.player())")
|
||||
|| !service.contains("loadedDeliveryBox") || !service.contains("PARCEL_RETENTION_MILLIS")
|
||||
|| !policy.contains("DataComponents.CONTAINER") || !policy.contains("DataComponents.BUNDLE_CONTENTS")
|
||||
|| !shop.contains("public static final boolean OPEN = true")
|
||||
@@ -1086,12 +1112,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 != 21
|
||||
|| manifest.custom?.sanctuary26?.network_protocol != 22
|
||||
|| 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 21, JEI and the client entrypoint")
|
||||
throw new GradleException("Sanctuary must expose data v11, protocol 22, 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"))
|
||||
@@ -2792,7 +2818,7 @@ tasks.register("verifyShopCurrencyRowsRelease") {
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java").text
|
||||
def shop = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.117"
|
||||
|| migration.shop_currency_inventory?.all_unlocked_rows_counted != true
|
||||
|| migration.shop_currency_inventory?.overflow_rows_counted != true
|
||||
@@ -2958,7 +2984,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| 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
|
||||
@@ -2996,7 +3022,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| 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]
|
||||
@@ -3027,7 +3053,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.195"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.111"
|
||||
|| migration.compatibility?.sanctuary_data_version != 11
|
||||
@@ -3058,7 +3084,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.112"
|
||||
|| migration.mailbox?.id != "sanctuary:delivery_box"
|
||||
|| migration.mailbox?.horizontal_facing != true
|
||||
@@ -3086,7 +3112,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| !transfer.contains("shouldAppendOverflow")
|
||||
|| !transfer.contains("isVanillaStorageRange")
|
||||
|| !transfer.contains("hotbarStart")
|
||||
@@ -3132,7 +3158,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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.113"
|
||||
|| migration.quest_requests?.save_key != "quest_requests"
|
||||
|| migration.quest_requests?.data_version != 1
|
||||
@@ -3144,7 +3170,7 @@ tasks.register("verifyQuestRequests") {
|
||||
|| !data.contains('SAVE_KEY = "quest_requests"') || !data.contains("DATA_VERSION = 3")
|
||||
|| !service.contains("PlayerBlockBreakEvents.BEFORE")
|
||||
|| !service.contains("player.blockPosition().distSqr(payload.pos()) > 64.0D")
|
||||
|| !network.contains("PROTOCOL_VERSION = 21")
|
||||
|| !network.contains("PROTOCOL_VERSION = 22")
|
||||
|| !network.contains("QuestRequestSubmitPayload.ID")
|
||||
|| !network.contains("QuestRequestAcceptPayload.ID")
|
||||
|| !registry.contains('SanctuaryMod.id("quest_request_sign")')
|
||||
@@ -3190,7 +3216,7 @@ tasks.register("verifyQuestRequestContracts") {
|
||||
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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| 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"
|
||||
@@ -3210,7 +3236,7 @@ tasks.register("verifyQuestRequestContracts") {
|
||||
|| !service.contains('REWARD_LOAN = "loan"')
|
||||
|| !service.contains('PLAYER.equals(targetKind)')
|
||||
|| !screen.contains("rewardQuantity") || !screen.contains("killTargetIndex")
|
||||
|| !network.contains("PROTOCOL_VERSION = 21")
|
||||
|| !network.contains("PROTOCOL_VERSION = 22")
|
||||
|| 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
|
||||
@@ -3259,7 +3285,7 @@ tasks.register("verifyQuestRequestEscrow") {
|
||||
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.118"
|
||||
if (project.version.toString() != "0.0.0-alpha.119"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.200"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.115"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.201"
|
||||
@@ -3280,7 +3306,7 @@ tasks.register("verifyQuestRequestEscrow") {
|
||||
|| !service.contains('"quest_request_reward"')
|
||||
|| !service.contains('"quest_request_delivery"')
|
||||
|| service.contains("sanctuary_quest_accept")
|
||||
|| !network.contains("PROTOCOL_VERSION = 21")
|
||||
|| !network.contains("PROTOCOL_VERSION = 22")
|
||||
|| !network.contains("QuestRequestAcceptPayload.ID")
|
||||
|| !network.contains("QuestRequestConfirmPayload.ID")
|
||||
|| !acceptPayload.contains("readUtf(36)")
|
||||
|
||||
+12
@@ -11,6 +11,7 @@ import fr.koka99cab.sanctuary26.sanctuary.network.CelestialSkySnapshotPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.ShopSnapshotPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.CapeSyncPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.BlackMarketEditorPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.BlackMarketInteractPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.QuestRequestEditorPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.network.QuestRequestConfirmPayload;
|
||||
import fr.koka99cab.sanctuary26.sanctuary.progression.SanctuaryProgressionCosts;
|
||||
@@ -34,6 +35,8 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.CraftingMenu;
|
||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public final class SanctuaryClient implements ClientModInitializer {
|
||||
@@ -202,6 +205,15 @@ public final class SanctuaryClient implements ClientModInitializer {
|
||||
return switchHotbarRowKey != null && switchHotbarRowKey.matches(event);
|
||||
}
|
||||
|
||||
public static boolean handleBlackMarketMiddleClick(Minecraft client) {
|
||||
if (client.player == null || client.level == null || client.gui.screen() != null
|
||||
|| !(client.hitResult instanceof BlockHitResult hit)
|
||||
|| !(client.level.getBlockEntity(hit.getBlockPos()) instanceof SignBlockEntity)
|
||||
|| !ClientPlayNetworking.canSend(BlackMarketInteractPayload.ID)) return false;
|
||||
ClientPlayNetworking.send(new BlackMarketInteractPayload());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void openInventorySmokeScreen(Minecraft client) {
|
||||
inventorySmokeScreenOpened = true;
|
||||
inventorySmokeOpenDelay = -1;
|
||||
|
||||
+7
@@ -1,14 +1,21 @@
|
||||
package fr.koka99cab.sanctuary26.sanctuary.mixin.client;
|
||||
|
||||
import fr.koka99cab.sanctuary26.sanctuary.client.SanctuaryClient;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/** Gives the game window the Sanctuary identity while preserving its connection suffix. */
|
||||
@Mixin(Minecraft.class)
|
||||
public abstract class MinecraftMixin {
|
||||
@Inject(method = "pickBlock", at = @At("HEAD"), cancellable = true)
|
||||
private void sanctuary$blackMarketMiddleClick(CallbackInfo callback) {
|
||||
if (SanctuaryClient.handleBlackMarketMiddleClick((Minecraft) (Object) this)) callback.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "createTitle", at = @At("RETURN"), cancellable = true)
|
||||
private void sanctuary$replaceMinecraftWindowTitle(CallbackInfoReturnable<String> callback) {
|
||||
callback.setReturnValue(callback.getReturnValue().replaceFirst("^Minecraft\\*?", "Sanctuary"));
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package fr.koka99cab.sanctuary26.sanctuary.network;
|
||||
|
||||
import fr.koka99cab.sanctuary26.sanctuary.SanctuaryMod;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/** Empty middle-click intent; the server resolves and validates the targeted sign. */
|
||||
public record BlackMarketInteractPayload() implements CustomPacketPayload {
|
||||
public static final Type<BlackMarketInteractPayload> ID =
|
||||
new Type<>(SanctuaryMod.id("c2s/black_market_interact"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, BlackMarketInteractPayload> CODEC =
|
||||
CustomPacketPayload.codec(BlackMarketInteractPayload::write, BlackMarketInteractPayload::new);
|
||||
|
||||
private BlackMarketInteractPayload(RegistryFriendlyByteBuf buffer) {
|
||||
this();
|
||||
}
|
||||
|
||||
private void write(RegistryFriendlyByteBuf buffer) {
|
||||
// No client position, listing ID, item or price is trusted.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
+4
-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 = 21;
|
||||
public static final int PROTOCOL_VERSION = 22;
|
||||
private static boolean initialized;
|
||||
|
||||
private SanctuaryNetworking() {
|
||||
@@ -53,6 +53,7 @@ public final class SanctuaryNetworking {
|
||||
PayloadTypeRegistry.serverboundPlay().register(ShopRequestPayload.ID, ShopRequestPayload.CODEC);
|
||||
PayloadTypeRegistry.serverboundPlay().register(ShopActionPayload.ID, ShopActionPayload.CODEC);
|
||||
PayloadTypeRegistry.serverboundPlay().register(BlackMarketCreatePayload.ID, BlackMarketCreatePayload.CODEC);
|
||||
PayloadTypeRegistry.serverboundPlay().register(BlackMarketInteractPayload.ID, BlackMarketInteractPayload.CODEC);
|
||||
PayloadTypeRegistry.serverboundPlay().register(QuestRequestSubmitPayload.ID, QuestRequestSubmitPayload.CODEC);
|
||||
PayloadTypeRegistry.serverboundPlay().register(QuestRequestAcceptPayload.ID, QuestRequestAcceptPayload.CODEC);
|
||||
ServerPlayNetworking.registerGlobalReceiver(PurchaseProgressionPayload.ID, (payload, context) ->
|
||||
@@ -83,6 +84,8 @@ public final class SanctuaryNetworking {
|
||||
context.server().execute(() -> ShopService.handle(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(BlackMarketCreatePayload.ID, (payload, context) ->
|
||||
context.server().execute(() -> BlackMarketService.create(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(BlackMarketInteractPayload.ID, (payload, context) ->
|
||||
context.server().execute(() -> BlackMarketService.middleClick(context.player())));
|
||||
ServerPlayNetworking.registerGlobalReceiver(QuestRequestSubmitPayload.ID, (payload, context) ->
|
||||
context.server().execute(() -> QuestRequestService.submit(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(QuestRequestAcceptPayload.ID, (payload, context) ->
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package fr.koka99cab.sanctuary26.sanctuary.shop;
|
||||
|
||||
/** Pure interaction gates shared by the server implementation and smoke tests. */
|
||||
final class BlackMarketInteractionRules {
|
||||
private BlackMarketInteractionRules() {
|
||||
}
|
||||
|
||||
static boolean acceptsMiddleClick(boolean alive, boolean spectator,
|
||||
boolean targetsSign, boolean mayInteract) {
|
||||
return alive && !spectator && targetsSign && mayInteract;
|
||||
}
|
||||
|
||||
static boolean opensBlankListing(boolean middleClick, boolean secondaryUse, boolean heldItem) {
|
||||
return heldItem && (middleClick || secondaryUse);
|
||||
}
|
||||
}
|
||||
+18
-3
@@ -75,7 +75,7 @@ public final class BlackMarketService {
|
||||
? InteractionResult.SUCCESS : InteractionResult.PASS;
|
||||
}
|
||||
return player instanceof ServerPlayer serverPlayer
|
||||
? interact(serverPlayer, (ServerLevel) level, hit.getBlockPos(), sign)
|
||||
? interact(serverPlayer, (ServerLevel) level, hit.getBlockPos(), sign, false)
|
||||
: InteractionResult.PASS;
|
||||
});
|
||||
PlayerBlockBreakEvents.BEFORE.register((level, player, pos, state, blockEntity) -> {
|
||||
@@ -101,8 +101,22 @@ public final class BlackMarketService {
|
||||
BlackMarketCommands.register(dispatcher));
|
||||
}
|
||||
|
||||
public static void middleClick(ServerPlayer player) {
|
||||
net.minecraft.world.phys.HitResult hit = player.pick(
|
||||
player.blockInteractionRange() + 1.0D, 1.0F, false);
|
||||
boolean targetsSign = hit instanceof net.minecraft.world.phys.BlockHitResult blockHit
|
||||
&& player.level().getBlockEntity(blockHit.getBlockPos()) instanceof SignBlockEntity;
|
||||
BlockPos pos = targetsSign
|
||||
? ((net.minecraft.world.phys.BlockHitResult) hit).getBlockPos() : BlockPos.ZERO;
|
||||
boolean mayInteract = targetsSign && player.level().mayInteract(player, pos);
|
||||
if (!BlackMarketInteractionRules.acceptsMiddleClick(
|
||||
player.isAlive(), player.isSpectator(), targetsSign, mayInteract)) return;
|
||||
SignBlockEntity sign = (SignBlockEntity) player.level().getBlockEntity(pos);
|
||||
interact(player, (ServerLevel) player.level(), pos, sign, true);
|
||||
}
|
||||
|
||||
private static InteractionResult interact(ServerPlayer player, ServerLevel level, BlockPos pos,
|
||||
SignBlockEntity sign) {
|
||||
SignBlockEntity sign, boolean middleClick) {
|
||||
BlackMarketData data = BlackMarketData.get(level.getServer());
|
||||
Optional<BlackMarketData.Listing> existing = data.listingAt(dimension(level), pos.asLong());
|
||||
if (existing.isPresent()) {
|
||||
@@ -115,7 +129,8 @@ public final class BlackMarketService {
|
||||
}
|
||||
return InteractionResult.SUCCESS_SERVER;
|
||||
}
|
||||
if (!player.isSecondaryUseActive() || player.getMainHandItem().isEmpty()) return InteractionResult.PASS;
|
||||
if (!BlackMarketInteractionRules.opensBlankListing(middleClick,
|
||||
player.isSecondaryUseActive(), !player.getMainHandItem().isEmpty())) return InteractionResult.PASS;
|
||||
if (data.isBanned(player.getUUID())) {
|
||||
player.sendSystemMessage(Component.translatable("message.sanctuary.black_market.banned"));
|
||||
return InteractionResult.CONSUME;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"system_type": "gameplay-system",
|
||||
"namespace": "sanctuary",
|
||||
"data_version": 11,
|
||||
"network_protocol": 21,
|
||||
"network_protocol": 22,
|
||||
"lifecycle": "${lifecycle}",
|
||||
"pack_version": "${pack_version}",
|
||||
"descriptions": {
|
||||
|
||||
+13
@@ -8,6 +8,19 @@ public final class BlackMarketModelSmoke {
|
||||
private BlackMarketModelSmoke() {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
require(BlackMarketInteractionRules.acceptsMiddleClick(true, false, true, true),
|
||||
"A valid middle-click sign target was rejected");
|
||||
require(!BlackMarketInteractionRules.acceptsMiddleClick(false, false, true, true),
|
||||
"A dead player may middle-click the Black Market");
|
||||
require(!BlackMarketInteractionRules.acceptsMiddleClick(true, true, true, true),
|
||||
"A spectator may middle-click the Black Market");
|
||||
require(!BlackMarketInteractionRules.acceptsMiddleClick(true, false, false, true),
|
||||
"A non-sign target may open the Black Market");
|
||||
require(BlackMarketInteractionRules.opensBlankListing(true, false, true),
|
||||
"Middle-click should create a listing without crouching");
|
||||
require(!BlackMarketInteractionRules.opensBlankListing(true, false, false),
|
||||
"An empty hand should not create a listing");
|
||||
|
||||
UUID seller = UUID.fromString("6c43c35a-3498-41bb-a77e-10c679e635d1");
|
||||
ItemStack escrow = ItemStack.EMPTY;
|
||||
BlackMarketData data = new BlackMarketData();
|
||||
|
||||
Reference in New Issue
Block a user