9
0
mirror of https://github.com/Xiao-MoMi/Custom-Nameplates.git synced 2026-01-06 15:42:00 +00:00

migration system

This commit is contained in:
XiaoMoMi
2024-01-24 03:30:02 +08:00
parent b43d2859f7
commit 60549ade96
41 changed files with 854 additions and 325 deletions

View File

@@ -32,6 +32,8 @@ dependencies {
compileOnly("com.github.LoneDev6:api-itemsadder:3.5.0c-r5")
compileOnly("io.th0rgal:oraxen:1.165.0")
compileOnly("com.github.FrancoBM12:API-MagicCosmetics:2.2.5")
compileOnly("commons-io:commons-io:2.15.1")
// chat channels
compileOnly(files("libs/VentureChat-3.7.1.jar"))

View File

@@ -17,7 +17,6 @@
package net.momirealms.customnameplates.paper;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.event.CustomNameplatesReloadEvent;
import net.momirealms.customnameplates.api.util.LogUtils;
@@ -42,13 +41,12 @@ import net.momirealms.customnameplates.paper.scheduler.SchedulerImpl;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import net.momirealms.customnameplates.paper.storage.StorageManagerImpl;
import net.momirealms.customnameplates.paper.util.Migration;
import net.momirealms.customnameplates.paper.util.ReflectionUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.io.File;
import java.util.TimeZone;
@@ -66,6 +64,11 @@ public class CustomNameplatesPluginImpl extends CustomNameplatesPlugin implement
@Override
public void onEnable() {
if (Migration.check()) {
LogUtils.warn("Please read /CustomNameplates/README.txt to finish the migration.");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
this.adventureManager = new AdventureManagerImpl(this);
this.versionManager = new VersionManagerImpl(this);
this.scheduler = new SchedulerImpl(this);
@@ -94,21 +97,21 @@ public class CustomNameplatesPluginImpl extends CustomNameplatesPlugin implement
@Override
public void onDisable() {
((SchedulerImpl) this.scheduler).shutdown();
((ActionBarManagerImpl) actionBarManager).unload();
((NameplateManagerImpl) this.nameplateManager).disable();
((TeamManagerImpl) this.teamManager).unload();
((BossBarManagerImpl) this.bossBarManager).unload();
((ImageManagerImpl) this.imageManager).unload();
((BackGroundManagerImpl) this.backGroundManager).unload();
((PlaceholderManagerImpl) this.placeholderManager).unload();
((BubbleManagerImpl) this.bubbleManager).unload();
((RequirementManagerImpl) this.requirementManager).unload();
((ResourcePackManagerImpl) this.resourcePackManager).unload();
((WidthManagerImpl) this.widthManager).unload();
((StorageManagerImpl) this.storageManager).disable();
((AdventureManagerImpl) this.adventureManager).close();
HandlerList.unregisterAll((VersionManagerImpl) versionManager);
if (scheduler != null) ((SchedulerImpl) this.scheduler).shutdown();
if (actionBarManager != null) ((ActionBarManagerImpl) actionBarManager).unload();
if (nameplateManager != null) ((NameplateManagerImpl) this.nameplateManager).disable();
if (teamManager != null) ((TeamManagerImpl) this.teamManager).unload();
if (bossBarManager != null) ((BossBarManagerImpl) this.bossBarManager).unload();
if (imageManager != null) ((ImageManagerImpl) this.imageManager).unload();
if (backGroundManager != null) ((BackGroundManagerImpl) this.backGroundManager).unload();
if (placeholderManager != null) ((PlaceholderManagerImpl) this.placeholderManager).unload();
if (bubbleManager != null) ((BubbleManagerImpl) this.bubbleManager).unload();
if (requirementManager != null) ((RequirementManagerImpl) this.requirementManager).unload();
if (resourcePackManager != null) ((ResourcePackManagerImpl) this.resourcePackManager).unload();
if (widthManager != null) ((WidthManagerImpl) this.widthManager).unload();
if (storageManager != null) ((StorageManagerImpl) this.storageManager).disable();
if (adventureManager != null) ((AdventureManagerImpl) this.adventureManager).close();
if (versionManager != null) HandlerList.unregisterAll((VersionManagerImpl) versionManager);
}
@Override
@@ -158,7 +161,7 @@ public class CustomNameplatesPluginImpl extends CustomNameplatesPlugin implement
"com.zaxxer:HikariCP:5.0.1", mavenRepo,
"org.mariadb.jdbc:mariadb-java-client:3.3.0", mavenRepo,
"com.mysql:mysql-connector-j:8.2.0", mavenRepo,
"commons-io:commons-io:2.14.0", mavenRepo,
"commons-io:commons-io:2.15.1", mavenRepo,
"com.google.code.gson:gson:2.10.1", mavenRepo,
"com.h2database:h2:2.2.224", mavenRepo,
"org.mongodb:mongodb-driver-sync:4.11.1", mavenRepo,

View File

@@ -17,6 +17,10 @@
package net.momirealms.customnameplates.paper.command;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import dev.jorel.commandapi.CommandAPI;
import dev.jorel.commandapi.CommandAPIBukkitConfig;
import dev.jorel.commandapi.CommandAPICommand;
@@ -25,21 +29,36 @@ import dev.jorel.commandapi.arguments.BooleanArgument;
import dev.jorel.commandapi.arguments.PlayerArgument;
import dev.jorel.commandapi.arguments.StringArgument;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.data.DataStorageInterface;
import net.momirealms.customnameplates.api.data.LegacyDataStorageInterface;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.api.util.CompletableFutures;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import net.momirealms.customnameplates.paper.storage.method.database.sql.MariaDBImpl;
import net.momirealms.customnameplates.paper.storage.method.database.sql.MySQLImpl;
import net.momirealms.customnameplates.paper.storage.method.file.YAMLImpl;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Optional;
import java.util.StringJoiner;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@SuppressWarnings("DuplicatedCode")
public class CommandManager {
@@ -57,7 +76,8 @@ public class CommandManager {
.withAliases("nameplates", "cnameplates")
.withSubcommands(
NameplatesCommands.getReloadCommand(),
NameplatesCommands.getAboutCommand()
NameplatesCommands.getAboutCommand(),
NameplatesCommands.getDataCommand()
);
if (CNConfig.nameplateModule) {
command1.withSubcommands(
@@ -332,5 +352,191 @@ public class CommandManager {
AdventureManagerImpl.getInstance().sendMessage(sender, "<#FFD700>⭐ <click:open_url:https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates>Document</click> <#A9A9A9>| <#FAFAD2>⛏ <click:open_url:https://github.com/Xiao-MoMi/Custom-Nameplates>Github</click> <#A9A9A9>| <#48D1CC>\uD83D\uDD14 <click:open_url:https://polymart.org/resource/customnameplates.2543>Polymart</click>");
});
}
public static CommandAPICommand getDataCommand() {
return new CommandAPICommand("data")
.withPermission("customnameplates.admin")
.withSubcommands(
new CommandAPICommand("export")
.executes((sender, args) -> {
CustomNameplatesPlugin plugin = CustomNameplatesPlugin.get();
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>export</aqua>.");
DataStorageInterface dataStorageInterface = plugin.getStorageManager().getDataSource();
Set<UUID> uuids = dataStorageInterface.getUniqueUsers(false);
Set<CompletableFuture<Void>> futures = new HashSet<>();
AtomicInteger userCount = new AtomicInteger(0);
Map<UUID, String> out = Collections.synchronizedMap(new TreeMap<>());
int amount = uuids.size();
for (UUID uuid : uuids) {
futures.add(dataStorageInterface.getPlayerData(uuid).thenAccept(it -> {
if (it.isPresent()) {
out.put(uuid, plugin.getStorageManager().toJson(it.get()));
userCount.incrementAndGet();
}
}));
}
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
while (true) {
try {
overallFuture.get(3, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
break;
} catch (TimeoutException e) {
LogUtils.info("Progress: " + userCount.get() + "/" + amount);
continue;
}
break;
}
JsonObject outJson = new JsonObject();
for (Map.Entry<UUID, String> entry : out.entrySet()) {
outJson.addProperty(entry.getKey().toString(), entry.getValue());
}
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
String formattedDate = formatter.format(new Date());
File outFile = new File(plugin.getDataFolder(), "exported-" + formattedDate + ".json.gz");
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(outFile.toPath())), StandardCharsets.UTF_8))) {
new GsonBuilder().disableHtmlEscaping().create().toJson(outJson, writer);
} catch (IOException e) {
e.printStackTrace();
}
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
}),
new CommandAPICommand("export-legacy")
.withArguments(new StringArgument("method")
.replaceSuggestions(ArgumentSuggestions.strings("MySQL", "MariaDB", "YAML")))
.executes((sender, args) -> {
String arg = (String) args.get("method");
if (arg == null) return;
CustomNameplatesPlugin plugin = CustomNameplatesPlugin.get();
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>export</aqua>.");
LegacyDataStorageInterface dataStorageInterface;
switch (arg) {
case "MySQL" -> dataStorageInterface = new MySQLImpl(plugin);
case "MariaDB" -> dataStorageInterface = new MariaDBImpl(plugin);
case "YAML" -> dataStorageInterface = new YAMLImpl(plugin);
default -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "No such legacy storage method.");
return;
}
}
dataStorageInterface.initialize();
Set<UUID> uuids = dataStorageInterface.getUniqueUsers(true);
Set<CompletableFuture<Void>> futures = new HashSet<>();
AtomicInteger userCount = new AtomicInteger(0);
Map<UUID, String> out = Collections.synchronizedMap(new TreeMap<>());
for (UUID uuid : uuids) {
futures.add(dataStorageInterface.getLegacyPlayerData(uuid).thenAccept(it -> {
if (it.isPresent()) {
out.put(uuid, plugin.getStorageManager().toJson(it.get()));
userCount.incrementAndGet();
}
}));
}
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
while (true) {
try {
overallFuture.get(3, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
break;
} catch (TimeoutException e) {
LogUtils.info("Progress: " + userCount.get() + "/" + uuids.size());
continue;
}
break;
}
JsonObject outJson = new JsonObject();
for (Map.Entry<UUID, String> entry : out.entrySet()) {
outJson.addProperty(entry.getKey().toString(), entry.getValue());
}
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
String formattedDate = formatter.format(new Date());
File outFile = new File(plugin.getDataFolder(), "exported-" + formattedDate + ".json.gz");
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(outFile.toPath())), StandardCharsets.UTF_8))) {
new GsonBuilder().disableHtmlEscaping().create().toJson(outJson, writer);
} catch (IOException e) {
e.printStackTrace();
}
dataStorageInterface.disable();
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
})
,
new CommandAPICommand("import")
.withArguments(new StringArgument("file"))
.executes((sender, args) -> {
String fileName = (String) args.get("file");
if (fileName == null) return;
CustomNameplatesPlugin plugin = CustomNameplatesPlugin.get();
File file = new File(plugin.getDataFolder(), fileName);
if (!file.exists()) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "File not exists.");
return;
}
if (!file.getName().endsWith(".json.gz")) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Invalid file.");
return;
}
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>import</aqua>.");
JsonObject data;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(Files.newInputStream(file.toPath())), StandardCharsets.UTF_8))) {
data = new GsonBuilder().disableHtmlEscaping().create().fromJson(reader, JsonObject.class);
} catch (IOException e) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Error occurred when reading the backup file.");
e.printStackTrace();
return;
}
DataStorageInterface dataStorageInterface = plugin.getStorageManager().getDataSource();
var entrySet = data.entrySet();
int amount = entrySet.size();
AtomicInteger userCount = new AtomicInteger(0);
Set<CompletableFuture<Void>> futures = new HashSet<>();
for (Map.Entry<String, JsonElement> entry : entrySet) {
UUID uuid = UUID.fromString(entry.getKey());
if (entry.getValue() instanceof JsonPrimitive primitive) {
PlayerData playerData = plugin.getStorageManager().fromJson(primitive.getAsString());
futures.add(dataStorageInterface.updateOrInsertPlayerData(uuid, playerData).thenAccept(it -> userCount.incrementAndGet()));
}
}
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
while (true) {
try {
overallFuture.get(3, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
break;
} catch (TimeoutException e) {
LogUtils.info("Progress: " + userCount.get() + "/" + amount);
continue;
}
break;
}
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
})
);
}
}
}

