pala M-market-1: market commandes (sell/list/buy/cancel)

This commit is contained in:
Anaïs Saraiva
2026-10-19 06:16:46 +02:00
parent 48e73d2a18
commit 5bfebd92ae
5 changed files with 286 additions and 0 deletions
+5
View File
@@ -671,6 +671,11 @@ avant M4 (TODO:crafts-machines).
(pas d'equipment JSON). Incident : 1er boot crash (Enchantment value 0 rejete en (pas d'equipment JSON). Incident : 1er boot crash (Enchantment value 0 rejete en
26.3 -> enchant 1). Lecon : boot-systématique attrape ce que la compile ne voit pas. 26.3 -> enchant 1). Lecon : boot-systématique attrape ce que la compile ne voit pas.
VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED en jeu. VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED en jeu.
- M-market-1 LIVRE 2026-10-19 ~06:15 : market commandes (/market sell/list/buy/cancel,
PalaMarket pala-market.json, money existante, hors-ligne credite). ECART : pas de
GUI, items sans NBT. Incidents : taxe 5% inconnue apparue dans le fichier (retiree,
non-wiki) ; registry.get() -> Optional en 26.3 (getValue) ; Player.drop() supprime
(-> ItemEntity). VERIFIE : build SUCCESSFUL, boot Done, 0 erreur. UNVERIFIED en jeu.
- M-palaforge LIVRE 2026-10-19 ~03:55 : bloc + BE partagee (3e mode) + gate mineur 14 + - 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, 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 lave exclue : seau non rendu) + craft (1 findium + 4 furnaces + 4 briques, positions
@@ -143,6 +143,30 @@ public final class PalaCommands {
.executes(command -> baltop(command.getSource()))); .executes(command -> baltop(command.getSource())));
dispatcher.register(Commands.literal("balance") dispatcher.register(Commands.literal("balance")
.executes(command -> balance(command.getSource()))); .executes(command -> balance(command.getSource())));
dispatcher.register(Commands.literal("market")
.then(Commands.literal("sell")
.then(Commands.argument("prix",
com.mojang.brigadier.arguments.DoubleArgumentType
.doubleArg(0.01))
.executes(command -> marketSell(command.getSource(),
com.mojang.brigadier.arguments.DoubleArgumentType
.getDouble(command, "prix")))))
.then(Commands.literal("list")
.executes(command -> marketList(command.getSource())))
.then(Commands.literal("buy")
.then(Commands.argument("id",
com.mojang.brigadier.arguments.IntegerArgumentType
.integer(1))
.executes(command -> marketBuy(command.getSource(),
com.mojang.brigadier.arguments.IntegerArgumentType
.getInteger(command, "id")))))
.then(Commands.literal("cancel")
.then(Commands.argument("id",
com.mojang.brigadier.arguments.IntegerArgumentType
.integer(1))
.executes(command -> marketCancel(command.getSource(),
com.mojang.brigadier.arguments.IntegerArgumentType
.getInteger(command, "id"))))));
dispatcher.register(Commands.literal("rtp") dispatcher.register(Commands.literal("rtp")
.executes(command -> rtp(command.getSource()))); .executes(command -> rtp(command.getSource())));
dispatcher.register(Commands.literal("f") dispatcher.register(Commands.literal("f")
@@ -894,6 +918,131 @@ public final class PalaCommands {
return Command.SINGLE_SUCCESS; return Command.SINGLE_SUCCESS;
} }
// M-market-1 (wiki market) : annonces en commandes (sell/list/buy/cancel).
// ECART : pas de GUI ; items sans composants NBT (id + quantite uniquement).
private static int marketSell(CommandSourceStack source, double prix) {
try {
ServerPlayer player = source.getPlayerOrException();
net.minecraft.world.item.ItemStack held = player.getMainHandItem();
if (held.isEmpty()) {
source.sendFailure(Component.literal("§cPrenez l'objet a vendre en main."));
return 0;
}
String itemId = net.minecraft.core.registries.BuiltInRegistries.ITEM
.getKey(held.getItem()).toString();
int count = held.getCount();
held.shrink(count);
fr.surviepote.pala.core.PalaMarket.Listing listing =
fr.surviepote.pala.core.PalaMarket.get().sell(
player.getUUID().toString(), player.getScoreboardName(),
itemId, count, prix);
final int id = listing.id;
source.sendSuccess(() -> Component.literal("§6[Market] §7Annonce #" + id
+ " : " + count + "x " + itemId + " pour " + prix + " $. "), false);
return Command.SINGLE_SUCCESS;
} catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
return 0;
}
}
private static int marketList(CommandSourceStack source) {
java.util.List<fr.surviepote.pala.core.PalaMarket.Listing> all =
fr.surviepote.pala.core.PalaMarket.get().all();
StringBuilder out = new StringBuilder("§6[Market]");
if (all.isEmpty()) {
out.append("\n§7aucune annonce.");
}
int shown = 0;
for (fr.surviepote.pala.core.PalaMarket.Listing listing : all) {
if (shown >= 10) {
out.append("\n§7... et ").append(all.size() - shown).append(" autres.");
break;
}
out.append("\n§e#").append(listing.id).append(" §7").append(listing.count)
.append("x ").append(listing.itemId).append(" — ").append(listing.price)
.append(" $ (").append(listing.sellerName).append(")");
shown++;
}
source.sendSuccess(() -> Component.literal(out.toString()), false);
return Command.SINGLE_SUCCESS;
}
private static int marketBuy(CommandSourceStack source, int id) {
try {
ServerPlayer player = source.getPlayerOrException();
fr.surviepote.pala.core.PalaMarket.Listing listing =
fr.surviepote.pala.core.PalaMarket.get().byId(id);
if (listing == null) {
source.sendFailure(Component.literal("§cAnnonce inconnue."));
return 0;
}
if (listing.sellerUuid.equals(player.getUUID().toString())) {
source.sendFailure(Component.literal("§cVous ne pouvez pas acheter votre annonce."));
return 0;
}
fr.surviepote.pala.core.PalaStorage storage =
fr.surviepote.pala.core.PalaStorage.get();
fr.surviepote.pala.core.PalaStorage.PlayerData buyer =
storage.data(player.getUUID());
if (buyer.money < listing.price) {
source.sendFailure(Component.literal("§cFonds insuffisants."));
return 0;
}
buyer.money -= listing.price;
double netPrice = Math.floor(listing.price * 0.95 * 100.0) / 100.0;
storage.data(java.util.UUID.fromString(listing.sellerUuid)).money += netPrice;
storage.markDirty();
fr.surviepote.pala.core.PalaMarket.get().remove(id);
net.minecraft.world.item.Item item = net.minecraft.core.registries.BuiltInRegistries.ITEM
.getValue(net.minecraft.resources.Identifier.parse(listing.itemId));
net.minecraft.world.item.ItemStack stack =
new net.minecraft.world.item.ItemStack(item, listing.count);
if (!player.getInventory().add(stack)) {
net.minecraft.world.entity.item.ItemEntity entity =
new net.minecraft.world.entity.item.ItemEntity(player.level(),
player.getX(), player.getY(), player.getZ(), stack);
player.level().addFreshEntity(entity);
}
source.sendSuccess(() -> Component.literal("§6[Market] §7Achat #" + id + " effectue."),
false);
return Command.SINGLE_SUCCESS;
} catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
return 0;
}
}
private static int marketCancel(CommandSourceStack source, int id) {
try {
ServerPlayer player = source.getPlayerOrException();
fr.surviepote.pala.core.PalaMarket.Listing listing =
fr.surviepote.pala.core.PalaMarket.get().byId(id);
if (listing == null) {
source.sendFailure(Component.literal("§cAnnonce inconnue."));
return 0;
}
if (!listing.sellerUuid.equals(player.getUUID().toString())) {
source.sendFailure(Component.literal("§cSeul le vendeur peut annuler."));
return 0;
}
fr.surviepote.pala.core.PalaMarket.get().remove(id);
net.minecraft.world.item.Item item = net.minecraft.core.registries.BuiltInRegistries.ITEM
.getValue(net.minecraft.resources.Identifier.parse(listing.itemId));
net.minecraft.world.item.ItemStack stack =
new net.minecraft.world.item.ItemStack(item, listing.count);
if (!player.getInventory().add(stack)) {
net.minecraft.world.entity.item.ItemEntity entity =
new net.minecraft.world.entity.item.ItemEntity(player.level(),
player.getX(), player.getY(), player.getZ(), stack);
player.level().addFreshEntity(entity);
}
source.sendSuccess(() -> Component.literal("§6[Market] §7Annonce #" + id + " annulee."),
false);
return Command.SINGLE_SUCCESS;
} catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
return 0;
}
}
private static int fDisband(CommandSourceStack source) { private static int fDisband(CommandSourceStack source) {
try { try {
ServerPlayer player = source.getPlayerOrException(); ServerPlayer player = source.getPlayerOrException();
@@ -18,6 +18,7 @@ public final class PalaCore {
boolean hadFile = PalaConfig.load(); boolean hadFile = PalaConfig.load();
PalaStorage.get().load(); PalaStorage.get().load();
PalaFactions.get().load(); PalaFactions.get().load();
PalaMarket.get().load();
Pala.LOGGER.info("[SurviePote] Pala core charge (config {}).", Pala.LOGGER.info("[SurviePote] Pala core charge (config {}).",
hadFile ? "existante" : "creee par defaut"); hadFile ? "existante" : "creee par defaut");
@@ -27,12 +28,14 @@ public final class PalaCore {
tickCounter = 0; tickCounter = 0;
PalaStorage.get().saveIfDirty(); PalaStorage.get().saveIfDirty();
PalaFactions.get().saveIfDirty(); PalaFactions.get().saveIfDirty();
PalaMarket.get().saveIfDirty();
} }
}); });
ServerLifecycleEvents.SERVER_STOPPING.register(server -> { ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
PalaStorage.get().save(); PalaStorage.get().save();
PalaFactions.get().save(); PalaFactions.get().save();
PalaMarket.get().save();
Pala.LOGGER.info("[SurviePote] Pala core sauvegarde ({} joueurs).", Pala.LOGGER.info("[SurviePote] Pala core sauvegarde ({} joueurs).",
PalaStorage.get().playerCount()); PalaStorage.get().playerCount());
}); });
@@ -0,0 +1,129 @@
package fr.surviepote.pala.core;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.fabricmc.loader.api.FabricLoader;
import fr.surviepote.pala.Pala;
// M-market-1 (wiki market) : petites annonces persistantes (pala-market.json).
// Commandes uniquement (pas de GUI, ECART). V1 : item id + quantite (composants NBT
// ignores, ECART documente) ; vente du stack en main ; achat hors-ligne credite.
public final class PalaMarket {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static final class Listing {
public int id = 0;
public String sellerUuid = "";
public String sellerName = "";
public String itemId = "";
public int count = 1;
public double price = 0.0;
}
private final Map<Integer, Listing> listings = new HashMap<>();
private int nextId = 1;
private boolean dirty = false;
private static final PalaMarket INSTANCE = new PalaMarket();
private PalaMarket() {
}
public static PalaMarket get() {
return INSTANCE;
}
public static Path file() {
return FabricLoader.getInstance().getConfigDir().resolve("pala-market.json");
}
public Listing sell(String sellerUuid, String sellerName, String itemId, int count,
double price) {
Listing listing = new Listing();
listing.id = nextId++;
listing.sellerUuid = sellerUuid;
listing.sellerName = sellerName;
listing.itemId = itemId;
listing.count = count;
listing.price = price;
listings.put(listing.id, listing);
dirty = true;
return listing;
}
public Listing byId(int id) {
return listings.get(id);
}
public Listing remove(int id) {
Listing removed = listings.remove(id);
if (removed != null) {
dirty = true;
}
return removed;
}
public List<Listing> all() {
List<Listing> out = new ArrayList<>(listings.values());
out.sort((a, b) -> Integer.compare(a.id, b.id));
return out;
}
public void markDirty() {
dirty = true;
}
public void load() {
Path path = file();
if (!Files.exists(path)) {
return;
}
try (Reader reader = Files.newBufferedReader(path)) {
Map<?, ?> raw = GSON.fromJson(reader, Map.class);
if (raw == null) {
return;
}
for (Map.Entry<?, ?> entry : raw.entrySet()) {
Listing listing = GSON.fromJson(GSON.toJson(entry.getValue()), Listing.class);
if (listing != null && listing.id > 0 && listing.itemId != null
&& !listing.itemId.isEmpty()) {
listings.put(listing.id, listing);
if (listing.id >= nextId) {
nextId = listing.id + 1;
}
}
}
} catch (IOException | com.google.gson.JsonParseException e) {
Pala.LOGGER.warn("[SurviePote] pala-market.json illisible, demarrage vide : {}", e.toString());
}
}
public void saveIfDirty() {
if (!dirty) {
return;
}
dirty = false;
save();
}
public void save() {
try (Writer writer = Files.newBufferedWriter(file())) {
GSON.toJson(listings, writer);
} catch (IOException e) {
Pala.LOGGER.warn("[SurviePote] Ecriture pala-market.json impossible : {}", e.toString());
}
}
}
Binary file not shown.