diff --git a/.github/ISSUE_TEMPLATE/bug-report-cn.yml b/.github/ISSUE_TEMPLATE/bug-report-cn.yml index 2b4a562c6..39f9fc7ad 100644 --- a/.github/ISSUE_TEMPLATE/bug-report-cn.yml +++ b/.github/ISSUE_TEMPLATE/bug-report-cn.yml @@ -24,7 +24,7 @@ body: required: false - label: 你没有对下载的文件内容进行任何更改 required: true - - label: 你已经寻找过[已知问题列表](https://github.com/ybw0014/GuizhanSlimefunAddon/issues),且没有找到相同的问题 + - label: 你已经寻找过[已知问题列表](https://github.com/ybw0014/SlimefunTranslation/issues),且没有找到相同的问题 required: true - type: textarea @@ -126,4 +126,4 @@ body: 只需填写Build后面的数字版本即可 (`Build 7 zh-CN(ybw0014) (git 9ef7fee)`只需填写`7`即可) validations: - required: true \ No newline at end of file + required: true diff --git a/.github/ISSUE_TEMPLATE/bug-report-en.yml b/.github/ISSUE_TEMPLATE/bug-report-en.yml index f2f566ed0..d5022532a 100644 --- a/.github/ISSUE_TEMPLATE/bug-report-en.yml +++ b/.github/ISSUE_TEMPLATE/bug-report-en.yml @@ -8,7 +8,7 @@ body: attributes: value: | ## Welcome to Bug Tracker - Please take a look at [How to report bugs](https://github.com/Slimefun/Slimefun4/wiki/How-to-report-bugs) and [existing Issues](https://github.com/ybw0014/GuizhanSlimefunAddon/issues). + Please take a look at [How to report bugs](https://github.com/Slimefun/Slimefun4/wiki/How-to-report-bugs) and [existing Issues](https://github.com/ybw0014/SlimefunTranslation/issues). Fields marked with an asterisk (*) are required. diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 2bce46a94..990810548 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,11 +13,11 @@ jobs: if: startsWith(github.event.head_commit.message, '[CI skip]') == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set up JDK 16 - uses: actions/setup-java@v3.11.0 + uses: actions/setup-java@v4 with: - java-version: 16 + java-version: 17 distribution: temurin - name: Build with Maven run: mvn package --file pom.xml diff --git a/LICENSE b/LICENSE index 07e921d3d..839434228 100644 --- a/LICENSE +++ b/LICENSE @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - GuizhanSlimefunAddon Copyright (C) 2022 ybw0014 + SlimefunTranslation Copyright (C) 2023 ybw0014 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/README.md b/README.md new file mode 100644 index 000000000..180f0df26 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# SlimefunTranslation + +[English](./README.md) | [简体中文](./README.zh-CN.md) + +A [Slimefun4](https://github.com/Slimefun/Slimefun4) addon that translates Slimefun items (also supports addons). It does not modify the actual item, instead modifying the packets. The display language will be based on player's Slimefun language setting. + +## Download + +### Dependencies + +- [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) is required dependency. You may need to download the development version if you are on 1.20+. +- [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/) is optional dependency. It is required if you want to use placeholders in the translation. + +### Blob Builds + +Blob Builds (official builds page for Slimefun and addons): [Click to go](https://blob.build/project/SlimefunTranslation/Dev) + +### Guizhan Builds + +Guizhan Builds (my own builds page, all my addons are also available there): + +[![Build Status](https://builds.guizhanss.com/api/badge/ybw0014/SlimefunTranslation/master/latest)](https://builds.guizhanss.com/ybw0014/SlimefunTranslation/master) + +## Wiki + +For usage and more information, please visit our [Wiki](https://docs.ybw0014.dev/slimefuntranslation/). diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 000000000..24dac1378 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,17 @@ +# SlimefunTranslation 粘液翻译 + +[English](./README.md) | [简体中文](./README.zh-CN.md) + +A [Slimefun4](https://github.com/Slimefun/Slimefun4) addon that translates Slimefun items (also supports addons). It does not modify the actual item, instead modifying the packets. The display language will be based on player's Slimefun language setting. + +## Download + +[ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) is required dependency. You may need to download the development version if you are on 1.20+. + +Click the image below to download SlimefunTranslation: + +[![Build Status](https://builds.guizhanss.com/api/badge/ybw0014/SlimefunTranslation/master/latest)](https://builds.guizhanss.com/ybw0014/SlimefunTranslation/master) + +## Wiki + +For usage and more information, please visit our [Wiki](https://docs.ybw0014.dev/slimefuntranslation/). diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..667b629d2 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,4 @@ +files: + - source: /src/main/resources/languages/en/*.yml + translation: /src/main/resources/languages/%osx_locale%/%original_file_name% + diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 000000000..3dcd4f738 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,6 @@ +before_install: + - sdk install java 17.0.1-open + - sdk use java 17.0.1-open + +jdk: + - openjdk17 diff --git a/pom.xml b/pom.xml index 9a83b9a74..a1a54ebd0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 net.guizhanss - GuizhanSlimefunAddon + SlimefunTranslation UNOFFICIAL jar @@ -45,7 +45,7 @@ org.bstats - net.guizhanss.guizhanslimefunaddon.bstats + net.guizhanss.slimefuntranslation.bstats @@ -77,6 +77,10 @@ jitpack.io https://jitpack.io + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + @@ -88,9 +92,9 @@ - io.github.Slimefun + com.github.Slimefun Slimefun4 - RC-34 + bbfb9734b9 provided @@ -103,7 +107,7 @@ org.bstats bstats-bukkit - 3.0.0 + 3.0.1 compile @@ -116,8 +120,15 @@ net.guizhanss - GuizhanLibPlugin - 1.3.1 + GuizhanLib-api + 1.7.0-SNAPSHOT + compile + + + + com.comphenix.protocol + ProtocolLib + 4.7.0 provided diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..ec83b8bdf --- /dev/null +++ b/renovate.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base", + ":disableDependencyDashboard" + ] +} diff --git a/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java b/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java deleted file mode 100644 index a7b673999..000000000 --- a/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.guizhanss.guizhanslimefunaddon; - -import java.io.File; -import java.lang.reflect.Method; -import java.util.logging.Level; - -import org.bukkit.plugin.Plugin; - -import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater; - -import net.guizhanss.guizhanlib.slimefun.addon.AbstractAddon; -import net.guizhanss.guizhanlib.updater.GuizhanBuildsUpdater; - -import org.bstats.bukkit.Metrics; - -public final class GuizhanSlimefunAddon extends AbstractAddon { - - public GuizhanSlimefunAddon() { - super("ybw0014", "GuizhanSlimefunAddon", "master", "auto-update"); - } - - @Override - public void enable() { - log(Level.INFO, "===================="); - log(Level.INFO, "GuizhanSlimefunAddon"); - log(Level.INFO, " by ybw0014 "); - log(Level.INFO, "===================="); - } - - @Override - public void disable() { - } - - private void setupMetrics() { - new Metrics(this, 114514); - } - - @Override - protected void autoUpdate() { - if (getPluginVersion().startsWith("DEV")) { - String path = getGithubUser() + "/" + getGithubRepo() + "/" + getGithubBranch(); - new GitHubBuildsUpdater(this, getFile(), path).start(); - } else if (getPluginVersion().startsWith("Build")) { - try { - // use updater in lib plugin - Class clazz = Class.forName("net.guizhanss.guizhanlibplugin.updater.GuizhanUpdater"); - Method updaterStart = clazz.getDeclaredMethod("start", Plugin.class, File.class, String.class, String.class, String.class); - updaterStart.invoke(null, this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()); - } catch (Exception ignored) { - // use updater in lib - new GuizhanBuildsUpdater(this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()).start(); - } - } - } -} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/SlimefunTranslation.java b/src/main/java/net/guizhanss/slimefuntranslation/SlimefunTranslation.java new file mode 100644 index 000000000..a76fdf93b --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/SlimefunTranslation.java @@ -0,0 +1,93 @@ +package net.guizhanss.slimefuntranslation; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.logging.Level; + +import org.bukkit.plugin.Plugin; + +import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.BlobBuildUpdater; + +import net.guizhanss.guizhanlib.slimefun.addon.AbstractAddon; +import net.guizhanss.guizhanlib.updater.GuizhanBuildsUpdater; +import net.guizhanss.slimefuntranslation.core.Registry; +import net.guizhanss.slimefuntranslation.implementation.managers.CommandManager; +import net.guizhanss.slimefuntranslation.implementation.managers.ListenerManager; +import net.guizhanss.slimefuntranslation.implementation.managers.PacketListenerManager; +import net.guizhanss.slimefuntranslation.implementation.managers.TranslationManager; +import net.guizhanss.slimefuntranslation.implementation.managers.UserManager; + +import org.bstats.bukkit.Metrics; + +public final class SlimefunTranslation extends AbstractAddon { + + private Registry registry; + private UserManager userManager; + private TranslationManager translationManager; + + public SlimefunTranslation() { + super("ybw0014", "SlimefunTranslation", "master", "auto-update"); + } + + private static SlimefunTranslation inst() { + return getInstance(); + } + + public static Registry getRegistry() { + return inst().registry; + } + + public static UserManager getUserManager() { + return inst().userManager; + } + + public static TranslationManager getTranslationManager() { + return inst().translationManager; + } + + @Override + public void enable() { + log(Level.INFO, "===================="); + log(Level.INFO, "Slimefun Translation"); + log(Level.INFO, " by ybw0014 "); + log(Level.INFO, "===================="); + + registry = new Registry(); + userManager = new UserManager(); + translationManager = new TranslationManager(this); + new CommandManager(this); + new ListenerManager(this); + new PacketListenerManager(); + + setupMetrics(); + + getScheduler().runAsync(() -> { + translationManager.loadTranslations(); + }); + } + + @Override + public void disable() { + } + + private void setupMetrics() { + new Metrics(this, 20496); + } + + @Override + protected void autoUpdate() { + if (getPluginVersion().startsWith("Dev")) { + new BlobBuildUpdater(this, getFile(), getGithubRepo()).start(); + } else if (getPluginVersion().startsWith("Build")) { + try { + // use updater in lib plugin + Class clazz = Class.forName("net.guizhanss.guizhanlibplugin.updater.GuizhanUpdater"); + Method updaterStart = clazz.getDeclaredMethod("start", Plugin.class, File.class, String.class, String.class, String.class); + updaterStart.invoke(null, this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()); + } catch (Exception ignored) { + // use updater in lib + new GuizhanBuildsUpdater(this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()).start(); + } + } + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/api/TranslationConfiguration.java b/src/main/java/net/guizhanss/slimefuntranslation/api/TranslationConfiguration.java new file mode 100644 index 000000000..7da76ccee --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/api/TranslationConfiguration.java @@ -0,0 +1,25 @@ +package net.guizhanss.slimefuntranslation.api; + +import java.util.HashMap; +import java.util.Map; + +import net.guizhanss.slimefuntranslation.api.interfaces.Translation; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * This class holds the information provided from a valid translations file, or from other addons. + * + * @author ybw0014 + */ +@RequiredArgsConstructor +@Getter +public class TranslationConfiguration { + private final String name; + private final String author; + private final boolean enabled; + private final String lang; + + private final Map translations = new HashMap<>(); +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translatable.java b/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translatable.java new file mode 100644 index 000000000..ec8d1e60c --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translatable.java @@ -0,0 +1,19 @@ +package net.guizhanss.slimefuntranslation.api.interfaces; + +import java.util.List; + +import javax.annotation.Nonnull; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; + +/** + * This interface should be implemented by a {@link SlimefunItem}. + * It means the {@link SlimefunItem} can be translated from code. + */ +public interface Translatable { + @Nonnull + String getTranslatedDisplayName(String original); + + @Nonnull + List getTranslatedLore(List original); +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translation.java b/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translation.java new file mode 100644 index 000000000..c3513ce25 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/api/interfaces/Translation.java @@ -0,0 +1,20 @@ +package net.guizhanss.slimefuntranslation.api.interfaces; + +import java.util.List; + +import javax.annotation.Nonnull; + +import net.guizhanss.slimefuntranslation.api.translations.FixedTranslation; + +/** + * This interface represents a translation. + * + * @see FixedTranslation + */ +public interface Translation { + @Nonnull + String getDisplayName(String original); + + @Nonnull + List getLore(List original); +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/api/translations/FixedTranslation.java b/src/main/java/net/guizhanss/slimefuntranslation/api/translations/FixedTranslation.java new file mode 100644 index 000000000..05535699e --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/api/translations/FixedTranslation.java @@ -0,0 +1,23 @@ +package net.guizhanss.slimefuntranslation.api.translations; + +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; + +import net.guizhanss.slimefuntranslation.api.interfaces.Translation; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class FixedTranslation implements Translation { + private final String displayName; + private final List lore; + private final Map replacements; + + @Override + @Nonnull + public String getDisplayName(@Nonnull String original) { + return displayName; + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/api/translations/ProgrammedTranslation.java b/src/main/java/net/guizhanss/slimefuntranslation/api/translations/ProgrammedTranslation.java new file mode 100644 index 000000000..10e71cbc1 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/api/translations/ProgrammedTranslation.java @@ -0,0 +1,31 @@ +package net.guizhanss.slimefuntranslation.api.translations; + +import lombok.RequiredArgsConstructor; + +import net.guizhanss.slimefuntranslation.api.interfaces.Translation; +import net.guizhanss.slimefuntranslation.api.interfaces.Translatable; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; + +import javax.annotation.Nonnull; + +import java.util.List; + +/** + * This {@link Translation} is applied by {@link SlimefunItem}s which implemented {@link Translatable}. + */ +@RequiredArgsConstructor +public class ProgrammedTranslation implements Translation { + private final Translatable translatable; + + @Nonnull + @Override + public String getDisplayName(@Nonnull String original) { + return translatable.getTranslatedDisplayName(original); + } + + @Nonnull + @Override + public List getLore(@Nonnull List original) { + return translatable.getTranslatedLore(original); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/core/Registry.java b/src/main/java/net/guizhanss/slimefuntranslation/core/Registry.java new file mode 100644 index 000000000..3b9ed6577 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/core/Registry.java @@ -0,0 +1,16 @@ +package net.guizhanss.slimefuntranslation.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import net.guizhanss.slimefuntranslation.api.interfaces.Translation; +import net.guizhanss.slimefuntranslation.core.users.User; + +import lombok.Getter; + +@Getter +public final class Registry { + private final Map users = new HashMap<>(); + private final Map translations = new HashMap<>(); +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/core/users/User.java b/src/main/java/net/guizhanss/slimefuntranslation/core/users/User.java new file mode 100644 index 000000000..8a5869418 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/core/users/User.java @@ -0,0 +1,43 @@ +package net.guizhanss.slimefuntranslation.core.users; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +import lombok.Getter; +import lombok.ToString; + +/** + * The {@link User} class holds information of a {@link Player}. + */ +@Getter +@ToString +public class User { + private final Player player; + private final UUID uuid; + private String locale; + + public User(Player player) { + this.player = player; + this.uuid = player.getUniqueId(); + init(); + } + + public User(UUID uuid) { + this.player = Bukkit.getPlayer(uuid); + this.uuid = uuid; + init(); + } + + private void init() { + var lang = Slimefun.getLocalization().getLanguage(player); + if (lang != null) { + locale = lang.getId(); + } else { + locale = Slimefun.getLocalization().getDefaultLanguage().getId(); + } + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerJoinListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerJoinListener.java new file mode 100644 index 000000000..495436ab6 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerJoinListener.java @@ -0,0 +1,18 @@ +package net.guizhanss.slimefuntranslation.implementation.listeners; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; + +public class PlayerJoinListener implements Listener { + public PlayerJoinListener(SlimefunTranslation plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onJoin(PlayerJoinEvent e) { + SlimefunTranslation.getUserManager().addUser(e.getPlayer()); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerQuitListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerQuitListener.java new file mode 100644 index 000000000..f257c2775 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/listeners/PlayerQuitListener.java @@ -0,0 +1,18 @@ +package net.guizhanss.slimefuntranslation.implementation.listeners; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; + +public class PlayerQuitListener implements Listener { + public PlayerQuitListener(SlimefunTranslation plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onJoin(PlayerQuitEvent e) { + SlimefunTranslation.getUserManager().removeUser(e.getPlayer()); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/CommandManager.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/CommandManager.java new file mode 100644 index 000000000..64a9ba432 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/CommandManager.java @@ -0,0 +1,9 @@ +package net.guizhanss.slimefuntranslation.implementation.managers; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; + +public final class CommandManager { + public CommandManager(SlimefunTranslation plugin) { + // new MainCommand(plugin.getCommand("sftranslation")).register(); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/ListenerManager.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/ListenerManager.java new file mode 100644 index 000000000..8debc8e4d --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/ListenerManager.java @@ -0,0 +1,14 @@ +package net.guizhanss.slimefuntranslation.implementation.managers; + +import javax.annotation.Nonnull; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.listeners.PlayerJoinListener; +import net.guizhanss.slimefuntranslation.implementation.listeners.PlayerQuitListener; + +public final class ListenerManager { + public ListenerManager(@Nonnull SlimefunTranslation plugin) { + new PlayerJoinListener(plugin); + new PlayerQuitListener(plugin); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/PacketListenerManager.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/PacketListenerManager.java new file mode 100644 index 000000000..9d5367991 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/PacketListenerManager.java @@ -0,0 +1,26 @@ +package net.guizhanss.slimefuntranslation.implementation.managers; + +import java.util.ArrayList; +import java.util.List; + +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.AListener; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.items.SetCreativeSlotListener; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.items.WindowClickListener; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.items.SetSlotListener; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.items.WindowItemListener; + +public final class PacketListenerManager { + + public PacketListenerManager() { + List packetListeners = new ArrayList<>(); + + packetListeners.add(new SetSlotListener()); + packetListeners.add(new WindowItemListener()); + packetListeners.add(new SetCreativeSlotListener()); + packetListeners.add(new WindowClickListener()); + + for (var listener : packetListeners) { + listener.register(); + } + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/TranslationManager.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/TranslationManager.java new file mode 100644 index 000000000..3dbd47f6c --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/TranslationManager.java @@ -0,0 +1,92 @@ +package net.guizhanss.slimefuntranslation.implementation.managers; + +import java.io.File; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.base.Preconditions; + +import net.guizhanss.slimefuntranslation.api.TranslationConfiguration; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.api.interfaces.Translatable; +import net.guizhanss.slimefuntranslation.core.users.User; + +public final class TranslationManager { + private static final String FOLDER_NAME = "translations"; + + public TranslationManager(SlimefunTranslation plugin) { + File translationsFolder = new File(plugin.getDataFolder(), FOLDER_NAME); + if (!translationsFolder.exists()) { + translationsFolder.mkdirs(); + } + } + + public void loadTranslations() { + + } + + private void loadFixedTranslations() { + // TODO: Load file translations + } + + private void loadProgrammedTranslations() { + // TODO: Load Translatable SlimefunItem translations + } + + /** + * Register a {@link TranslationConfiguration}. + * This can be called from the loading methods in this class, or by other plugins if they don't want to implement {@link Translatable}. + * @param configuration The {@link TranslationConfiguration}. + */ + public void registerTranslationConfiguration(@Nonnull TranslationConfiguration configuration) { + + } + + /** + * Translate the given {@link ItemStack} for the given {@link User}. + * The given {@link ItemStack} must have a Slimefun item, or the translation will not be applied. + * + * @param user + * The {@link User}. + * @param item + * The {@link ItemStack}. + * + * @return Whether the item was translated. + */ + public boolean translateItem(@Nonnull User user, @Nullable ItemStack item) { + Preconditions.checkArgument(user != null, "user cannot be null"); + if (item == null || !item.hasItemMeta()) { + return false; + } + SlimefunItem sfItem = SlimefunItem.getByItem(item); + if (sfItem == null) { + return false; + } + + return translateItem(user, item, sfItem); + } + + @ParametersAreNonnullByDefault + private boolean translateItem(User user, ItemStack item, SlimefunItem sfItem) { + if (sfItem instanceof Translatable translatable) { + ItemMeta meta = item.getItemMeta(); + if (meta.hasDisplayName()) { + meta.setDisplayName(translatable.getTranslatedDisplayName(meta.getDisplayName())); + } + if (meta.hasLore()) { + meta.setLore(translatable.getTranslatedLore(meta.getLore())); + } + return true; + } + + return false; + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/UserManager.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/UserManager.java new file mode 100644 index 000000000..ccdb5cb53 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/managers/UserManager.java @@ -0,0 +1,46 @@ +package net.guizhanss.slimefuntranslation.implementation.managers; + +import java.util.UUID; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.core.users.User; + +public final class UserManager { + + @Nonnull + public User getUser(@Nonnull UUID uuid) { + var users = SlimefunTranslation.getRegistry().getUsers(); + if (users.containsKey(uuid)) { + return users.get(uuid); + } else { + var user = new User(uuid); + users.put(uuid, user); + return user; + } + } + + @Nonnull + public User getUser(@Nonnull Player p) { + return getUser(p.getUniqueId()); + } + + public void addUser(@Nonnull UUID uuid) { + SlimefunTranslation.getRegistry().getUsers().putIfAbsent(uuid, new User(uuid)); + } + + public void addUser(@Nonnull Player p) { + addUser(p.getUniqueId()); + } + + public void removeUser(@Nonnull UUID uuid) { + SlimefunTranslation.getRegistry().getUsers().remove(uuid); + } + + public void removeUser(@Nonnull Player p) { + removeUser(p.getUniqueId()); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/AListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/AListener.java new file mode 100644 index 000000000..4a7765a55 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/AListener.java @@ -0,0 +1,46 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners; + +import java.util.logging.Level; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; +import com.google.common.base.Preconditions; + +import org.bukkit.entity.Player; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.core.users.User; + +public abstract class AListener { + protected final PacketType packetType; + protected PacketAdapter adapter; + + protected AListener(@Nonnull PacketType packetType) { + this.packetType = packetType; + } + + @Nullable + public User getUser(@Nonnull PacketEvent event) { + Preconditions.checkArgument(event != null, "PacketEvent cannot be null"); + Player p = event.getPlayer(); + if (event.isPlayerTemporary()) { + SlimefunTranslation.log(Level.WARNING, + "ProtocolLib returns temporary player [{0}] for packet {1}. It cannot be processed.", + p.getAddress(), packetType.name()); + return null; + } else { + return SlimefunTranslation.getUserManager().getUser(p); + } + } + + public void register() { + ProtocolLibrary.getProtocolManager().addPacketListener(adapter); + } + + protected abstract void process(@Nonnull PacketEvent event); +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/AClientListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/AClientListener.java new file mode 100644 index 000000000..1d6d653d3 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/AClientListener.java @@ -0,0 +1,24 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.client; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.AListener; + +public abstract class AClientListener extends AListener { + protected AClientListener(@Nonnull PacketType packetType) { + super(packetType); + + adapter = new PacketAdapter(SlimefunTranslation.getInstance(), ListenerPriority.HIGHEST, packetType) { + @Override + public void onPacketReceiving(@Nonnull PacketEvent event) { + process(event); + } + }; + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/SetCreativeSlotListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/SetCreativeSlotListener.java new file mode 100644 index 000000000..6a73aee30 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/SetCreativeSlotListener.java @@ -0,0 +1,26 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.items; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketEvent; + +import org.bukkit.inventory.ItemStack; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.AClientListener; + +public class SetCreativeSlotListener extends AClientListener { + public SetCreativeSlotListener() { + super(PacketType.Play.Client.SET_CREATIVE_SLOT); + } + + protected void process(@Nonnull PacketEvent event) { + var user = getUser(event); + if (user == null) { + return; + } + ItemStack item = event.getPacket().getItemModifier().read(0); + SlimefunTranslation.getTranslationManager().translateItem(user, item); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/WindowClickListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/WindowClickListener.java new file mode 100644 index 000000000..0c4eb27f6 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/client/items/WindowClickListener.java @@ -0,0 +1,26 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.items; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketEvent; + +import org.bukkit.inventory.ItemStack; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.client.AClientListener; + +public class WindowClickListener extends AClientListener { + public WindowClickListener() { + super(PacketType.Play.Client.WINDOW_CLICK); + } + + protected void process(@Nonnull PacketEvent event) { + var user = getUser(event); + if (user == null) { + return; + } + ItemStack item = event.getPacket().getItemModifier().read(0); + SlimefunTranslation.getTranslationManager().translateItem(user, item); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/AServerListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/AServerListener.java new file mode 100644 index 000000000..40b33d34e --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/AServerListener.java @@ -0,0 +1,24 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.server; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.AListener; + +public abstract class AServerListener extends AListener { + protected AServerListener(@Nonnull PacketType packetType) { + super(packetType); + + adapter = new PacketAdapter(SlimefunTranslation.getInstance(), ListenerPriority.HIGHEST, packetType) { + @Override + public void onPacketSending(@Nonnull PacketEvent event) { + process(event); + } + }; + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/SetSlotListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/SetSlotListener.java new file mode 100644 index 000000000..1716218f6 --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/SetSlotListener.java @@ -0,0 +1,35 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.items; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.reflect.StructureModifier; + +import org.bukkit.inventory.ItemStack; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.AServerListener; + +public class SetSlotListener extends AServerListener { + public SetSlotListener() { + super(PacketType.Play.Server.SET_SLOT); + } + + @Override + protected void process(@Nonnull PacketEvent event) { + var user = getUser(event); + if (user == null) { + return; + } + PacketContainer packet = event.getPacket(); + StructureModifier modifier = packet.getItemModifier(); + for (int i = 0; i < modifier.size(); i++) { + ItemStack item = modifier.read(i); + if (SlimefunTranslation.getTranslationManager().translateItem(user, item)) { + modifier.write(i, item); + } + } + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/WindowItemListener.java b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/WindowItemListener.java new file mode 100644 index 000000000..59bc2da3d --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/implementation/packetlisteners/server/items/WindowItemListener.java @@ -0,0 +1,36 @@ +package net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.items; + +import java.util.List; + +import javax.annotation.Nonnull; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.reflect.StructureModifier; + +import org.bukkit.inventory.ItemStack; + +import net.guizhanss.slimefuntranslation.SlimefunTranslation; +import net.guizhanss.slimefuntranslation.implementation.packetlisteners.server.AServerListener; + +public class WindowItemListener extends AServerListener { + public WindowItemListener() { + super(PacketType.Play.Server.WINDOW_ITEMS); + } + + @Override + protected void process(@Nonnull PacketEvent event) { + var user = getUser(event); + if (user == null) { + return; + } + PacketContainer packet = event.getPacket(); + StructureModifier> modifier = packet.getItemListModifier(); + List items = modifier.read(0); + for (ItemStack item : items) { + SlimefunTranslation.getTranslationManager().translateItem(user, item); + } + modifier.write(0, items); + } +} diff --git a/src/main/java/net/guizhanss/slimefuntranslation/utils/FileUtils.java b/src/main/java/net/guizhanss/slimefuntranslation/utils/FileUtils.java new file mode 100644 index 000000000..8e80e36eb --- /dev/null +++ b/src/main/java/net/guizhanss/slimefuntranslation/utils/FileUtils.java @@ -0,0 +1,58 @@ +package net.guizhanss.slimefuntranslation.utils; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import lombok.experimental.UtilityClass; + +@SuppressWarnings("ConstantConditions") +@UtilityClass +public final class FileUtils { + /** + * Lists all YAML files in the given folder. + * The folder or files starts with a dot (.) or an underscore(_) will be ignored. + * + * @param folder + * the folder to search in + * + * @return a list of all YAML files in the given folder + */ + @Nonnull + public static List listYamlFiles(@Nonnull File folder) { + return listYamlFiles(folder, ""); + } + + @Nonnull + @ParametersAreNonnullByDefault + private static List listYamlFiles(File folder, String path) { + if (folder == null || !folder.isDirectory()) { + return Collections.emptyList(); + } + var files = folder.listFiles(); + if (files == null) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + for (File file : files) { + String filename = file.getName(); + if (filename.startsWith(".") || filename.startsWith("_")) { + continue; + } + if (file.isDirectory()) { + String subFolderPath = path + filename + "/"; + result.addAll(listYamlFiles(file, subFolderPath)); + } else { + if (filename.endsWith(".yml") || filename.endsWith(".yaml")) { + result.add(path + filename); + } + } + } + return result; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3c2f9467d..4a65eabd6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1 +1,7 @@ +# Whether to enable auto update auto-update: true + +# Language mappings +# Format: : +language-mappings: + en-US: en diff --git a/src/main/resources/languages/en/slimefun-weapons.yml b/src/main/resources/languages/en/slimefun-weapons.yml new file mode 100644 index 000000000..f4df69c0c --- /dev/null +++ b/src/main/resources/languages/en/slimefun-weapons.yml @@ -0,0 +1,6 @@ +name: Slimefun Weapons Translation +author: Slimefun +enabled: true +lang: en +translations: + diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index de8e017e5..e02d4f6b0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,17 @@ -name: GuizhanSlimefunAddon +name: SlimefunTranslation version: '${project.version}' -main: net.guizhanss.guizhanslimefunaddon.GuizhanSlimefunAddon -api-version: 1.14 -depend: [ Slimefun ] -softdepend: [ GuizhanLibPlugin ] +main: net.guizhanss.slimefuntranslation.SlimefunTranslation +api-version: 1.16 +depend: + - Slimefun + - ProtocolLib +softdepend: + - GuizhanLibPlugin + - PlaceholderAPI authors: [ ybw0014 ] -description: A Slimefun Addon +description: A Slimefun Addon that translates items without actually modifying the items. +commands: + sftranslation: + description: SlimefunTranslation Command + usage: / + aliases: [ slimefuntranslation, sft, sftr ]