View File

@@ -109,7 +109,7 @@ public class ActionBarManagerImpl implements ActionBarManager, Listener {
if (!(barEntry.getValue() instanceof ConfigurationSection section))
return;
this.config = ActionBarConfig.Builder.of()
this.config = ActionBarConfig.builder()
.checkFrequency(section.getInt("check-frequency", 10))
.requirement(plugin.getRequirementManager().getRequirements(section.getConfigurationSection("conditions")))
.displayOrder(ConfigUtils.getTimeLimitTexts(section.getConfigurationSection("text-display-order")))

View File

@@ -19,13 +19,15 @@ package net.momirealms.customnameplates.paper.mechanic.bubble;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.event.BubblesSpawnEvent;
import net.momirealms.customnameplates.api.event.NameplateDataLoadEvent;
import net.momirealms.customnameplates.api.manager.BubbleManager;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import net.momirealms.customnameplates.api.mechanic.character.CharacterArranger;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.nameplate.CachedNameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.EntityTagPlayer;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.StaticTextEntity;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.StaticTextTagSetting;
@@ -45,6 +47,8 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.PluginManager;
import org.bukkit.potion.PotionEffectType;
@@ -308,6 +312,22 @@ public class BubbleManagerImpl implements BubbleManager {
return result;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onDataLoaded(NameplateDataLoadEvent event) {
OnlineUser data = event.getOnlineUser();
String bubble = data.getBubbleKey();
if (!bubble.equals("none") && !containsBubble(bubble)) {
if (bubble.equals(defaultBubble)) {
LogUtils.severe("Default nameplate doesn't exist");
return;
}
LogUtils.severe("Bubble " + bubble + " doesn't exist. To prevent bugs, player " + event.getUUID() + " 's bubble data is reset");
data.setBubble("none");
plugin.getStorageManager().saveOnlinePlayerData(event.getUUID());
}
}
@Override
public Collection<String> getBubbleKeys() {
return bubbleMap.keySet();
@@ -356,6 +376,11 @@ public class BubbleManagerImpl implements BubbleManager {
return bubbleMap.values();
}
@Override
public boolean containsBubble(String key) {
return bubbleMap.containsKey(key);
}
@Override
public boolean equipBubble(Player player, String bubbleKey) {
Bubble bubble = getBubble(bubbleKey);

View File

@@ -17,15 +17,12 @@
package net.momirealms.customnameplates.paper.mechanic.image;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.manager.ImageManager;
import net.momirealms.customnameplates.api.mechanic.character.CharacterArranger;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.util.ImageUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;

View File

@@ -19,22 +19,15 @@ package net.momirealms.customnameplates.paper.mechanic.nameplate.tag.team;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedDataValue;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.google.common.collect.Lists;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.scheduler.CancellableTask;
import net.momirealms.customnameplates.common.team.TeamColor;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.misc.PacketManager;
import net.momirealms.customnameplates.paper.util.FakeEntityUtils;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

View File

@@ -32,7 +32,6 @@ import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.util.ConfigUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.codehaus.plexus.util.FileUtils;
@@ -44,7 +43,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class ResourcePackManagerImpl implements ResourcePackManager {
@@ -263,11 +261,6 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
e.printStackTrace();
}
}
if (!CNConfig.legacyUnicodes) {
return;
}
for (int ascent : ascentUnicodes) {
String line;
StringBuilder sb = new StringBuilder();
@@ -581,7 +574,7 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
public static final String Animated_Text_FSH =
"\n" +
"vec2 p1 = round(pos1 / (posID == 0 ? 1 - coord.x : 1 - coord.y));\n" +
" vec2 p1 = round(pos1 / (posID == 0 ? 1 - coord.x : 1 - coord.y));\n" +
" vec2 p2 = round(pos2 / (posID == 0 ? coord.y : coord.x));\n" +
" ivec2 resolution = ivec2(abs(p1 - p2));\n" +
" ivec2 corner = ivec2(min(p1, p2));\n" +

View File

@@ -26,7 +26,6 @@ import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.placeholder.*;
import net.momirealms.customnameplates.api.util.FontUtils;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

View File

@@ -38,7 +38,7 @@ import java.util.Objects;
public class CNConfig {
public static String configVersion = "22";
public static String configVersion = "23";
public static int cacheSize;
public static int corePoolSize;
public static long keepAliveTime;

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.paper.storage;
import net.momirealms.customnameplates.api.data.PlayerData;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface DataStorageInterface {
/**
* Initialize the data resource
*/
void initialize();
/**
* Close the data resource
*/
void disable();
/**
* Get the storage data source type
*
* @return {@link StorageType}
*/
StorageType getStorageType();
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData);
}

View File

@@ -20,10 +20,13 @@ package net.momirealms.customnameplates.paper.storage;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import net.momirealms.customnameplates.api.data.DataStorageInterface;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.event.NameplateDataLoadEvent;
import net.momirealms.customnameplates.api.manager.StorageManager;
import net.momirealms.customnameplates.api.scheduler.CancellableTask;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.storage.method.database.nosql.MongoDBImpl;
@@ -36,6 +39,7 @@ import net.momirealms.customnameplates.paper.storage.method.file.JsonImpl;
import net.momirealms.customnameplates.paper.storage.method.file.YAMLImpl;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
@@ -50,6 +54,7 @@ import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* This class implements the StorageManager interface and is responsible for managing player data storage.
@@ -112,7 +117,19 @@ public class StorageManagerImpl implements Listener, StorageManager {
if (onlineUser != null) {
return CompletableFuture.completedFuture(Optional.of(onlineUser.toPlayerData()));
}
return dataSource.getPlayerData(uuid);
if (hasRedis) {
return redisManager.getPlayerData(uuid).thenCompose(
result -> {
if (result.isEmpty()) {
return dataSource.getPlayerData(uuid);
} else {
return CompletableFuture.completedFuture(result);
}
}
);
} else {
return dataSource.getPlayerData(uuid);
}
}
@Override
@@ -121,12 +138,23 @@ public class StorageManagerImpl implements Listener, StorageManager {
if (onlineUser == null) {
return CompletableFuture.completedFuture(false);
}
return dataSource.updatePlayerData(uuid, onlineUser.toPlayerData());
return savePlayerData(uuid, onlineUser.toPlayerData());
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData) {
return dataSource.updatePlayerData(uuid, playerData);
if (hasRedis) {
return redisManager.updatePlayerData(uuid, playerData).thenCompose(
result -> {
if (!result) {
return CompletableFuture.completedFuture(false);
}
return dataSource.updatePlayerData(uuid, playerData);
}
);
} else {
return dataSource.updatePlayerData(uuid, playerData);
}
}
@Override
@@ -228,6 +256,11 @@ public class StorageManagerImpl implements Listener, StorageManager {
return gson.toJson(playerData);
}
@Override
public DataStorageInterface getDataSource() {
return dataSource;
}
/**
* Custom exception class for data serialization errors.
*/

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.paper.storage;
public enum StorageType {
JSON,
YAML,
H2,
SQLite,
MySQL,
MariaDB,
MongoDB,
Redis
}

View File

@@ -18,7 +18,11 @@
package net.momirealms.customnameplates.paper.storage.method;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.storage.DataStorageInterface;
import net.momirealms.customnameplates.api.data.DataStorageInterface;
import net.momirealms.customnameplates.api.data.PlayerData;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* An abstract class that implements the DataStorageInterface and provides common functionality for data storage.
@@ -40,4 +44,10 @@ public abstract class AbstractStorage implements DataStorageInterface {
public void disable() {
// This method can be overridden in subclasses to perform cleanup or shutdown tasks specific to the storage type.
}
@Override
public CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData) {
// By default, delegate to the updatePlayerData method to update or insert player data.
return updatePlayerData(uuid, playerData);
}
}

View File

@@ -18,18 +18,16 @@
package net.momirealms.customnameplates.paper.storage.method.database.nosql;
import com.mongodb.*;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.paper.storage.method.AbstractStorage;
import org.bson.Document;
import org.bson.UuidRepresentation;
@@ -39,9 +37,7 @@ import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
@@ -145,6 +141,30 @@ public class MongoDBImpl extends AbstractStorage {
return future;
}
/**
* Get a set of unique player UUIDs from the MongoDB database.
*
* @param legacy Flag indicating whether to retrieve legacy data.
* @return A set of unique player UUIDs.
*/
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
// no legacy files
Set<UUID> uuids = new HashSet<>();
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
try {
Bson projectionFields = Projections.fields(Projections.include("uuid"));
try (MongoCursor<Document> cursor = collection.find().projection(projectionFields).iterator()) {
while (cursor.hasNext()) {
uuids.add(cursor.next().get("uuid", UUID.class));
}
}
} catch (MongoException e) {
LogUtils.warn("Failed to get unique data.", e);
}
return uuids;
}
/**
* Get the collection name for a specific subcategory of data.
*

View File

@@ -18,9 +18,9 @@
package net.momirealms.customnameplates.paper.storage.method.database.nosql;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.paper.storage.method.AbstractStorage;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -32,7 +32,9 @@ import redis.clients.jedis.exceptions.JedisException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -71,6 +73,11 @@ public class RedisManager extends AbstractStorage {
return jedisPool.getResource();
}
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
return new HashSet<>();
}
/**
* Initialize the Redis connection and configuration based on the plugin's YAML configuration.
*/
@@ -87,7 +94,7 @@ public class RedisManager extends AbstractStorage {
jedisPoolConfig.setTestWhileIdle(true);
jedisPoolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(30000));
jedisPoolConfig.setNumTestsPerEvictionRun(-1);
jedisPoolConfig.setMinEvictableIdleTime(Duration.ofMillis(section.getInt("MinEvictableIdleTimeMillis",1800000)));
jedisPoolConfig.setMinEvictableIdleDuration(Duration.ofMillis(section.getInt("MinEvictableIdleTimeMillis", 1800000)));
jedisPoolConfig.setMaxTotal(section.getInt("MaxTotal",8));
jedisPoolConfig.setMaxIdle(section.getInt("MaxIdle",8));
jedisPoolConfig.setMinIdle(section.getInt("MinIdle",1));
@@ -168,7 +175,7 @@ public class RedisManager extends AbstractStorage {
try (Jedis jedis = jedisPool.getResource()) {
jedis.setex(
getRedisKey("cn_data", uuid),
300,
600,
plugin.getStorageManager().toBytes(playerData)
);
future.complete(true);

View File

@@ -20,21 +20,24 @@ package net.momirealms.customnameplates.paper.storage.method.database.sql;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.data.LegacyDataStorageInterface;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.storage.StorageType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
* An abstract base class for SQL databases using the HikariCP connection pool, which handles player data storage.
*/
public abstract class AbstractHikariDatabase extends AbstractSQLDatabase {
public abstract class AbstractHikariDatabase extends AbstractSQLDatabase implements LegacyDataStorageInterface {
private HikariDataSource dataSource;
private final String driverClass;
@@ -117,6 +120,30 @@ public abstract class AbstractHikariDatabase extends AbstractSQLDatabase {
super.createTableIfNotExist();
}
@Override
public CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid) {
var future = new CompletableFuture<Optional<PlayerData>>();
String sql = String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("data"));
try (Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, uuid.toString());
ResultSet rs = statement.executeQuery();
if (rs.next()) {
String nameplate = rs.getString(2);
String bubbles = rs.getString(3);
future.complete(Optional.of(PlayerData.builder()
.setBubble(bubbles)
.setNameplate(nameplate)
.build()));
} else {
future.complete(Optional.empty());
}
} catch (SQLException e) {
e.printStackTrace();
}
return future;
}
/**
* Disable the database by closing the connection pool.
*/

View File

@@ -28,10 +28,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
@@ -73,6 +70,36 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
}
}
/**
* Update or insert a player's data into the SQL database.
*
* @param uuid The UUID of the player.
* @param playerData The player data to update or insert.
* @return A CompletableFuture indicating the success of the operation.
*/
@Override
public CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
try (
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("data")))
) {
statement.setString(1, uuid.toString());
ResultSet rs = statement.executeQuery();
if (rs.next()) {
updatePlayerData(uuid, playerData).thenRun(() -> future.complete(true));
} else {
insertPlayerData(uuid, playerData);
future.complete(true);
}
} catch (SQLException e) {
LogUtils.warn("Failed to update " + uuid + "'s data.", e);
}
});
return future;
}
/**
* Get the SQL schema from a resource file.
*
@@ -177,6 +204,29 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
}
}
/**
* Get a set of unique user UUIDs from the SQL database.
*
* @param legacy Whether to include legacy data in the retrieval.
* @return A set of unique user UUIDs.
*/
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
Set<UUID> uuids = new HashSet<>();
try (Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_ALL_UUID, legacy ? getTableName("fishingbag") : getTableName("data")))) {
try (ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
UUID uuid = UUID.fromString(rs.getString("uuid"));
uuids.add(uuid);
}
}
} catch (SQLException e) {
LogUtils.warn("Failed to get unique data.", e);
}
return uuids;
}
/**
* Constants defining SQL statements used for database operations.
*/

