pala M0: socle core (config/permissions/storage/jobs) + /pala /jobs + gate /nether, jar serveur redeploye
This commit is contained in:
@@ -11,6 +11,7 @@ public class Pala implements ModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
fr.surviepote.pala.core.PalaCore.register();
|
||||
PalaRegistries.registerAll();
|
||||
fr.surviepote.pala.events.PalaEvents.registerAll();
|
||||
LOGGER.info("[SurviePote] Pala initialisé.");
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package fr.surviepote.pala;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -15,7 +18,13 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.portal.TeleportTransition;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
// Commandes Pala : /end /nether /overworld (permission niveau 4, legacy).
|
||||
import fr.surviepote.pala.core.PalaConfig;
|
||||
import fr.surviepote.pala.core.PalaJobs;
|
||||
import fr.surviepote.pala.core.PalaPermissions;
|
||||
import fr.surviepote.pala.core.PalaStorage;
|
||||
|
||||
// Commandes Pala : /end /overworld (permission niveau 4, legacy), /nether (gate metier
|
||||
// mineur niv.3, M0), /pala reload|info|rank (admin), /jobs (metiers). Voir CDC §3.8.
|
||||
// Origine : CommandEnd/Nether/Overworld + procedures *CommandExecuted qui
|
||||
// teleportaient le joueur au spawn de la dimension visee. Ici via
|
||||
// TeleportTransition (API 26.x), sans le Teleporter custom du legacy.
|
||||
@@ -30,14 +39,96 @@ public final class PalaCommands {
|
||||
.requires(source -> Commands.LEVEL_OWNERS.check(source.permissions()))
|
||||
.executes(command -> teleport(command.getSource(), Level.END)));
|
||||
dispatcher.register(Commands.literal("nether")
|
||||
.requires(source -> Commands.LEVEL_OWNERS.check(source.permissions()))
|
||||
.executes(command -> teleport(command.getSource(), Level.NETHER)));
|
||||
.executes(command -> nether(command.getSource())));
|
||||
dispatcher.register(Commands.literal("overworld")
|
||||
.requires(source -> Commands.LEVEL_OWNERS.check(source.permissions()))
|
||||
.executes(command -> teleport(command.getSource(), Level.OVERWORLD)));
|
||||
com.mojang.brigadier.builder.ArgumentBuilder<CommandSourceStack, ?> rankArg =
|
||||
Commands.argument("rang", StringArgumentType.word())
|
||||
.executes(command -> rank(command.getSource(),
|
||||
EntityArgument.getPlayer(command, "joueur"),
|
||||
StringArgumentType.getString(command, "rang")));
|
||||
com.mojang.brigadier.builder.ArgumentBuilder<CommandSourceStack, ?> joueurArg =
|
||||
Commands.argument("joueur", EntityArgument.player()).then(rankArg);
|
||||
dispatcher.register(Commands.literal("pala")
|
||||
.then(Commands.literal("reload")
|
||||
.requires(source -> isAdmin(source))
|
||||
.executes(command -> reload(command.getSource())))
|
||||
.then(Commands.literal("info")
|
||||
.requires(source -> isAdmin(source))
|
||||
.executes(command -> info(command.getSource())))
|
||||
.then(Commands.literal("rank")
|
||||
.requires(source -> isAdmin(source))
|
||||
.then(joueurArg)));
|
||||
dispatcher.register(Commands.literal("jobs")
|
||||
.executes(command -> jobs(command.getSource())));
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isAdmin(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player == null) {
|
||||
return true;
|
||||
}
|
||||
return PalaPermissions.has(source, player, "pala.admin");
|
||||
}
|
||||
|
||||
private static int reload(CommandSourceStack source) {
|
||||
PalaConfig.load();
|
||||
source.sendSuccess(() -> Component.literal(
|
||||
"§6[Pala] §7Config rechargee (" + PalaStorage.get().playerCount() + " joueurs connus)."),
|
||||
false);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private static int info(CommandSourceStack source) {
|
||||
source.sendSuccess(() -> Component.literal("§6[Pala] §7Joueurs connus : "
|
||||
+ PalaStorage.get().playerCount()), false);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private static int rank(CommandSourceStack source, ServerPlayer target, String rank) {
|
||||
if (!PalaConfig.get().rankNodes.containsKey(rank)) {
|
||||
source.sendFailure(Component.literal("§cRang inconnu : " + rank));
|
||||
return 0;
|
||||
}
|
||||
PalaPermissions.setRank(target, rank);
|
||||
source.sendSuccess(() -> Component.literal("§6[Pala] §7" + target.getScoreboardName()
|
||||
+ " -> rang " + rank + "."), false);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private static int jobs(CommandSourceStack source) {
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
StringBuilder lines = new StringBuilder("§6[Metiers]");
|
||||
for (String job : PalaJobs.JOBS) {
|
||||
lines.append("\n§e").append(job).append(" §7niv. §a")
|
||||
.append(PalaJobs.levelOf(player, job)).append(" §8(")
|
||||
.append((long) PalaJobs.xpOf(player, job)).append(" xp)");
|
||||
}
|
||||
source.sendSuccess(() -> Component.literal(lines.toString()), false);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
} catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// /nether : deblocage metier mineur niv.3 (wiki recompenses mineur, VERIFIE), OP bypass.
|
||||
private static int nether(CommandSourceStack source) {
|
||||
ServerPlayer player = source.getPlayer();
|
||||
if (player != null) {
|
||||
int required = PalaConfig.get().netherMinerLevel;
|
||||
if (!Commands.LEVEL_ADMINS.check(source.permissions())
|
||||
&& PalaJobs.levelOf(player, "mineur") < required) {
|
||||
player.sendSystemMessage(Component.literal("§cNether verrouille : mineur niveau "
|
||||
+ required + " requis (actuel : " + PalaJobs.levelOf(player, "mineur") + ")."));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return teleport(source, Level.NETHER);
|
||||
}
|
||||
|
||||
private static int teleport(CommandSourceStack source, ResourceKey<Level> dimension) {
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
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.HashMap;
|
||||
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;
|
||||
|
||||
// Config rechargeable du mod (M0). JSON via Gson (fourni par Mojang au runtime).
|
||||
//
|
||||
// Choix JSON plutot que YAML en 3 lignes :
|
||||
// 1. Zero dependance (pas de snakeyaml a embarquer/patcher au build) ;
|
||||
// 2. Gson est deja au classpath compile (gson-2.14.0.jar) et au runtime Mojang ;
|
||||
// 3. /pala reload re-parse le fichier sans restart, valeurs par defaut si cles absentes.
|
||||
// Les valeurs wiki VERIFIEES sont en Maka ; le reste est UNVERIFIED (balance staff, M5).
|
||||
public final class PalaConfig {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
// XP metier mineur par bloc casse (wiki "Evolution du metier Mineur", VERIFIE).
|
||||
// Cles = ids de registres (vanilla ou pala:). Map.ofEntries : Map.of limite a 10 paires.
|
||||
public Map<String, Double> minerXp = new HashMap<>(Map.ofEntries(
|
||||
Map.entry("minecraft:stone", 0.5),
|
||||
Map.entry("minecraft:diorite", 3.0), Map.entry("minecraft:andesite", 3.0),
|
||||
Map.entry("minecraft:coal_ore", 4.0), Map.entry("minecraft:deepslate_coal_ore", 4.0),
|
||||
Map.entry("minecraft:quartz_ore", 6.0), Map.entry("minecraft:obsidian", 6.0),
|
||||
Map.entry("minecraft:lapis_ore", 15.0), Map.entry("minecraft:redstone_ore", 15.0),
|
||||
Map.entry("minecraft:emerald_ore", 50.0),
|
||||
Map.entry("minecraft:iron_ore", 2.0), Map.entry("minecraft:deepslate_iron_ore", 2.0),
|
||||
Map.entry("minecraft:gold_ore", 4.0), Map.entry("minecraft:deepslate_gold_ore", 4.0),
|
||||
Map.entry("minecraft:diamond_ore", 8.0), Map.entry("minecraft:deepslate_diamond_ore", 8.0),
|
||||
Map.entry("pala:amethyst_ore", 12.0), Map.entry("pala:titane_ore", 16.0),
|
||||
Map.entry("pala:paladium_ore", 20.0),
|
||||
Map.entry("pala:paladium_green_ore", 20.0), Map.entry("pala:trixium_ore", 10.0),
|
||||
Map.entry("pala:findium_ore", 10.0)));
|
||||
|
||||
// Courbe XP : cout du niveau n. UNVERIFIED (formule placeholder, a caler M5).
|
||||
public double xpBase = 100.0;
|
||||
public double xpExponent = 1.5;
|
||||
|
||||
// Niveau mineur requis pour /nether (wiki recompenses mineur niv.3, VERIFIE).
|
||||
public int netherMinerLevel = 3;
|
||||
|
||||
// Cooldowns sticks PvP en secondes. UNVERIFIED (durees balance staff, M5).
|
||||
public Map<String, Integer> stickCooldowns = new HashMap<>(Map.of(
|
||||
"heal_stick", 60, "speed_stick", 30, "hyper_jump_stick", 30,
|
||||
"strenght_stick", 120, "stick_of_god", 600));
|
||||
|
||||
// Rangs -> noeuds de permission (extrait page "par grade", partiel UNVERIFIED).
|
||||
public Map<String, java.util.List<String>> rankNodes = new HashMap<>(Map.of(
|
||||
"default", java.util.List.of("pala.job", "pala.trade", "pala.market"),
|
||||
"heros", java.util.List.of("pala.*")));
|
||||
|
||||
private static PalaConfig instance = new PalaConfig();
|
||||
|
||||
private PalaConfig() {
|
||||
}
|
||||
|
||||
public static PalaConfig get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Path file() {
|
||||
return FabricLoader.getInstance().getConfigDir().resolve("pala.json");
|
||||
}
|
||||
|
||||
/** Charge (ou cree avec defauts). Retourne true si un fichier existant a ete lu. */
|
||||
public static boolean load() {
|
||||
Path path = file();
|
||||
if (!Files.exists(path)) {
|
||||
save();
|
||||
return false;
|
||||
}
|
||||
try (Reader reader = Files.newBufferedReader(path)) {
|
||||
PalaConfig loaded = GSON.fromJson(reader, PalaConfig.class);
|
||||
if (loaded != null) {
|
||||
if (loaded.minerXp != null && !loaded.minerXp.isEmpty()) {
|
||||
instance.minerXp = loaded.minerXp;
|
||||
}
|
||||
if (loaded.xpBase > 0) {
|
||||
instance.xpBase = loaded.xpBase;
|
||||
}
|
||||
if (loaded.xpExponent > 0) {
|
||||
instance.xpExponent = loaded.xpExponent;
|
||||
}
|
||||
if (loaded.netherMinerLevel >= 0) {
|
||||
instance.netherMinerLevel = loaded.netherMinerLevel;
|
||||
}
|
||||
if (loaded.stickCooldowns != null && !loaded.stickCooldowns.isEmpty()) {
|
||||
instance.stickCooldowns = loaded.stickCooldowns;
|
||||
}
|
||||
if (loaded.rankNodes != null && !loaded.rankNodes.isEmpty()) {
|
||||
instance.rankNodes = loaded.rankNodes;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (IOException | com.google.gson.JsonParseException e) {
|
||||
Pala.LOGGER.warn("[SurviePote] Config pala.json illisible, defauts gardes : {}", e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
try (Writer writer = Files.newBufferedWriter(file())) {
|
||||
GSON.toJson(instance, writer);
|
||||
} catch (IOException e) {
|
||||
Pala.LOGGER.warn("[SurviePote] Ecriture pala.json impossible : {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/** Cout XP total pour atteindre le niveau n (n >= 1). */
|
||||
public long xpForLevel(int level) {
|
||||
return (long) (xpBase * Math.pow(level, xpExponent));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package fr.surviepote.pala.core;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
import fr.surviepote.pala.Pala;
|
||||
|
||||
// Cycle de vie du socle M0 : config + storage au boot, flush periodique, save a l'arret.
|
||||
// Le compteur modulo 100 sur END_SERVER_TICK = ~5 s (20 ticks/s) : zero I/O si pas dirty.
|
||||
public final class PalaCore {
|
||||
|
||||
private static int tickCounter = 0;
|
||||
|
||||
private PalaCore() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
boolean hadFile = PalaConfig.load();
|
||||
PalaStorage.get().load();
|
||||
Pala.LOGGER.info("[SurviePote] Pala core charge (config {}).",
|
||||
hadFile ? "existante" : "creee par defaut");
|
||||
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
tickCounter++;
|
||||
if (tickCounter >= 100) {
|
||||
tickCounter = 0;
|
||||
PalaStorage.get().saveIfDirty();
|
||||
}
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
|
||||
PalaStorage.get().save();
|
||||
Pala.LOGGER.info("[SurviePote] Pala core sauvegarde ({} joueurs).",
|
||||
PalaStorage.get().playerCount());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package fr.surviepote.pala.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
// Metiers : XP et niveaux (M0 = moteur minimal, tables completes en M5).
|
||||
// Wiki VERIFIE : 4 metiers (mineur, fermier, chasseur, alchimiste), ~100 niveaux,
|
||||
// table XP mineur par bloc (PalaConfig.minerXp). Courbe et recompenses : UNVERIFIED (M5).
|
||||
public final class PalaJobs {
|
||||
|
||||
public static final List<String> JOBS = List.of("mineur", "fermier", "chasseur", "alchimiste");
|
||||
|
||||
private PalaJobs() {
|
||||
}
|
||||
|
||||
public static int levelOf(ServerPlayer player, String job) {
|
||||
return PalaStorage.get().data(player.getUUID()).jobs
|
||||
.getOrDefault(job, new PalaStorage.JobData()).level;
|
||||
}
|
||||
|
||||
public static double xpOf(ServerPlayer player, String job) {
|
||||
return PalaStorage.get().data(player.getUUID()).jobs
|
||||
.getOrDefault(job, new PalaStorage.JobData()).xp;
|
||||
}
|
||||
|
||||
/** Ajoute de l'XP, monte les niveaux franchis, annonce. Retourne le niveau final. */
|
||||
public static int addXp(ServerPlayer player, String job, double amount) {
|
||||
if (amount <= 0) {
|
||||
return levelOf(player, job);
|
||||
}
|
||||
PalaStorage.JobData data = PalaStorage.get().data(player.getUUID()).jobs
|
||||
.computeIfAbsent(job, k -> new PalaStorage.JobData());
|
||||
data.xp += amount;
|
||||
PalaConfig config = PalaConfig.get();
|
||||
while (data.level < 100 && data.xp >= config.xpForLevel(data.level + 1)) {
|
||||
data.level++;
|
||||
player.sendSystemMessage(Component.literal(
|
||||
"§6[Metier] §e" + job + " §7niveau §a" + data.level + " §7atteint !"));
|
||||
// TODO:recompenses-m5 : lots par palier (voidstone niv.2, /nether niv.3...). Raison : M5.
|
||||
}
|
||||
PalaStorage.get().markDirty();
|
||||
return data.level;
|
||||
}
|
||||
|
||||
/** Hook casse-bloc : XP mineur selon la table config. Appele depuis PalaToolEvents. */
|
||||
public static void onBlockBreak(ServerPlayer player, ServerLevel level, BlockPos pos, BlockState state) {
|
||||
Identifier id = level.registryAccess()
|
||||
.lookupOrThrow(net.minecraft.core.registries.Registries.BLOCK)
|
||||
.getKey(state.getBlock());
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
Double xp = PalaConfig.get().minerXp.get(id.toString());
|
||||
if (xp != null) {
|
||||
addXp(player, "mineur", xp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package fr.surviepote.pala.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
// Permissions internes (M0) : rangs + noeuds pala.*.
|
||||
//
|
||||
// Choix systeme interne plutot que LuckPerms en 3 lignes :
|
||||
// 1. Zero dependance : le serveur actuel n'a pas LuckPerms, M0 doit booter tel quel ;
|
||||
// 2. Les grades boutique se resolvent en 2 rangs + noeuds explicites, suffisant pour M0-M6 ;
|
||||
// 3. Si LuckPerms est ajoute plus tard, cette classe devient un adaptateur (1 seul point de contact).
|
||||
// TODO:luckperms : re-evaluer en M7 (CDC §3.8). Raison : reconciliation avec les grades boutique.
|
||||
public final class PalaPermissions {
|
||||
|
||||
private PalaPermissions() {
|
||||
}
|
||||
|
||||
public static String rankOf(ServerPlayer player) {
|
||||
return PalaStorage.get().data(player.getUUID()).rank;
|
||||
}
|
||||
|
||||
public static void setRank(ServerPlayer player, String rank) {
|
||||
PalaStorage.PlayerData data = PalaStorage.get().data(player.getUUID());
|
||||
data.rank = rank;
|
||||
PalaStorage.get().markDirty();
|
||||
}
|
||||
|
||||
/** OP niveau 2+ (LEVEL_ADMINS) bypass tout ; sinon noeud exact ou wildcard pala.* du rang.
|
||||
* Prend la source (PermissionSet vanilla 26.3, verifie au javap) + le joueur (rang interne). */
|
||||
public static boolean has(CommandSourceStack source, ServerPlayer player, String node) {
|
||||
if (net.minecraft.commands.Commands.LEVEL_ADMINS.check(source.permissions())) {
|
||||
return true;
|
||||
}
|
||||
List<String> nodes = PalaConfig.get().rankNodes.getOrDefault(rankOf(player), List.of());
|
||||
if (nodes.contains(node) || nodes.contains("pala.*")) {
|
||||
return true;
|
||||
}
|
||||
// Wildcard partiel : pala.job.* couvre pala.job.mineur, etc.
|
||||
int dot = node.lastIndexOf('.');
|
||||
if (dot > 0 && nodes.contains(node.substring(0, dot) + ".*")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import fr.surviepote.pala.Pala;
|
||||
|
||||
// Donnees joueurs persistantes (M0) : jobs XP/niveaux, rang, monnaie.
|
||||
//
|
||||
// Choix JSON fichier unique en 3 lignes :
|
||||
// 1. M0 n'a besoin que de lectures/ecritures simples (pas de jointures) ;
|
||||
// 2. Flush differe hors tick (dirty + save 5 s) = zero I/O sur le thread tick ;
|
||||
// 3. SQLite arrive en M7 avec l'economie (listings, historique) — le schema est prevu
|
||||
// pour migrer tel quel (1 ligne joueur = 1 document JSON aujourd'hui).
|
||||
// TODO:sqlite : migrer vers pala.db (JDBC) en M7. Raison : requetes market/ELO hors de portee JSON.
|
||||
public final class PalaStorage {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
public static final class JobData {
|
||||
public double xp = 0.0;
|
||||
public int level = 0;
|
||||
}
|
||||
|
||||
public static final class PlayerData {
|
||||
public Map<String, JobData> jobs = new HashMap<>();
|
||||
public String rank = "default";
|
||||
public double money = 0.0;
|
||||
}
|
||||
|
||||
private final Map<String, PlayerData> players = new HashMap<>();
|
||||
private boolean dirty = false;
|
||||
|
||||
private static final PalaStorage INSTANCE = new PalaStorage();
|
||||
|
||||
private PalaStorage() {
|
||||
}
|
||||
|
||||
public static PalaStorage get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Path file() {
|
||||
return FabricLoader.getInstance().getConfigDir().resolve("pala-players.json");
|
||||
}
|
||||
|
||||
public PlayerData data(UUID uuid) {
|
||||
return players.computeIfAbsent(uuid.toString(), k -> new PlayerData());
|
||||
}
|
||||
|
||||
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()) {
|
||||
PlayerData data = GSON.fromJson(GSON.toJson(entry.getValue()), PlayerData.class);
|
||||
if (data != null) {
|
||||
if (data.jobs == null) {
|
||||
data.jobs = new HashMap<>();
|
||||
}
|
||||
players.put(String.valueOf(entry.getKey()), data);
|
||||
}
|
||||
}
|
||||
} catch (IOException | com.google.gson.JsonParseException e) {
|
||||
Pala.LOGGER.warn("[SurviePote] pala-players.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(players, writer);
|
||||
} catch (IOException e) {
|
||||
Pala.LOGGER.warn("[SurviePote] Ecriture pala-players.json impossible : {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/** Nombre de joueurs connus (debug /pala). */
|
||||
public int playerCount() {
|
||||
return players.size();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||
|
||||
import fr.surviepote.pala.PalaBlocks;
|
||||
import fr.surviepote.pala.PalaItems;
|
||||
import fr.surviepote.pala.core.PalaJobs;
|
||||
|
||||
// Portage des procedures "bloc detruit avec l'outil / par le joueur" MCreator :
|
||||
// - ProcedurePickaxeOfTheGodBlockDestroyedWithTool : compteur "level" en CustomData,
|
||||
@@ -104,6 +105,9 @@ public final class PalaToolEvents {
|
||||
ItemStack hand = sp.getMainHandItem();
|
||||
Item held = hand.isEmpty() ? null : hand.getItem();
|
||||
|
||||
// --- Metiers : XP mineur (M0) ---
|
||||
PalaJobs.onBlockBreak(sp, sl, pos, state);
|
||||
|
||||
// --- Pioche divine : compteur + evolution ---
|
||||
if (held != null && GOD_PICKAXES.contains(held)) {
|
||||
if (held == PalaItems.PICKAXE_OF_THE_GOD_LEVEL25) {
|
||||
|
||||
Reference in New Issue
Block a user