From a82089749052752374377a52a0d65f66f1ee0352 Mon Sep 17 00:00:00 2001 From: Xharos Date: Tue, 25 Jun 2024 23:47:08 +0200 Subject: [PATCH] Implement player data synchronization on redis, add translatable bundle and override logging systems to json --- .idea/uiDesigner.xml | 124 ++++++++++++++++ build.gradle.kts | 3 +- compose.yaml | 25 +++- redis/Dockerfile | 7 + redis/custom-entrypoint.sh | 28 ++++ .../java/fr/islandswars/ineundo/Ineundo.java | 69 ++++++--- .../ineundo/lang/IneundoError.java | 36 +++++ .../ineundo/listener/LazyListener.java | 6 +- .../ineundo/listener/PlayerDataListener.java | 139 +++++++++++------- .../ineundo/locale/TranslationLoader.java | 64 ++++++++ .../ineundo/log/InternalLogger.java | 92 ++++++++++++ .../java/fr/islandswars/ineundo/log/Log.java | 62 ++++++++ .../ineundo/log/Log4jLevelSerializer.java | 41 ++++++ .../log/StackTraceElementTypeAdapter.java | 48 ++++++ .../ineundo/log/internal/DefaultLog.java | 43 ++++++ .../ineundo/log/internal/ErrorLog.java | 44 ++++++ .../ineundo/player/IslandsPlayer.java | 49 +++--- .../ineundo/player/IslandsRank.java | 21 ++- .../fr/islandswars/ineundo/player/Rank.java | 58 ++++++++ .../player/sanction/IslandsSanction.java | 22 +-- .../player/sanction/SanctionReason.java | 5 +- .../ineundo/utils/MongoConstants.java | 40 +++++ .../ineundo/utils/ProxyConstants.java | 31 ++++ .../ineundo/utils/RedisConstants.java | 36 +++++ .../islandswars/ineundo/utils/TimeUtils.java | 39 +++++ .../resources/locale/ineundo_en_US.properties | 10 ++ .../resources/locale/ineundo_fr_FR.properties | 2 + src/main/resources/log4j2-islands.xml | 27 ++++ 28 files changed, 1051 insertions(+), 120 deletions(-) create mode 100644 .idea/uiDesigner.xml create mode 100644 redis/Dockerfile create mode 100644 redis/custom-entrypoint.sh create mode 100644 src/main/java/fr/islandswars/ineundo/lang/IneundoError.java create mode 100644 src/main/java/fr/islandswars/ineundo/locale/TranslationLoader.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/InternalLogger.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/Log.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/Log4jLevelSerializer.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/StackTraceElementTypeAdapter.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/internal/DefaultLog.java create mode 100644 src/main/java/fr/islandswars/ineundo/log/internal/ErrorLog.java create mode 100644 src/main/java/fr/islandswars/ineundo/player/Rank.java create mode 100644 src/main/java/fr/islandswars/ineundo/utils/MongoConstants.java create mode 100644 src/main/java/fr/islandswars/ineundo/utils/ProxyConstants.java create mode 100644 src/main/java/fr/islandswars/ineundo/utils/RedisConstants.java create mode 100644 src/main/java/fr/islandswars/ineundo/utils/TimeUtils.java create mode 100644 src/main/resources/locale/ineundo_en_US.properties create mode 100644 src/main/resources/locale/ineundo_fr_FR.properties create mode 100644 src/main/resources/log4j2-islands.xml diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index f923adb..de1fce4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,9 +29,10 @@ dependencies { implementation("org.mongodb:mongodb-driver-reactivestreams:5.0.0") implementation("io.lettuce:lettuce-core:6.3.2.RELEASE") implementation("com.rabbitmq:amqp-client:5.21.0") + implementation("org.apache.logging.log4j:log4j-core:3.0.0-beta2") + implementation("fr.islandswars:commons:0.3.1") compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") - implementation("fr.islandswars:commons:0.3.1") } tasks.withType { diff --git a/compose.yaml b/compose.yaml index e24fee1..37e603a 100644 --- a/compose.yaml +++ b/compose.yaml @@ -27,6 +27,8 @@ services: depends_on: mongo: condition: service_healthy + redis: + condition: service_healthy mc: image: itzg/minecraft-server:java21-jdk @@ -37,9 +39,6 @@ services: PAPER_DOWNLOAD_URL: "https://api.papermc.io/v2/projects/paper/versions/1.21/builds/37/downloads/paper-1.21-37.jar" volumes: - ./data:/data - depends_on: - mongo: - condition: service_healthy networks: - islands_network @@ -71,6 +70,26 @@ services: - ./mongodb/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d/ command: [ --auth ] + redis: + build: redis/. + ports: + - '6379:6379' + environment: + REDIS_PASSWORD_FILE: /run/secrets/redis_password + REDIS_USERNAME_FILE: /run/secrets/redis_username + REDIS_DISABLE_DEFAULT_USER: true + secrets: + - redis_password + - redis_username + networks: + - islands_network + healthcheck: + test: [ "CMD-SHELL", "redis-cli -u redis://$(cat /run/secrets/redis_username):$(cat /run/secrets/redis_password)@redis:6379 PING | grep -q PONG" ] + interval: 2s + timeout: 12s + retries: 5 + start_period: 10s + networks: islands_network: driver: bridge diff --git a/redis/Dockerfile b/redis/Dockerfile new file mode 100644 index 0000000..3cee879 --- /dev/null +++ b/redis/Dockerfile @@ -0,0 +1,7 @@ +FROM redis:latest + +# Copy the custom entrypoint script +COPY custom-entrypoint.sh /usr/local/bin/custom-entrypoint.sh +RUN chmod +x /usr/local/bin/custom-entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/custom-entrypoint.sh"] \ No newline at end of file diff --git a/redis/custom-entrypoint.sh b/redis/custom-entrypoint.sh new file mode 100644 index 0000000..85cb0d6 --- /dev/null +++ b/redis/custom-entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# Paths to the secrets files +REDIS_USERNAME_FILE=/run/secrets/redis_username +REDIS_PASSWORD_FILE=/run/secrets/redis_password + +# Read the contents of the secrets files +REDIS_USERNAME=$(cat $REDIS_USERNAME_FILE) +REDIS_PASSWORD=$(cat $REDIS_PASSWORD_FILE) + +# Set up Redis configuration directory +mkdir -p /usr/local/etc/redis + +# Dynamically generate Redis configuration and ACL files +echo "aclfile /usr/local/etc/redis/custom_aclfile.acl" > /usr/local/etc/redis/redis.conf + +# Generate ACL file using secrets contents +if [ -n "$REDIS_USERNAME" ] && [ -n "$REDIS_PASSWORD" ]; then + echo "user $REDIS_USERNAME on allkeys allchannels allcommands >$REDIS_PASSWORD" > /usr/local/etc/redis/custom_aclfile.acl +fi + +# Disable default user +if [ "$REDIS_DISABLE_DEFAULT_USER" = "true" ]; then + echo "user default off nopass nocommands" >> /usr/local/etc/redis/custom_aclfile.acl +fi + +# Call the original Docker entrypoint script with redis-server and the path to the custom Redis configuration +exec docker-entrypoint.sh redis-server /usr/local/etc/redis/redis.conf \ No newline at end of file diff --git a/src/main/java/fr/islandswars/ineundo/Ineundo.java b/src/main/java/fr/islandswars/ineundo/Ineundo.java index 1a5e71d..14dd48b 100644 --- a/src/main/java/fr/islandswars/ineundo/Ineundo.java +++ b/src/main/java/fr/islandswars/ineundo/Ineundo.java @@ -1,25 +1,27 @@ package fr.islandswars.ineundo; import com.google.inject.Inject; -import com.mongodb.MongoClientSettings; -import com.mongodb.reactivestreams.client.MongoClients; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; import fr.islandswars.commons.service.mongodb.MongoDBConnection; +import fr.islandswars.commons.service.redis.RedisConnection; import fr.islandswars.commons.utils.LogUtils; import fr.islandswars.ineundo.listener.PlayerDataListener; +import fr.islandswars.ineundo.locale.TranslationLoader; +import fr.islandswars.ineundo.log.InternalLogger; import fr.islandswars.ineundo.player.IslandsPlayer; import net.kyori.adventure.text.Component; -import org.bson.UuidRepresentation; +import org.apache.logging.log4j.Level; import java.nio.file.Path; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Logger; +import java.util.concurrent.atomic.AtomicBoolean; /** * File Ineundo located on fr.islandswars.ineundo @@ -53,47 +55,74 @@ ) public class Ineundo { - private final CopyOnWriteArrayList players; - private final MongoDBConnection mongoConnection; - private final Logger logger; - private final ProxyServer server; + private static Ineundo INSTANCE; + private final CopyOnWriteArrayList players; + private final MongoDBConnection mongoConnection; + private final RedisConnection redisConnection; + private final ProxyServer server; + private final InternalLogger infraLogger; + private final AtomicBoolean STAFF_ONLY; @Inject - public Ineundo(Logger logger, ProxyServer server, @DataDirectory Path dataDirectory) { + public Ineundo(ProxyServer server, @DataDirectory Path dataDirectory) { + if (INSTANCE == null) + INSTANCE = this; this.mongoConnection = new MongoDBConnection(); + this.redisConnection = new RedisConnection(); + this.infraLogger = new InternalLogger(); this.players = new CopyOnWriteArrayList<>(); - this.logger = logger; + this.STAFF_ONLY = new AtomicBoolean(false); this.server = server; - LogUtils.setErrorConsummer(e -> { - e.printStackTrace();//TODO change - }); + LogUtils.setErrorConsummer(infraLogger::logError); + } + + public static Ineundo getInstance() { + return INSTANCE; } @Subscribe public void onInitialization(ProxyInitializeEvent event) { + new TranslationLoader().load("locale.ineundo"); + //databases try { mongoConnection.load(); mongoConnection.connect(); - logger.info(mongoConnection.getConnection().getName()); + redisConnection.load(); + redisConnection.connect(); } catch (Exception e) { - server.shutdown(Component.text("Database issue")); - e.printStackTrace(); + infraLogger.logError(e); + server.shutdown(Component.translatable("proxy.startup.database.error")); } - new PlayerDataListener(this, mongoConnection); + //listeners + new PlayerDataListener(this, mongoConnection, redisConnection); + } + + @Subscribe + public void onQuit(ProxyShutdownEvent event) { + try { + mongoConnection.close(); + redisConnection.close(); + } catch (Exception e) { + infraLogger.logError(e); + } } public ProxyServer getServer() { return server; } - public Logger getLogger() { - return logger; + public InternalLogger getInfraLogger() { + return infraLogger; + } + + public AtomicBoolean getSTAFF_ONLY() { + return STAFF_ONLY; } public void addPlayer(IslandsPlayer player) { if (getPlayer(player.getUUID()).isPresent()) - logger.severe("Player " + player.getUUID() + " is already registered...."); + infraLogger.log(Level.WARN, "Player " + player.getUUID() + " is already registered...."); else players.add(player); } diff --git a/src/main/java/fr/islandswars/ineundo/lang/IneundoError.java b/src/main/java/fr/islandswars/ineundo/lang/IneundoError.java new file mode 100644 index 0000000..8ea9604 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/lang/IneundoError.java @@ -0,0 +1,36 @@ +package fr.islandswars.ineundo.lang; + +/** + * File IneundoError located on fr.islandswars.ineundo.lang + * IneundoError is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 21:15 + * @since 0.1 + */ +public class IneundoError extends RuntimeException { + + public IneundoError(String message) { + super(message); + } + + public IneundoError(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/listener/LazyListener.java b/src/main/java/fr/islandswars/ineundo/listener/LazyListener.java index c60d88e..95b91bc 100644 --- a/src/main/java/fr/islandswars/ineundo/listener/LazyListener.java +++ b/src/main/java/fr/islandswars/ineundo/listener/LazyListener.java @@ -51,7 +51,11 @@ public ProxyServer getServer() { } public void log(String msg) { - ineundo.getLogger().info(msg); + ineundo.getInfraLogger().logInfo(msg); + } + + public void error(Exception e) { + ineundo.getInfraLogger().logError(e); } public Optional getPlayer(UUID uuid) { diff --git a/src/main/java/fr/islandswars/ineundo/listener/PlayerDataListener.java b/src/main/java/fr/islandswars/ineundo/listener/PlayerDataListener.java index b15761b..ba52120 100644 --- a/src/main/java/fr/islandswars/ineundo/listener/PlayerDataListener.java +++ b/src/main/java/fr/islandswars/ineundo/listener/PlayerDataListener.java @@ -1,36 +1,34 @@ package fr.islandswars.ineundo.listener; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.mongodb.client.model.Filters; -import com.mongodb.client.model.ReplaceOptions; import com.mongodb.client.result.UpdateResult; import com.velocitypowered.api.event.EventTask; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; -import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.player.ServerPreConnectEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import fr.islandswars.commons.service.collection.Collection; -import fr.islandswars.commons.service.mongodb.FutureSubscriber; import fr.islandswars.commons.service.mongodb.MongoDBConnection; -import fr.islandswars.commons.service.mongodb.ObservableSubscriber; import fr.islandswars.commons.service.mongodb.OperationSubscriber; +import fr.islandswars.commons.service.redis.RedisConnection; +import fr.islandswars.commons.utils.ReflectionUtil; import fr.islandswars.ineundo.Ineundo; +import fr.islandswars.ineundo.lang.IneundoError; import fr.islandswars.ineundo.player.IslandsPlayer; -import fr.islandswars.ineundo.player.sanction.IslandsSanction; -import fr.islandswars.ineundo.player.sanction.SanctionReason; +import fr.islandswars.ineundo.utils.MongoConstants; +import fr.islandswars.ineundo.utils.RedisConstants; import net.kyori.adventure.text.Component; import org.bson.Document; +import java.lang.reflect.Field; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; @@ -57,6 +55,7 @@ * @author Jangliu, {@literal } * Created the 24/06/2024 at 16:10 * @since 0.1 + * TODO proper logging */ public class PlayerDataListener extends LazyListener { @@ -64,11 +63,13 @@ public class PlayerDataListener extends LazyListener { private final TimeUnit mongoTimeoutUnit = TimeUnit.SECONDS; private final List> pendingResults; private final Collection playersCollection; + private final RedisConnection redis; - public PlayerDataListener(Ineundo ineundo, MongoDBConnection connection) { + public PlayerDataListener(Ineundo ineundo, MongoDBConnection mongo, RedisConnection redis) { super(ineundo); + this.redis = redis; this.pendingResults = new CopyOnWriteArrayList<>(); - this.playersCollection = connection.getCollection("players", IslandsPlayer.class); + this.playersCollection = mongo.getCollection(MongoConstants.PLAYER_COLLECTION, IslandsPlayer.class); } @Subscribe @@ -80,32 +81,15 @@ public void onLogin(PreLoginEvent event) { @Subscribe(order = PostOrder.FIRST) public EventTask onServerPreconnectEvent(ServerPreConnectEvent event) { if (event.getPreviousServer() == null) { - return EventTask.async(() -> { - getPlayerAsync(event.getPlayer().getUniqueId()).whenCompleteAsync((optPlayer, ex) -> { - if (ex != null || optPlayer.isEmpty()) { - ex.printStackTrace(); - event.getPlayer().disconnect(Component.text("Database issue")); - } else { - var player = optPlayer.get(); - var sanction = player.isKick(); - sanction.ifPresent(s -> event.getPlayer().disconnect(Component.text(s.getReason().getKickKey()))); - //TODO server for staff only - //TODO server offline - //TODO set on redis - } - }); - }); - } - return null; + return EventTask.async(() -> synchroniseData(event)); + } else + return null; } @Subscribe public void onPlayerDisconnect(DisconnectEvent event) { var uuid = event.getPlayer().getUniqueId(); var optPlayer = getPlayer(uuid); - optPlayer.get().addSanction(new IslandsSanction(SanctionReason.CHEAT, UUID.randomUUID())); - //TODO fetch from redis - log("quit event call "); optPlayer.ifPresent(this::savePlayerData); } @@ -116,36 +100,80 @@ public void onProxyShutdown(ProxyShutdownEvent event) { } private void savePlayerData(IslandsPlayer player) { - var subscriber = playersCollection.replace(player, Filters.eq("uuid", player.getUUID().toString())); - pendingResults.add(subscriber); + updateFromRedis(player).whenCompleteAsync((p, thr) -> { + if (thr != null) + error(new IneundoError("Error when saving player data in MongoDB...", thr)); + + var subscriber = playersCollection.replace(player, MongoConstants.PLAYER_ID_FILTER(player.getUUID())); + pendingResults.add(subscriber); + + CompletableFuture result = new CompletableFuture<>(); + result.completeAsync(subscriber::first); + result.whenCompleteAsync((re, th) -> { + if (th != null) + error(new IneundoError("Error when saving player data in MongoDB...", th)); + getIneundo().removePlayer(player); + pendingResults.remove(subscriber); + }); + //TODO maybe add a timeout here in case the player wants to connect back to the server + //TODO or check if a player with this uuid is already existing when joining + }); + } + + private void synchroniseData(ServerPreConnectEvent event) { + getPlayerAsync(event.getPlayer().getUniqueId()).whenCompleteAsync((optPlayer, th) -> { + if (th != null || optPlayer.isEmpty()) { + error(new IneundoError("Player " + event.getPlayer().getUsername() + " cannot be retrieved in time", th)); + event.getPlayer().disconnect(Component.translatable("event.join.data.error")); + } else { + var player = optPlayer.get(); + var sanction = player.isKick(); + sanction.ifPresent(s -> event.getPlayer().disconnect(s.getKickMessage())); + if (getIneundo().getSTAFF_ONLY().get() && !player.getMainRank().isStaff()) event.getPlayer().disconnect(Component.translatable("event.join.staff")); + else { + //TODO server offline + redis.getConnection().set(RedisConstants.PLAYER_KEY(player.getUUID()), playersCollection.serialize(player).toJson()); + } + } + }); + } - CompletableFuture result = new CompletableFuture<>(); - result.completeAsync(subscriber::first); - result.whenCompleteAsync((re, th) -> { + private CompletionStage updateFromRedis(IslandsPlayer current) { + return redis.getConnection().get(current.getUUID().toString() + ":player").handleAsync((json, th) -> { if (th != null) - th.printStackTrace(); - getIneundo().removePlayer(player); - pendingResults.remove(subscriber); + error(new IneundoError("Cannot retrieve player data on redis...", th)); + + if (json != null) { + var retrieved = playersCollection.deserialize(Document.parse(json)); + Field[] fields = retrieved.getClass().getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + var newValue = field.get(retrieved); + if (newValue != null && !field.get(current).equals(newValue)) ReflectionUtil.setField(current, field.getName(), newValue); + } catch (IllegalAccessException e) { + error(e); + } + } + } + return current; }); } private void fetchPlayerData(UUID uuid) { - var publisher = playersCollection.findOne(Filters.eq("uuid", uuid.toString())); + var publisher = playersCollection.findOne(MongoConstants.PLAYER_ID_FILTER(uuid)); publisher.thenApplyAsync(player -> { - if (player == null) { - player = new IslandsPlayer(); - player.setUUID(uuid); - } else { - player.setLastConnection(); - } - return player; - }) - .thenAcceptAsync(player -> getIneundo().addPlayer(player)) - .orTimeout(mongoTimeout, mongoTimeoutUnit) - .exceptionallyAsync(throwable -> { - throwable.printStackTrace(); - return null; - }); + if (player == null) { + player = new IslandsPlayer(); + player.firstConection(uuid); + } else { + player.welcomeBack(); + } + return player; + }).thenAcceptAsync(player -> getIneundo().addPlayer(player)).orTimeout(mongoTimeout, mongoTimeoutUnit).exceptionallyAsync(th -> { + error(new IneundoError("MongoDB timeout when retrieving player data", th)); + return null; + }); } private CompletableFuture> getPlayerAsync(UUID uuid) { @@ -153,8 +181,7 @@ private CompletableFuture> getPlayerAsync(UUID uuid) { var scheduledTask = getServer().getScheduler().buildTask(getIneundo(), () -> { var player = getPlayer(uuid); - if (player.isPresent()) - future.complete(player); + if (player.isPresent()) future.complete(player); }).repeat(Duration.of(100, ChronoUnit.MILLIS)).schedule(); future.orTimeout(mongoTimeout, mongoTimeoutUnit).whenComplete((optPlayer, ex) -> { diff --git a/src/main/java/fr/islandswars/ineundo/locale/TranslationLoader.java b/src/main/java/fr/islandswars/ineundo/locale/TranslationLoader.java new file mode 100644 index 0000000..8b2f5e0 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/locale/TranslationLoader.java @@ -0,0 +1,64 @@ +package fr.islandswars.ineundo.locale; + +import fr.islandswars.commons.utils.Preconditions; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.translation.GlobalTranslator; +import net.kyori.adventure.translation.TranslationRegistry; +import net.kyori.adventure.util.UTF8ResourceBundleControl; +import org.intellij.lang.annotations.Subst; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * File TranslationLoader located on fr.islandswars.ineundo.locale + * TranslationLoader is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 21:27 + * @since 0.1 + */ +public class TranslationLoader { + + public void load(@Subst("locale.core") String bundleName) { + Preconditions.checkNotNull(bundleName); + + TranslationRegistry registry = TranslationRegistry.create(Key.key(bundleName)); + ResourceBundle bundleUS = ResourceBundle.getBundle(bundleName, Locale.US, UTF8ResourceBundleControl.get()); + ResourceBundle bundleFR = ResourceBundle.getBundle(bundleName, Locale.FRANCE, UTF8ResourceBundleControl.get()); + registry.registerAll(Locale.US, bundleUS, true); + registry.registerAll(Locale.FRANCE, bundleFR, true); + GlobalTranslator.translator().addSource(registry); + } + + public Component render(String key, ComponentLike... parameters) { + return Component.translatable(key, parameters); + } + + public Component render(Locale locale, String key, ComponentLike... parameters) { + return GlobalTranslator.render(render(key, parameters), locale); + } + + public Component renderDefault(String key, ComponentLike... parameters) { + return GlobalTranslator.render(Component.translatable(key, parameters), Locale.US); + } + +} diff --git a/src/main/java/fr/islandswars/ineundo/log/InternalLogger.java b/src/main/java/fr/islandswars/ineundo/log/InternalLogger.java new file mode 100644 index 0000000..580243b --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/InternalLogger.java @@ -0,0 +1,92 @@ +package fr.islandswars.ineundo.log; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import fr.islandswars.commons.utils.ReflectionUtil; +import fr.islandswars.ineundo.lang.IneundoError; +import fr.islandswars.ineundo.log.internal.DefaultLog; +import fr.islandswars.ineundo.log.internal.ErrorLog; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.config.Configurator; + +import java.net.URISyntaxException; + +/** + * File InternalLogger located on fr.islandswars.ineundo.log + * InternalLogger is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 19:21 + * @since 0.1 + */ +public class InternalLogger { + + private final Logger rootLogger; + private final Gson gson; + private final boolean debug; + + public InternalLogger() { + this.gson = new GsonBuilder().registerTypeAdapter(Level.class, new Log4jLevelSerializer()) + .registerTypeAdapter(StackTraceElement.class, new StackTraceElementTypeAdapter()).create(); + this.debug = Boolean.parseBoolean(System.getenv("DEBUG")); + this.rootLogger = (Logger) LogManager.getRootLogger(); + //overrideDefault(); TODO update + } + + private void overrideDefault() { + try { + Configurator.reconfigure(InternalLogger.class.getClassLoader().getResource("log4j2-islands.xml").toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + public void logInfo(String message) { + log(Level.INFO, message); + } + + public void log(Level level, String msg) { + if (level.equals(Level.ERROR)) + logError(new IneundoError(msg)); + else + new DefaultLog(level, msg).log(); + } + + public void logDebug(String message) { + log(Level.DEBUG, message); + } + + public T createCustomLog(Class clazz, Level level, String message) { + return ReflectionUtil.getConstructorAccessor(clazz, Level.class, String.class).newInstance(level, message); + } + + public void logError(Exception e) { + new ErrorLog(Level.ERROR, e.getMessage() == null ? "Error" : e.getMessage()).supplyStacktrace(e.fillInStackTrace()).log(); + } + + protected void sysout(Log object) { + if (object.getLevel() == Level.DEBUG) { + if (debug) + rootLogger.log(object.getLevel(), gson.toJson(object)); + } else + rootLogger.log(object.getLevel(), gson.toJson(object)); + } +} \ No newline at end of file diff --git a/src/main/java/fr/islandswars/ineundo/log/Log.java b/src/main/java/fr/islandswars/ineundo/log/Log.java new file mode 100644 index 0000000..92c54da --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/Log.java @@ -0,0 +1,62 @@ +package fr.islandswars.ineundo.log; + +import com.google.gson.annotations.SerializedName; +import fr.islandswars.ineundo.Ineundo; +import org.apache.logging.log4j.Level; + +import java.time.Instant; +import java.time.format.DateTimeFormatter; + + +/** + * File Log located on fr.islandswars.api.log + * Log is a part of islands. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * islands 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 26/03/2024 at 19:30 + * @since 0.1 + */ +public abstract class Log { + + protected final Level level; + @SerializedName("message") + protected final String msg; + protected String date; + + protected Log(Level level, String msg) { + this.level = level; + this.msg = msg; + } + + public void log() { + checkValue(); + this.date = DateTimeFormatter.ISO_INSTANT.format(Instant.now()); + Ineundo.getInstance().getInfraLogger().sysout(this); + } + + protected abstract void checkValue(); + + public Level getLevel() { + return level; + } + + public String getMessage() { + return msg; + } +} diff --git a/src/main/java/fr/islandswars/ineundo/log/Log4jLevelSerializer.java b/src/main/java/fr/islandswars/ineundo/log/Log4jLevelSerializer.java new file mode 100644 index 0000000..3b8ea9c --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/Log4jLevelSerializer.java @@ -0,0 +1,41 @@ +package fr.islandswars.ineundo.log; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.logging.log4j.Level; + +import java.lang.reflect.Type; + +/** + * File Log4jLevelSerializer located on fr.islandswars.core.internal.log + * Log4jLevelSerializer is a part of islands. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * islands 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 30/03/2024 at 17:51 + * @since 0.1 + */ +public class Log4jLevelSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(Level level, Type type, JsonSerializationContext jsonSerializationContext) { + return new JsonPrimitive(level.name()); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/log/StackTraceElementTypeAdapter.java b/src/main/java/fr/islandswars/ineundo/log/StackTraceElementTypeAdapter.java new file mode 100644 index 0000000..0400ee1 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/StackTraceElementTypeAdapter.java @@ -0,0 +1,48 @@ +package fr.islandswars.ineundo.log; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +/** + * File StackTraceElementTypeAdapter located on fr.islandswars.core.internal.log + * StackTraceElementTypeAdapter is a part of islands. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * islands 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 30/03/2024 at 18:08 + * @since 0.1 + */ +public class StackTraceElementTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, StackTraceElement value) throws IOException { + out.beginObject(); + out.name("className").value(value.getClassName()); + out.name("methodName").value(value.getMethodName()); + out.name("fileName").value(value.getFileName()); + out.name("lineNumber").value(value.getLineNumber()); + out.endObject(); + } + + @Override + public StackTraceElement read(JsonReader in) throws IOException { + throw new UnsupportedOperationException("Deserialization of StackTraceElement is not supported."); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/log/internal/DefaultLog.java b/src/main/java/fr/islandswars/ineundo/log/internal/DefaultLog.java new file mode 100644 index 0000000..c8c2a67 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/internal/DefaultLog.java @@ -0,0 +1,43 @@ +package fr.islandswars.ineundo.log.internal; + +import fr.islandswars.commons.utils.Preconditions; +import fr.islandswars.ineundo.log.Log; +import org.apache.logging.log4j.Level; + + +/** + * File DefaultLog located on fr.islandswars.api.log.internal + * DefaultLog is a part of islands. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * islands 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 26/03/2024 at 19:32 + * @since 0.1 + */ +public class DefaultLog extends Log { + + public DefaultLog(Level level, String msg) { + super(level, msg); + } + + @Override + protected void checkValue() { + Preconditions.checkNotNull(level); + Preconditions.checkNotNull(msg); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/log/internal/ErrorLog.java b/src/main/java/fr/islandswars/ineundo/log/internal/ErrorLog.java new file mode 100644 index 0000000..a19b112 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/log/internal/ErrorLog.java @@ -0,0 +1,44 @@ +package fr.islandswars.ineundo.log.internal; + +import com.google.gson.annotations.SerializedName; +import org.apache.logging.log4j.Level; + + +/** + * File ErrorLog located on fr.islandswars.api.log.internal + * ErrorLog is a part of islands. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * islands 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 26/03/2024 at 19:33 + * @since 0.1 + */ +public class ErrorLog extends DefaultLog { + + @SerializedName("stack-trace") + private StackTraceElement[] stackTrace; + + public ErrorLog(Level level, String msg) { + super(level, msg); + } + + public ErrorLog supplyStacktrace(Throwable throwable) { + this.stackTrace = throwable.getStackTrace(); + return this; + } +} diff --git a/src/main/java/fr/islandswars/ineundo/player/IslandsPlayer.java b/src/main/java/fr/islandswars/ineundo/player/IslandsPlayer.java index be1a52a..b32436b 100644 --- a/src/main/java/fr/islandswars/ineundo/player/IslandsPlayer.java +++ b/src/main/java/fr/islandswars/ineundo/player/IslandsPlayer.java @@ -2,11 +2,12 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; -import com.velocitypowered.api.proxy.ProxyServer; +import fr.islandswars.ineundo.Ineundo; import fr.islandswars.ineundo.player.sanction.IslandsSanction; +import fr.islandswars.ineundo.utils.ProxyConstants; +import fr.islandswars.ineundo.utils.TimeUtils; import java.time.Instant; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -41,7 +42,7 @@ public class IslandsPlayer { @Expose private UUID uuid; @Expose - private List ranks; + private List ranks; @SerializedName("first_connection") @Expose private String firstConnection; @@ -52,12 +53,22 @@ public class IslandsPlayer { private List sanctions; public IslandsPlayer() { - this.ranks = List.of(IslandsRank.PLAYER.toString()); - this.firstConnection = DateTimeFormatter.ISO_INSTANT.format(Instant.now()); - this.lastConnection = firstConnection; + this.ranks = new ArrayList<>(); + this.sanctions = new ArrayList<>(); } + public void firstConection(UUID uuid) { + setUUID(uuid); + this.firstConnection = TimeUtils.NOW(); + this.lastConnection = firstConnection; + addRank(new Rank(IslandsRank.PLAYER, ProxyConstants.PROXY, TimeUtils.NOW())); + } + + public void welcomeBack() { + setLastConnection(); + } + public IslandsRank getMainRank() { return IslandsRank.getHighest(ranks); } @@ -70,21 +81,21 @@ public void setUUID(UUID uuid) { this.uuid = uuid; } - public void setRanks(List ranks) { - this.ranks = ranks; - } - public void setLastConnection() { - this.lastConnection = DateTimeFormatter.ISO_INSTANT.format(Instant.now()); - } - - public String getFirstConnection() { - return firstConnection; + this.lastConnection = TimeUtils.NOW(); } public void addSanction(IslandsSanction sanction) { sanctions.add(sanction); - //TODO kick player with message + Ineundo.getInstance().getServer().getPlayer(getUUID()).ifPresent(p -> { + p.disconnect(sanction.getKickMessage()); + }); + } + + public void addRank(Rank rank) { + if (ranks.stream().noneMatch(r -> r.getRank().equals(rank.getRank()))) + ranks.add(rank); + //TODO notify the player and update it !! } public Optional isKick() { @@ -96,11 +107,5 @@ public Optional isKick() { } return Optional.empty(); } - - @Override - public String toString() { - //TODO recode - return "IslandsPlayer:" + uuid + ":" + ranks; - } } diff --git a/src/main/java/fr/islandswars/ineundo/player/IslandsRank.java b/src/main/java/fr/islandswars/ineundo/player/IslandsRank.java index 7b07abd..295aee7 100644 --- a/src/main/java/fr/islandswars/ineundo/player/IslandsRank.java +++ b/src/main/java/fr/islandswars/ineundo/player/IslandsRank.java @@ -1,7 +1,5 @@ package fr.islandswars.ineundo.player; -import java.util.Arrays; -import java.util.Comparator; import java.util.List; /** @@ -30,7 +28,8 @@ */ public enum IslandsRank { - ADMIn(1), + ADMIN(1), + STAFF(2), PLAYER(5); private final int rankLevel; @@ -39,8 +38,20 @@ public enum IslandsRank { this.rankLevel = rankLevel; } - public static IslandsRank getHighest(List ranks) { - return Arrays.stream(IslandsRank.values()).filter(r -> ranks.contains(r.name())).min(Comparator.comparingInt(IslandsRank::getRankLevel)).orElse(PLAYER); + public static IslandsRank getHighest(List ranks) { + var highestRank = PLAYER; + + for (var rank : ranks) { + var currentRank = rank.getRank(); + if (currentRank.getRankLevel() < highestRank.getRankLevel()) { + highestRank = currentRank; + } + } + return highestRank; + } + + public boolean isStaff() { + return getRankLevel() <= IslandsRank.STAFF.getRankLevel(); } public int getRankLevel() { diff --git a/src/main/java/fr/islandswars/ineundo/player/Rank.java b/src/main/java/fr/islandswars/ineundo/player/Rank.java new file mode 100644 index 0000000..0cb9d38 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/player/Rank.java @@ -0,0 +1,58 @@ +package fr.islandswars.ineundo.player; + +import com.google.gson.annotations.Expose; +import fr.islandswars.ineundo.utils.TimeUtils; + +import java.time.Instant; + +/** + * File Ranks located on fr.islandswars.ineundo.player + * Ranks is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 22:19 + * @since 0.1 + */ +public class Rank { + + @Expose + private String rank; + @Expose + private String author; + @Expose + private String date; + + public Rank(IslandsRank rank, String givenBy, String date) { + this.rank = rank.name(); + this.author = givenBy; + this.date = date; + } + + public Instant getDate() { + return TimeUtils.FROM_ISO_STRING(date); + } + + public String getAuthor() { + return author; + } + + public IslandsRank getRank() { + return IslandsRank.valueOf(rank); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/player/sanction/IslandsSanction.java b/src/main/java/fr/islandswars/ineundo/player/sanction/IslandsSanction.java index 7ef580d..72c6b54 100644 --- a/src/main/java/fr/islandswars/ineundo/player/sanction/IslandsSanction.java +++ b/src/main/java/fr/islandswars/ineundo/player/sanction/IslandsSanction.java @@ -1,13 +1,11 @@ package fr.islandswars.ineundo.player.sanction; import com.google.gson.annotations.Expose; +import net.kyori.adventure.text.Component; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalUnit; -import java.util.Date; import java.util.UUID; /** @@ -44,14 +42,16 @@ public class IslandsSanction { private String end; @Expose private UUID author; + @Expose + private String authorName; - public IslandsSanction(SanctionReason reason, UUID author) { + public IslandsSanction(SanctionReason reason, UUID author, String authorName) { this.reason = reason; this.author = author; + this.authorName = authorName; var now = Instant.now(); this.start = DateTimeFormatter.ISO_INSTANT.format(now); this.end = DateTimeFormatter.ISO_INSTANT.format(now.plus(reason.getDays(), ChronoUnit.DAYS)); - } public String getEnd() { @@ -62,11 +62,15 @@ public SanctionReason getReason() { return reason; } - public String getStart() { - return start; - } - public UUID getAuthor() { return author; } + + public String getAuthorName() { + return authorName; + } + + public Component getKickMessage() { + return Component.translatable(reason.getKickKey(), Component.text(authorName), Component.text(end)); + } } diff --git a/src/main/java/fr/islandswars/ineundo/player/sanction/SanctionReason.java b/src/main/java/fr/islandswars/ineundo/player/sanction/SanctionReason.java index cc7a087..2a2fe31 100644 --- a/src/main/java/fr/islandswars/ineundo/player/sanction/SanctionReason.java +++ b/src/main/java/fr/islandswars/ineundo/player/sanction/SanctionReason.java @@ -24,11 +24,10 @@ * Created the 24/06/2024 at 22:37 * @since 0.1 */ -//TODO get kick message i18n public enum SanctionReason { - CHEAT("You cheat", 7), - BEHAVIOR("Bad behavior", 365); + CHEAT("sanction.cheat", 7), + BEHAVIOR("sanction.behavior", 365); private final String kickKey; private final int days; diff --git a/src/main/java/fr/islandswars/ineundo/utils/MongoConstants.java b/src/main/java/fr/islandswars/ineundo/utils/MongoConstants.java new file mode 100644 index 0000000..7b980dc --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/utils/MongoConstants.java @@ -0,0 +1,40 @@ +package fr.islandswars.ineundo.utils; + +import com.mongodb.client.model.Filters; +import org.bson.conversions.Bson; + +import java.util.UUID; + +/** + * File MongoConstants located on fr.islandswars.ineundo.utils + * MongoConstants is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 21:51 + * @since 0.1 + */ +public class MongoConstants { + + public static final String PLAYER_COLLECTION = "players"; + private static final String PLAYER_ID = "uuid"; + + public static Bson PLAYER_ID_FILTER(UUID uuid) { + return Filters.eq(PLAYER_ID, uuid.toString()); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/utils/ProxyConstants.java b/src/main/java/fr/islandswars/ineundo/utils/ProxyConstants.java new file mode 100644 index 0000000..7eb0886 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/utils/ProxyConstants.java @@ -0,0 +1,31 @@ +package fr.islandswars.ineundo.utils; + +/** + * File ProxyConstants located on fr.islandswars.ineundo.utils + * ProxyConstants is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 22:36 + * @since 0.1 + */ +public class ProxyConstants { + + public static final String PROXY = "INEUNDO"; + +} diff --git a/src/main/java/fr/islandswars/ineundo/utils/RedisConstants.java b/src/main/java/fr/islandswars/ineundo/utils/RedisConstants.java new file mode 100644 index 0000000..4fd566f --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/utils/RedisConstants.java @@ -0,0 +1,36 @@ +package fr.islandswars.ineundo.utils; + +import java.util.UUID; + +/** + * File RedisConstants located on fr.islandswars.ineundo.utils + * RedisConstants is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 23:38 + * @since 0.1 + */ +public class RedisConstants { + + private static String PLAYER = "player"; + + public static String PLAYER_KEY(UUID uuid) { + return uuid.toString() + ":" + uuid.toString(); + } +} diff --git a/src/main/java/fr/islandswars/ineundo/utils/TimeUtils.java b/src/main/java/fr/islandswars/ineundo/utils/TimeUtils.java new file mode 100644 index 0000000..37dd1c2 --- /dev/null +++ b/src/main/java/fr/islandswars/ineundo/utils/TimeUtils.java @@ -0,0 +1,39 @@ +package fr.islandswars.ineundo.utils; + +import java.time.Instant; +import java.time.format.DateTimeFormatter; + +/** + * File TimeUtils located on fr.islandswars.ineundo.utils + * TimeUtils is a part of ineundo. + *

+ * Copyright (c) 2017 - 2024 Islands Wars. + *

+ * ineundo 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 + * (at your option) 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 GNU license. + *

+ * + * @author Jangliu, {@literal } + * Created the 25/06/2024 at 22:17 + * @since 0.1 + */ +public class TimeUtils { + + public static String NOW() { + return DateTimeFormatter.ISO_INSTANT.format(Instant.now()); + } + + public static Instant FROM_ISO_STRING(String date) { + return Instant.parse(date); + } +} diff --git a/src/main/resources/locale/ineundo_en_US.properties b/src/main/resources/locale/ineundo_en_US.properties new file mode 100644 index 0000000..e418b79 --- /dev/null +++ b/src/main/resources/locale/ineundo_en_US.properties @@ -0,0 +1,10 @@ +#Proxy +proxy.startup.database.error=Database error on startup... + +#Event +event.join.data.error=Cannot synchronize data... +event.join.staff=The server is for staff only access... + +#sanction +sanction.cheat=Ban for cheating by {0} until {1}. +sanction.behavior=Ban for bad behavior by {0} until {1}. \ No newline at end of file diff --git a/src/main/resources/locale/ineundo_fr_FR.properties b/src/main/resources/locale/ineundo_fr_FR.properties new file mode 100644 index 0000000..7879aee --- /dev/null +++ b/src/main/resources/locale/ineundo_fr_FR.properties @@ -0,0 +1,2 @@ +#Event +event.join.staff=Seulement pour les admins. \ No newline at end of file diff --git a/src/main/resources/log4j2-islands.xml b/src/main/resources/log4j2-islands.xml new file mode 100644 index 0000000..563b2b0 --- /dev/null +++ b/src/main/resources/log4j2-islands.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file