Ver Fonte

Creating and adding custom Configs to player-specific yml files

Jan há 1 mês atrás
pai
commit
37843ab4a9

+ 7 - 1
pom.xml

@@ -6,7 +6,7 @@
 
     <groupId>me.lethunderhawk</groupId>
     <artifactId>FluxAPI</artifactId>
-    <version>1.0-SNAPSHOT</version>
+    <version>1.2.0</version>
     <packaging>jar</packaging>
 
     <name>FluxAPI</name>
@@ -45,6 +45,12 @@
                 </executions>
             </plugin>
         </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
     </build>
 
     <repositories>

+ 5 - 1
src/main/java/me/lethunderhawk/main/FluxAPI.java

@@ -2,6 +2,7 @@ package me.lethunderhawk.main;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.npc.NPCModule;
+import me.lethunderhawk.profile.ProfileModule;
 import org.bukkit.plugin.java.JavaPlugin;
 
 public class FluxAPI extends JavaPlugin {
@@ -12,6 +13,9 @@ public class FluxAPI extends JavaPlugin {
 
         NPCModule module = new NPCModule(this);
         module.onEnable();
-        FluxService.register(NPCModule.class, module);
+        FluxService.registerModule(NPCModule.class, module);
+
+        ProfileModule profile = new ProfileModule(this);
+        profile.onEnable();
     }
 }

+ 0 - 1
src/main/java/me/lethunderhawk/npc/NPCModule.java