View File

@@ -18,7 +18,7 @@
package net.momirealms.customnameplates.paper.storage.method.database.sql;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.api.data.StorageType;
import org.bukkit.configuration.file.YamlConfiguration;
import org.h2.jdbcx.JdbcConnectionPool;

View File

@@ -18,7 +18,7 @@
package net.momirealms.customnameplates.paper.storage.method.database.sql;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.api.data.StorageType;
public class MariaDBImpl extends AbstractHikariDatabase {

View File

@@ -18,7 +18,7 @@
package net.momirealms.customnameplates.paper.storage.method.database.sql;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.api.data.StorageType;
public class MySQLImpl extends AbstractHikariDatabase {

View File

@@ -19,8 +19,8 @@ package net.momirealms.customnameplates.paper.storage.method.database.sql;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.storage.StorageType;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.sqlite.SQLiteConfig;

View File

@@ -19,8 +19,8 @@ package net.momirealms.customnameplates.paper.storage.method.file;
import com.google.gson.Gson;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.paper.storage.method.AbstractStorage;
import org.bukkit.Bukkit;
@@ -29,7 +29,9 @@ import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -125,4 +127,21 @@ public class JsonImpl extends AbstractStorage {
this.saveToJsonFile(playerData, getPlayerDataFile(uuid));
return CompletableFuture.completedFuture(true);
}
// Retrieve a set of unique user UUIDs based on JSON data files in the 'data' folder.
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
// No legacy files
File folder = new File(plugin.getDataFolder(), "data");
Set<UUID> uuids = new HashSet<>();
if (folder.exists()) {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
uuids.add(UUID.fromString(file.getName().substring(file.getName().length() - 5)));
}
}
}
return uuids;
}
}

