diff --git a/PALAMOD_CDC.md b/PALAMOD_CDC.md index 652777e..7cc1a6f 100644 --- a/PALAMOD_CDC.md +++ b/PALAMOD_CDC.md @@ -680,6 +680,9 @@ avant M4 (TODO:crafts-machines). dereferenced"). VERIFIE : build SUCCESSFUL, boot Done (0.381s), 0 ERROR/Exception au log, jar md5 identique build/libs = server/mods = HEAD. UNVERIFIED en jeu (2 joueurs : vente->achat->taxe). +- M-market-2 LIVRE 2026-10-19 ~06:20 : expiration annonces (createdAt, marketExpiryDays + =7 persistee VERIFIEE, purge au flush, rendu si vendeur connecte). TODO:market-expiry + CLOS. VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED en jeu (purge 7j). - M-palaforge LIVRE 2026-10-19 ~03:55 : bloc + BE partagee (3e mode) + gate mineur 14 + table fonte wiki §3.2 (31 items, ratio floor usure) + fuels bois (+buche/planches/baton, lave exclue : seau non rendu) + craft (1 findium + 4 furnaces + 4 briques, positions diff --git a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaConfig.java b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaConfig.java index 8a76ac8..c911c20 100644 --- a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaConfig.java +++ b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaConfig.java @@ -88,6 +88,9 @@ public final class PalaConfig { // M-faction-2 : claims de chunks (quota par faction, defaut 10, UNVERIFIED). public int factionMaxClaims = 10; + // M-market-2 (wiki §3.8) : expiration des annonces en jours (defaut 7). + public int marketExpiryDays = 7; + // M-rtp (wiki commandes) : cooldown minutes entre deux /rtp (wiki : 15). public int rtpCooldownMinutes = 15; // Rayon max du /rtp autour du spawn (blocs). UNVERIFIED (wiki : "aleatoire", sans borne). @@ -238,7 +241,7 @@ public final class PalaConfig { "furnaceSmelts", "furnaceFuels", "serverName", "wikiUrl", "discordUrl", "shopUrl", "afkKickMinutes", "rtpCooldownMinutes", "rtpRadius", - "factionMaxClaims"); + "factionMaxClaims", "marketExpiryDays"); boolean complete = true; try (Reader keysReader = Files.newBufferedReader(path)) { com.google.gson.JsonObject obj = diff --git a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaCore.java b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaCore.java index 8643045..38885ec 100644 --- a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaCore.java +++ b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaCore.java @@ -28,6 +28,10 @@ public final class PalaCore { tickCounter = 0; PalaStorage.get().saveIfDirty(); PalaFactions.get().saveIfDirty(); + // M-market-2 (wiki §3.8) : purge des annonces expirees au flush. + PalaMarket.setServer(server); + PalaMarket.get().purgeExpired( + (long) PalaConfig.get().marketExpiryDays * 86400000L); PalaMarket.get().saveIfDirty(); } }); diff --git a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaMarket.java b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaMarket.java index 3395366..7d461a2 100644 --- a/mods/pala/src/main/java/fr/surviepote/pala/core/PalaMarket.java +++ b/mods/pala/src/main/java/fr/surviepote/pala/core/PalaMarket.java @@ -31,6 +31,8 @@ public final class PalaMarket { public String itemId = ""; public int count = 1; public double price = 0.0; + // M-market-2 (wiki §3.8) : expiration 7 j (epoch ms, 0 = a initialiser au load). + public long createdAt = 0L; } private final Map listings = new HashMap<>(); @@ -59,6 +61,7 @@ public final class PalaMarket { listing.itemId = itemId; listing.count = count; listing.price = price; + listing.createdAt = System.currentTimeMillis(); listings.put(listing.id, listing); dirty = true; return listing; @@ -86,6 +89,56 @@ public final class PalaMarket { dirty = true; } + // M-market-2 : purge les annonces expirees (vendues rendues si vendeur connecte, + // sinon supprimees). Appele par PalaCore au flush (set server chaque tick flush). + private static net.minecraft.server.MinecraftServer serverRef = null; + + public static void setServer(net.minecraft.server.MinecraftServer server) { + serverRef = server; + } + + public void purgeExpired(long expiryMs) { + long now = System.currentTimeMillis(); + java.util.List gone = new java.util.ArrayList<>(); + for (Listing listing : listings.values()) { + if (now - listing.createdAt > expiryMs) { + gone.add(listing.id); + } + } + for (int id : gone) { + Listing listing = listings.remove(id); + if (listing == null) { + continue; + } + dirty = true; + if (serverRef != null) { + try { + net.minecraft.server.level.ServerPlayer seller = serverRef.getPlayerList() + .getPlayer(java.util.UUID.fromString(listing.sellerUuid)); + if (seller != null) { + net.minecraft.world.item.Item item = + net.minecraft.core.registries.BuiltInRegistries.ITEM.getValue( + net.minecraft.resources.Identifier.parse(listing.itemId)); + if (item != null) { + net.minecraft.world.item.ItemStack stack = + new net.minecraft.world.item.ItemStack(item, listing.count); + if (!seller.getInventory().add(stack)) { + net.minecraft.world.entity.item.ItemEntity entity = + new net.minecraft.world.entity.item.ItemEntity(seller.level(), + seller.getX(), seller.getY(), seller.getZ(), stack); + seller.level().addFreshEntity(entity); + } + seller.sendSystemMessage(net.minecraft.network.chat.Component.literal( + "§6[Market] §7Annonce #" + id + " expiree, objets rendus.")); + } + } + } catch (IllegalArgumentException e) { + // UUID vendeur invalide : annonce supprimee sans rendu. + } + } + } + } + public void load() { Path path = file(); if (!Files.exists(path)) { @@ -100,6 +153,9 @@ public final class PalaMarket { Listing listing = GSON.fromJson(GSON.toJson(entry.getValue()), Listing.class); if (listing != null && listing.id > 0 && listing.itemId != null && !listing.itemId.isEmpty()) { + if (listing.createdAt <= 0L) { + listing.createdAt = System.currentTimeMillis(); + } listings.put(listing.id, listing); if (listing.id >= nextId) { nextId = listing.id + 1; diff --git a/server/mods/pala-0.2.1.jar b/server/mods/pala-0.2.1.jar index 3c7e757..04d8cf8 100644 Binary files a/server/mods/pala-0.2.1.jar and b/server/mods/pala-0.2.1.jar differ