@@ -8,7 +8,6 @@ import org.bukkit.event.HandlerList;
 import org.bukkit.plugin.java.JavaPlugin;
 
 public class NPCModule extends BazaarFluxModule{
-    public static final int viewDistance = 50;
     private NPCManager NPCManager;
 
     public NPCModule(JavaPlugin plugin) {

+ 1 - 2
src/main/java/me/lethunderhawk/npc/abstraction/DummyNPC.java

@@ -16,7 +16,6 @@ public class DummyNPC extends NPC{
 
     @Override
     public void onRightClick(Player player) {
-        player.sendMessage(Component.text("Bye there!"));
-
+        player.sendMessage(Component.text("<" + getOptions().getName() + "> You right clicked me!"));
     }
 }

+ 114 - 0
src/main/java/me/lethunderhawk/profile/ProfileManager.java

@@ -0,0 +1,114 @@
+package me.lethunderhawk.profile;
+
+import me.lethunderhawk.profile.config.ConfigLoader;
+import me.lethunderhawk.profile.representation.FluxProfile;
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class ProfileManager {
+
+    private final Map<UUID, FluxProfile> profiles = new HashMap<>();
+    private final ConfigLoader loader;
+
+    public ProfileManager(ConfigLoader loader) {
+        this.loader = loader;
+    }
+
+    /*
+     * Lazy-load profile.
+     */
+    public FluxProfile loadProfile(UUID uuid) {
+
+        if (profiles.containsKey(uuid)) {
+            return profiles.get(uuid);
+        }
+
+        FluxProfile profile = loader.loadConfig(
+                FluxProfile.class,
+                uuid.toString(),
+                FluxProfile::deserialize,
+                () -> createDefaultProfile(uuid)
+        );
+
+        profiles.put(uuid, profile);
+        return profile;
+    }
+
+    /*
+     * Creates default profile with default modules.
+     */
+    private FluxProfile createDefaultProfile(UUID uuid) {
+
+        FluxProfile profile = new FluxProfile(uuid.toString());
+
+        injectDefaultModules(profile);
+
+        return profile;
+    }
+
+    /*
+     * Injects default modules for new players.
+     * This is where API modules can define defaults.
+     */
+    private void injectDefaultModules(FluxProfile profile) {
+
+    }
+
+    /*
+     * Manual profile creation (rarely needed now).
+     */
+    public FluxProfile createNewProfile(Player player) {
+
+        UUID uuid = player.getUniqueId();
+
+        FluxProfile profile = createDefaultProfile(uuid);
+
+        profiles.put(uuid, profile);
+
+        return profile;
+    }
+
+    /*
+     * Get from memory only.
+     */
+    public FluxProfile getProfile(UUID uuid) {
+        return profiles.get(uuid);
+    }
+
+    /*
+     * Save single profile.
+     */
+    public void saveProfile(UUID uuid) {
+
+        FluxProfile profile = profiles.get(uuid);
+
+        if (profile == null) return;
+
+        loader.save(profile);
+    }
+
+    /*
+     * Save all loaded profiles.
+     */
+    public void saveAllProfiles() {
+
+        for (FluxProfile profile : profiles.values()) {
+            loader.save(profile);
+        }
+    }
+
+    /*
+     * Unload profile (save before removal).
+     */
+    public void unloadProfile(UUID uuid) {
+
+        FluxProfile profile = profiles.remove(uuid);
+
+        if (profile != null) {
+            loader.save(profile);
+        }
+    }
+}

+ 43 - 0
src/main/java/me/lethunderhawk/profile/ProfileModule.java

@@ -0,0 +1,43 @@
+package me.lethunderhawk.profile;
+
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
+import me.lethunderhawk.profile.config.ConfigLoader;
+import me.lethunderhawk.profile.listener.JoinListener;
+import org.bukkit.event.HandlerList;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public class ProfileModule extends BazaarFluxModule {
+    private JoinListener joinListener;
+    private ConfigLoader configLoader;
+    private ProfileManager profileManager;
+
+    public ProfileModule(JavaPlugin plugin) {
+        super(plugin);
+    }
+
+    @Override
+    public String getPrefix() {
+        return "Profile";
+    }
+
+    @Override
+    public void onEnable() {
+        configLoader = new ConfigLoader(this.plugin);
+        FluxService.register(ConfigLoader.class, configLoader);
+
+        profileManager = new ProfileManager(configLoader);
+        FluxService.register(ProfileManager.class, profileManager);
+
+        joinListener = new JoinListener(profileManager);
+        plugin.getServer().getPluginManager().registerEvents(joinListener, plugin);
+
+        plugin.getLogger().info("Game-Profile module enabled");
+    }
+
+    @Override
+    public void onDisable() {
+        HandlerList.unregisterAll(joinListener);
+        profileManager.saveAllProfiles();
+    }
+}

+ 87 - 0
src/main/java/me/lethunderhawk/profile/config/ConfigLoader.java

@@ -0,0 +1,87 @@
+package me.lethunderhawk.profile.config;
+
+import me.lethunderhawk.profile.config.abstraction.ConfigFactory;
+import me.lethunderhawk.profile.config.abstraction.PersistentConfig;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.function.Supplier;
+
+public class ConfigLoader {
+
+    private final File folder;
+    private final JavaPlugin main;
+
+    public ConfigLoader(JavaPlugin plugin) {
+        this.main = plugin;
+        this.folder = main.getDataFolder();
+
+        if (!folder.exists()) {
+            folder.mkdirs();
+        }
+    }
+
+    public <T extends PersistentConfig> T loadConfig(
+            Class<T> type,
+            String fileName,
+            ConfigFactory<T> factory,
+            Supplier<T> defaultSupplier
+    ) {
+
+        File file = getFile(fileName);
+
+        // If file does not exist → create default config
+        if (!file.exists()) {
+
+            try {
+                file.getParentFile().mkdirs();
+                file.createNewFile();
+            } catch (IOException e) {
+                throw new RuntimeException("Could not create config file: " + fileName, e);
+            }
+
+            T defaultConfig = defaultSupplier.get();
+            save(defaultConfig);
+
+            main.getLogger().info("[ProfileConfig] Created new profile " + fileName + ".yml");
+
+            return defaultConfig;
+        }
+
+        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
+
+        // If file exists but is empty → also create default
+        if (cfg.getKeys(false).isEmpty()) {
+
+            T defaultConfig = defaultSupplier.get();
+            save(defaultConfig);
+
+            main.getLogger().info("[ProfileConfig] Initialized empty profile " + fileName + ".yml");
+
+            return defaultConfig;
+        }
+
+        return factory.deserialize(cfg);
+    }
+
+
+    public void save(PersistentConfig persistentConfig) {
+        File file = getFile(persistentConfig.getFileName());
+        YamlConfiguration cfg = new YamlConfiguration();
+
+        persistentConfig.serialize(cfg);
+
+        try {
+            cfg.save(file);
+        } catch (IOException e) {
+            throw new RuntimeException("Could not save config file: " + file.getName(), e);
+        }
+    }
+
+    private File getFile(String name) {
+        return new File(folder, name + ".yml");
+    }
+}
+

+ 8 - 0
src/main/java/me/lethunderhawk/profile/config/abstraction/ConfigFactory.java

@@ -0,0 +1,8 @@
+package me.lethunderhawk.profile.config.abstraction;
+
+import org.bukkit.configuration.file.YamlConfiguration;
+
+@FunctionalInterface
+public interface ConfigFactory<T extends PersistentConfig> {
+    T deserialize(YamlConfiguration cfg);
+}

+ 10 - 0
src/main/java/me/lethunderhawk/profile/config/abstraction/PersistentConfig.java

@@ -0,0 +1,10 @@
+package me.lethunderhawk.profile.config.abstraction;
+
+import org.bukkit.configuration.file.YamlConfiguration;
+
+public interface PersistentConfig {
+
+    void serialize(YamlConfiguration cfg);
+
+    String getFileName();
+}

+ 17 - 0
src/main/java/me/lethunderhawk/profile/config/abstraction/subconfig/ProfileSubConfig.java

@@ -0,0 +1,17 @@
+package me.lethunderhawk.profile.config.abstraction.subconfig;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+public interface ProfileSubConfig {
+
+    /**
+     * Unique ID of this sub config.
+     * Used as YAML section name.
+     */
+    String getId();
+
+    /**
+     * Serialize into given section.
+     */
+    void serialize(ConfigurationSection section);
+}

+ 9 - 0
src/main/java/me/lethunderhawk/profile/config/abstraction/subconfig/ProfileSubConfigFactory.java

@@ -0,0 +1,9 @@
+package me.lethunderhawk.profile.config.abstraction.subconfig;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+@FunctionalInterface
+public interface ProfileSubConfigFactory<T extends ProfileSubConfig> {
+
+    T deserialize(ConfigurationSection section);
+}

+ 65 - 0
src/main/java/me/lethunderhawk/profile/config/registry/ConfigService.java

@@ -0,0 +1,65 @@
+package me.lethunderhawk.profile.config.registry;
+
+import me.lethunderhawk.profile.config.abstraction.ConfigFactory;
+import me.lethunderhawk.profile.config.abstraction.PersistentConfig;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class ConfigService {
+
+    private static final Map<Class<? extends PersistentConfig>, ConfigFactory<?>> factories = new ConcurrentHashMap<>();
+    private static final Map<Class<? extends PersistentConfig>, PersistentConfig> loadedConfigs = new ConcurrentHashMap<>();
+
+    private ConfigService() {}
+
+    public static <T extends PersistentConfig> void register(
+            Class<T> type,
+            ConfigFactory<T> factory
+    ) {
+        factories.put(type, factory);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends PersistentConfig> T load(
+            Class<T> type,
+            File file
+    ) {
+        ConfigFactory<T> factory = (ConfigFactory<T>) factories.get(type);
+
+        if (factory == null) {
+            throw new IllegalStateException("No factory registered for " + type.getName());
+        }
+
+        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);
+        T config = factory.deserialize(cfg);
+
+        loadedConfigs.put(type, config);
+        return config;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends PersistentConfig> T get(Class<T> type) {
+        return (T) loadedConfigs.get(type);
+    }
+
+    public static <T extends PersistentConfig> void save(Class<T> type, File file) {
+        T config = get(type);
+
+        if (config == null) {
+            throw new IllegalStateException("Config not loaded: " + type.getName());
+        }
+
+        YamlConfiguration cfg = new YamlConfiguration();
+        config.serialize(cfg);
+
+        try {
+            cfg.save(file);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 31 - 0
src/main/java/me/lethunderhawk/profile/config/registry/ProfileModuleRegistry.java

@@ -0,0 +1,31 @@
+package me.lethunderhawk.profile.config.registry;
+
+import me.lethunderhawk.profile.config.abstraction.subconfig.ProfileSubConfig;
+import me.lethunderhawk.profile.config.abstraction.subconfig.ProfileSubConfigFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public final class ProfileModuleRegistry {
+
+    private static final Map<String, ProfileSubConfigFactory<?>> factories = new HashMap<>();
+
+    private ProfileModuleRegistry() {}
+
+    public static <T extends ProfileSubConfig> void register(
+            String id,
+            ProfileSubConfigFactory<T> factory
+    ) {
+        factories.put(id, factory);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends ProfileSubConfig> ProfileSubConfigFactory<T> getFactory(String id) {
+        return (ProfileSubConfigFactory<T>) factories.get(id);
+    }
+
+    public static Set<String> getRegisteredIds() {
+        return factories.keySet();
+    }
+}

+ 25 - 0
src/main/java/me/lethunderhawk/profile/listener/JoinListener.java

@@ -0,0 +1,25 @@
+package me.lethunderhawk.profile.listener;
+
+import me.lethunderhawk.profile.ProfileManager;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+public class JoinListener implements Listener {
+
+    ProfileManager profileManager;
+    public JoinListener(ProfileManager profileManager) {
+        this.profileManager = profileManager;
+    }
+
+    @EventHandler
+    public void onPlayerQuit(PlayerQuitEvent event) {
+        profileManager.saveProfile(event.getPlayer().getUniqueId());
+    }
+
+    @EventHandler
+    public void onJoin(PlayerJoinEvent event) {
+        profileManager.loadProfile(event.getPlayer().getUniqueId());
+    }
+}

+ 91 - 0
src/main/java/me/lethunderhawk/profile/representation/FluxProfile.java

@@ -0,0 +1,91 @@
+package me.lethunderhawk.profile.representation;
+
+import me.lethunderhawk.profile.config.abstraction.PersistentConfig;
+import me.lethunderhawk.profile.config.abstraction.subconfig.ProfileSubConfig;
+import me.lethunderhawk.profile.config.abstraction.subconfig.ProfileSubConfigFactory;
+import me.lethunderhawk.profile.config.registry.ProfileModuleRegistry;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class FluxProfile implements PersistentConfig {
+
+    private final String playerUUID;
+
+    // key = subconfig id
+    private final Map<String, ProfileSubConfig> subConfigs = new HashMap<>();
+
+    public FluxProfile(String playerUUID) {
+        this.playerUUID = playerUUID;
+    }
+
+    /*
+     * Add a module dynamically.
+     */
+    public void addSubConfig(ProfileSubConfig subConfig) {
+        subConfigs.put(subConfig.getId(), subConfig);
+    }
+
+    /*
+     * Get module by type safely.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends ProfileSubConfig> T getSubConfig(String id, Class<T> type) {
+        return (T) subConfigs.get(id);
+    }
+
+    @Override
+    public void serialize(YamlConfiguration cfg) {
+
+        cfg.set("uuid", playerUUID);
+
+        for (ProfileSubConfig subConfig : subConfigs.values()) {
+
+            ConfigurationSection section =
+                    cfg.createSection(subConfig.getId());
+
+            subConfig.serialize(section);
+        }
+    }
+
+    public static FluxProfile deserialize(YamlConfiguration cfg) {
+
+        String uuid = cfg.getString("uuid");
+
+        if (uuid == null) {
+            throw new IllegalStateException("Profile file missing UUID.");
+        }
+
+        FluxProfile profile = new FluxProfile(uuid);
+
+        for (String id : ProfileModuleRegistry.getRegisteredIds()) {
+
+            if (!cfg.isConfigurationSection(id)) continue;
+
+            ConfigurationSection section = cfg.getConfigurationSection(id);
+
+            ProfileSubConfigFactory<?> factory =
+                    ProfileModuleRegistry.getFactory(id);
+
+            if (factory == null) continue;
+
+            ProfileSubConfig subConfig =
+                    factory.deserialize(section);
+
+            profile.addSubConfig(subConfig);
+        }
+
+        return profile;
+    }
+
+    @Override
+    public String getFileName() {
+        return playerUUID;
+    }
+
+    public String getPlayerUUID() {
+        return playerUUID;
+    }
+}

+ 1 - 1
src/main/resources/plugin.yml

@@ -1,4 +1,4 @@
-name: FluxAPI
+name: ${project.artifactId}
 version: ${project.version}
 main: me.lethunderhawk.main.FluxAPI
 api-version: 1.21.10