View File

@@ -17,27 +17,30 @@
package net.momirealms.customnameplates.paper.storage.method.file;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.data.LegacyDataStorageInterface;
import net.momirealms.customnameplates.api.data.PlayerData;
import net.momirealms.customnameplates.api.data.StorageType;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.storage.StorageType;
import net.momirealms.customnameplates.paper.storage.method.AbstractStorage;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* A data storage implementation that uses YAML files to store player data, with support for legacy data.
*/
public class YAMLImpl extends AbstractStorage {
public class YAMLImpl extends AbstractStorage implements LegacyDataStorageInterface {
@SuppressWarnings("ResultOfMethodCallIgnored")
public YAMLImpl(CustomNameplatesPluginImpl plugin) {
public YAMLImpl(CustomNameplatesPlugin plugin) {
super(plugin);
File folder = new File(plugin.getDataFolder(), "data");
if (!folder.exists()) folder.mkdirs();
@@ -102,4 +105,35 @@ public class YAMLImpl extends AbstractStorage {
}
return CompletableFuture.completedFuture(true);
}
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
File folder;
if (legacy) {
folder = new File(plugin.getDataFolder(), "player_data");
} else {
folder = new File(plugin.getDataFolder(), "data");
}
Set<UUID> uuids = new HashSet<>();
if (folder.exists()) {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
uuids.add(UUID.fromString(file.getName().substring(0, file.getName().length() - 4)));
}
}
}
return uuids;
}
@Override
public CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid) {
File dataFile = new File(plugin.getDataFolder(), "player_data" + File.separator + uuid + ".yml");
YamlConfiguration data = readData(dataFile);
PlayerData playerData = new PlayerData.Builder()
.setBubble(data.getString("bubbles", ""))
.setNameplate(data.getString("nameplate", ""))
.build();
return CompletableFuture.completedFuture(Optional.of(playerData));
}
}

View File

@@ -33,4 +33,21 @@ public class ImageUtils {
e.printStackTrace();
}
}
public static void setAnimatedImage(File file, int frames) {
try {
BufferedImage inputImage = ImageIO.read(file);
int width = inputImage.getWidth();
int height = inputImage.getHeight();
int frameHeight = height / frames;
BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int newPixel = (1 << 24) | (10 << 16) | (width << 8) | frameHeight;
for (int i = 0; i < frames; i++) {
outputImage.setRGB(0, frameHeight * i, newPixel);
}
ImageIO.write(outputImage, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,211 @@
package net.momirealms.customnameplates.paper.util;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.util.LogUtils;
import org.apache.commons.io.FileUtils;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class Migration {
public static boolean check() {
File readMe = new File(CustomNameplatesPlugin.get().getDataFolder(), "README.text");
if (readMe.exists()) {
return true;
}
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "config.yml");
if (!file.exists()) {
return false;
}
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
boolean version = config.contains("other-settings.default-character-width");
if (!version) {
return false;
}
config.set("other-settings.default-character-width", null);
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
CustomNameplatesPlugin.get().saveResource("README.txt", true);
updateBossBar();
updateActionBar();
updateBubble();
updateNameplate();
updateCustomPlaceholders();
deleteFiles();
return true;
}
private static void deleteFiles() {
try {
FileUtils.delete(new File(CustomNameplatesPlugin.get().getDataFolder(), "database.yml"));
FileUtils.deleteDirectory(new File(CustomNameplatesPlugin.get().getDataFolder(), "unicodes"));
FileUtils.deleteDirectory(new File(CustomNameplatesPlugin.get().getDataFolder(), "templates"));
FileUtils.deleteDirectory(new File(CustomNameplatesPlugin.get().getDataFolder(), "ResourcePack"));
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateBossBar() {
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "configs" + File.separator + "bossbar.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> entry : config.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection section) {
section.set("check-frequency", 1);
int refresh = section.getInt("refresh-rate");
if (section.contains("text")) {
String text = section.getString("text");
section.set("text-display-order.1.duration", 1000);
section.set("text-display-order.1.refresh-frequency", refresh);
section.set("text-display-order.1.text", text);
} else if (section.contains("dynamic-text")) {
int switchInt = section.getInt("switch-interval", 15) * 20;
int i = 0;
for (String text : section.getStringList("dynamic-text")) {
i++;
section.set("text-display-order."+i+".duration", switchInt);
section.set("text-display-order."+i+".refresh-frequency", refresh);
section.set("text-display-order."+i+".text", text);
}
}
section.set("switch-interval", null);
section.set("dynamic-text", null);
section.set("refresh-rate", null);
section.set("text", null);
}
}
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateActionBar() {
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "configs" + File.separator + "actionbar.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> entry : config.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection section) {
String text = section.getString("text", "");
section.set("text", null);
section.set("check-frequency", 1);
section.set("text-display-order.1.text", text);
section.set("text-display-order.1.refresh-frequency", 1);
section.set("text-display-order.1.duration", 1000);
}
}
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateBubble() {
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "configs" + File.separator + "bubble.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
config.set("mode", null);
config.set("text-display-options", null);
config.set("default-bubble", config.getString("default-bubbles","none"));
config.set("default-bubbles", null);
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateNameplate() {
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "configs" + File.separator + "nameplate.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
String mode = config.getString("mode","");
if (!mode.equalsIgnoreCase("team")) {
config.set("mode", "Unlimited");
}
config.set("nameplate.player-name", config.getString("player-name","%player_name%"));
config.set("nameplate.refresh-frequency", 10);
config.set("nameplate.prefix", config.getString("prefix", ""));
config.set("nameplate.prefix", config.getString("suffix",""));
if (mode.equalsIgnoreCase("team")) {
config.createSection("unlimited");
ConfigurationSection section = config.createSection("team");
section.set("refresh-frequency", 20);
section.set("prefix", "");
section.set("suffix", "");
} else {
ConfigurationSection old;
if (mode.equalsIgnoreCase("armor_stand")) {
old = config.getConfigurationSection("armor_stand");
} else if (mode.equalsIgnoreCase("text_display")) {
old = config.getConfigurationSection("text_display");
} else {
LogUtils.severe("No mode is set for nameplate. Failed to migrate!");
return;
}
ConfigurationSection newSection = config.createSection("unlimited", old.getValues(false));
for (Map.Entry<String, Object> entry : newSection.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
ConfigurationSection conditions = inner.getConfigurationSection("conditions");
if (conditions != null) {
inner.createSection("owner-conditions", conditions.getValues(false));
inner.createSection("viewer-conditions");
}
}
}
}
try {
config.set("player-name", null);
config.set("prefix", null);
config.set("suffix", null);
config.set("hide-prefix-when-equipping-nameplate", null);
config.set("hide-suffix-when-equipping-nameplate", null);
config.set("create-fake-team", null);
config.set("text_display", null);
config.set("armor_stand", null);
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateCustomPlaceholders() {
File file = new File(CustomNameplatesPlugin.get().getDataFolder(), "configs" + File.separator + "custom-placeholders.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
config.createSection("switch-text");
ConfigurationSection descentTSection = config.getConfigurationSection("descent-text");
ConfigurationSection descentUSection = config.getConfigurationSection("descent-unicode");
if (descentTSection != null && descentUSection != null) {
for (Map.Entry<String, Object> entry : descentUSection.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
String text = inner.getString("text");
int descent = inner.getInt("descent");
ConfigurationSection newSection;
if (descentTSection.contains(entry.getKey())) {
newSection = descentTSection.createSection(entry.getKey() + "_");
LogUtils.warn("Duplicated key '" + entry.getKey() + "' found during migration. Please manually fix that.");
} else {
newSection = descentTSection.createSection(entry.getKey());
}
newSection.set("text", text);
newSection.set("descent", descent);
newSection.set("is-unicode", true);
}
}
}
config.set("descent-unicode", null);
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,3 @@
Hi! It seems that you are updating the plugin from 2.2 to 2.3.
Please read this and follow the guide to update your configs
https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/2.2-to-2.3-migration-guide

View File

@@ -1,5 +1,5 @@
# Do not change
config-version: '22'
config-version: '23'
# Debug mode
debug: false

View File

@@ -1,6 +1,6 @@
# You can only create "actionbar" section in this config file
# Player can only receive at most 1 actionbar at the same time
actionbar:
check-frequency: 1
check-frequency: 10
conditions:
permission: "actionbar.show"
text-display-order:

View File

@@ -4,7 +4,7 @@ blacklist-channels:
- Staff
# Default bubble to display if player's bubble is "none"
default-bubbles: 'chat'
default-bubble: 'chat'
# Text format when bubble is "none"
default-format:

View File

@@ -1,7 +1,7 @@
conditional-text:
actionbar:
priority_1:
text: '%nameplates_background_actionbar%'
text: '%nameplates_background_other_actionbar%'
conditions:
'!=':
value1: '%player_remaining_air%'
@@ -122,9 +122,4 @@ vanilla-hud:
full: stamina_2
placeholder:
value: '1.1'
max-value: '2'
cached-text:
cached:
text: '%super_complex_javascript%'
refresh-interval: 10000
max-value: '2'

View File

@@ -28,14 +28,16 @@ unlimited:
tag_1:
text: '%nameplates_nametag%'
vertical-offset: -1
owner-conditions: { }
owner-conditions:
potion-effect: "INVISIBILITY=0"
viewer-conditions: { }
tag_2:
text: "IP: %player_ip% My IP: %viewer_player_ip%"
vertical-offset: -0.7
refresh-frequency: 10
check-frequency: 20
owner-conditions: { }
owner-conditions:
potion-effect: "INVISIBILITY=0"
viewer-conditions:
condition_1:
type: permission