From b3764bd6c4c8df66fd9e0e3547de4bce5157702c Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:20:20 +0200 Subject: [PATCH 01/10] GH-1142 Add message placeholders for `msg_toggle` and `socialspy_status` * Register new placeholders for `msg_toggle` and `socialspy_status` in `MsgPlaceholderSetup`. * Extend `MsgMessages` with a `Placeholders` interface and implement language-specific placeholder formats in `ENMsgMessages` and `PLMsgMessages`. --- .../core/feature/msg/MsgPlaceholderSetup.java | 44 +++++++++++++++++++ .../feature/msg/messages/ENMsgMessages.java | 17 +++++++ .../feature/msg/messages/MsgMessages.java | 10 +++++ .../feature/msg/messages/PLMsgMessages.java | 16 +++++++ 4 files changed, 87 insertions(+) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java new file mode 100644 index 000000000..9fa64aa4c --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -0,0 +1,44 @@ +package com.eternalcode.core.feature.msg; + +import com.eternalcode.core.feature.msg.toggle.MsgState; +import com.eternalcode.core.feature.msg.toggle.MsgToggleService; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Controller; +import com.eternalcode.core.placeholder.PlaceholderRegistry; +import com.eternalcode.core.placeholder.PlaceholderReplacer; +import com.eternalcode.core.publish.Subscribe; +import com.eternalcode.core.publish.event.EternalInitializeEvent; +import java.util.UUID; + +@Controller +class MsgPlaceholderSetup { + + private final MsgService msgService; + private final MsgToggleService msgToggleService; + + @Inject + MsgPlaceholderSetup(MsgService msgService, MsgToggleService msgToggleService) { + this.msgService = msgService; + this.msgToggleService = msgToggleService; + } + + @Subscribe(EternalInitializeEvent.class) + void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( + "socialspy_status", + player -> { + UUID uuid = player.getUniqueId(); + return String.valueOf(this.msgService.isSpy(uuid)); + } + )); + + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( + "msg_toggle", + player -> { + UUID uuid = player.getUniqueId(); + MsgState state = this.msgToggleService.getState(uuid).join(); + return state.name().toLowerCase(); + } + )); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java index 2f353548f..f6fcb919f 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java @@ -36,4 +36,21 @@ public class ENMsgMessages extends OkaeriConfig implements MsgMessages { public Notice socialSpyEnable = Notice.chat("SocialSpy has been {STATE}!"); public Notice socialSpyDisable = Notice.chat("SocialSpy has been {STATE}!"); + @Comment("# Formatowanie placeholderów") + public ENPlaceholders placeholders = new ENPlaceholders(); + + @Getter + @Accessors(fluent = true) + public static class ENPlaceholders implements MsgMessages.Placeholders { + + private String msgEnabled = "Enabled"; + private String msgDisabled = "Disabled"; + private String socialSpyEnabled = "Enabled"; + private String socialSpyDisabled = "Disabled"; + } + + public ENPlaceholders placeholders() { + return this.placeholders; + } + } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java index 070f0b391..9a3d30d99 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java @@ -17,4 +17,14 @@ public interface MsgMessages { Notice otherMessagesDisabled(); Notice otherMessagesEnabled(); + Placeholders placeholders(); + + interface Placeholders { + String msgEnabled(); + String msgDisabled(); + + String socialSpyEnabled(); + String socialSpyDisabled(); + } + } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java index ece54845e..4fc650d99 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java @@ -37,4 +37,20 @@ public class PLMsgMessages extends OkaeriConfig implements MsgMessages { public Notice otherMessagesDisabled = Notice.chat("Wiadomości prywatne zostały wyłączone dla gracza {PLAYER}!"); public Notice otherMessagesEnabled = Notice.chat("Wiadomości prywatne zostały włączone dla gracza {PLAYER}!"); + @Comment("# Formatowanie placeholderów") + public PLPlaceholders placeholders = new PLPlaceholders(); + + @Getter + @Accessors(fluent = true) + public static class PLPlaceholders implements MsgMessages.Placeholders { + + private String msgEnabled = "Włączone"; + private String msgDisabled = "Wyłączone"; + private String socialSpyEnabled = "Włączony"; + private String socialSpyDisabled = "Wyłączony"; + } + + public PLPlaceholders placeholders() { + return this.placeholders; + } } From af593f148e4bb0801c76d8cefd542c7fa4785636 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:28:46 +0200 Subject: [PATCH 02/10] GH-1143 Enhance `MsgPlaceholderSetup` with caching and new placeholders * Add caching logic for `msg_toggle` state in `MsgPlaceholderSetup`. * Introduce new formatted placeholders for `msg_toggle` and `socialspy_status`. * Extend `MsgMessages.Placeholders` to support a loading state with translations. --- .../core/feature/msg/MsgPlaceholderSetup.java | 76 ++++++++++++++++++- .../feature/msg/messages/ENMsgMessages.java | 1 + .../feature/msg/messages/MsgMessages.java | 2 + .../feature/msg/messages/PLMsgMessages.java | 1 + 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index 9fa64aa4c..3574d5f38 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -8,22 +8,35 @@ import com.eternalcode.core.placeholder.PlaceholderReplacer; import com.eternalcode.core.publish.Subscribe; import com.eternalcode.core.publish.event.EternalInitializeEvent; +import com.eternalcode.core.translation.Translation; +import com.eternalcode.core.translation.TranslationManager; +import java.time.Duration; +import java.time.Instant; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; @Controller class MsgPlaceholderSetup { + private static final Duration CACHE_DURATION = Duration.ofMillis(200); + private final MsgService msgService; private final MsgToggleService msgToggleService; + private final TranslationManager translationManager; + private final ConcurrentHashMap stateCache = new ConcurrentHashMap<>(); @Inject - MsgPlaceholderSetup(MsgService msgService, MsgToggleService msgToggleService) { + MsgPlaceholderSetup(MsgService msgService, MsgToggleService msgToggleService, TranslationManager translationManager) { this.msgService = msgService; this.msgToggleService = msgToggleService; + this.translationManager = translationManager; } @Subscribe(EternalInitializeEvent.class) void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { + Translation translation = this.translationManager.getMessages(); + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "socialspy_status", player -> { @@ -32,13 +45,72 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { } )); + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( + "socialspy_status_formatted", + player -> { + UUID uuid = player.getUniqueId(); + return this.msgService.isSpy(uuid) + ? translation.msg().placeholders().socialSpyEnabled() + : translation.msg().placeholders().socialSpyDisabled(); + } + )); + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "msg_toggle", player -> { UUID uuid = player.getUniqueId(); - MsgState state = this.msgToggleService.getState(uuid).join(); + MsgState state = this.getCachedOrLoadState(uuid); + + if (state == null) { + return translation.msg().placeholders().loading(); + } + return state.name().toLowerCase(); } )); + + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( + "msg_toggle_formatted", + player -> { + UUID uuid = player.getUniqueId(); + MsgState state = this.getCachedOrLoadState(uuid); + + if (state == null) { + return translation.msg().placeholders().loading(); + } + + return state == MsgState.ENABLED + ? translation.msg().placeholders().msgEnabled() + : translation.msg().placeholders().msgDisabled(); + } + )); + } + + private MsgState getCachedOrLoadState(UUID uuid) { + CachedState cached = this.stateCache.get(uuid); + + if (cached != null && !cached.isExpired()) { + return cached.state(); + } + + CompletableFuture future = this.msgToggleService.getState(uuid); + + if (future.isDone() && !future.isCompletedExceptionally()) { + MsgState state = future.join(); + this.stateCache.put(uuid, new CachedState(state, Instant.now())); + return state; + } + + future.thenAccept(state -> + this.stateCache.put(uuid, new CachedState(state, Instant.now())) + ); + + return null; + } + + private record CachedState(MsgState state, Instant timestamp) { + boolean isExpired() { + return Duration.between(this.timestamp, Instant.now()).compareTo(CACHE_DURATION) > 0; + } } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java index f6fcb919f..f88543128 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java @@ -42,6 +42,7 @@ public class ENMsgMessages extends OkaeriConfig implements MsgMessages { @Getter @Accessors(fluent = true) public static class ENPlaceholders implements MsgMessages.Placeholders { + private String loading = "Loading..."; private String msgEnabled = "Enabled"; private String msgDisabled = "Disabled"; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java index 9a3d30d99..9f5831a70 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/MsgMessages.java @@ -20,6 +20,8 @@ public interface MsgMessages { Placeholders placeholders(); interface Placeholders { + String loading(); + String msgEnabled(); String msgDisabled(); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java index 4fc650d99..d2c5d9500 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java @@ -43,6 +43,7 @@ public class PLMsgMessages extends OkaeriConfig implements MsgMessages { @Getter @Accessors(fluent = true) public static class PLPlaceholders implements MsgMessages.Placeholders { + private String loading = "Ładowanie..."; private String msgEnabled = "Włączone"; private String msgDisabled = "Wyłączone"; From 1f98392020814621dae10357f8ab860211355a62 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:43:37 +0200 Subject: [PATCH 03/10] GH-1144 Update `MsgPlaceholderSetup` caching and integrate `PlaceholderAPI` * Adjust cache duration in `MsgPlaceholderSetup` from 200ms to 5s. * Rename `msg_toggle` placeholders to `msg_status` for consistency. * Extend `ENPlaceholders` and `PLPlaceholders` with `OkaeriConfig`. * Add `PlaceholderAPI` dependency in `runServer` task configuration. --- .../eternalcode/core/feature/msg/MsgPlaceholderSetup.java | 6 +++--- .../core/feature/msg/messages/ENMsgMessages.java | 2 +- .../core/feature/msg/messages/PLMsgMessages.java | 2 +- eternalcore-plugin/build.gradle.kts | 6 +++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index 3574d5f38..37839fe26 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -19,7 +19,7 @@ @Controller class MsgPlaceholderSetup { - private static final Duration CACHE_DURATION = Duration.ofMillis(200); + private static final Duration CACHE_DURATION = Duration.ofSeconds(5); private final MsgService msgService; private final MsgToggleService msgToggleService; @@ -56,7 +56,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { )); placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( - "msg_toggle", + "msg_status", player -> { UUID uuid = player.getUniqueId(); MsgState state = this.getCachedOrLoadState(uuid); @@ -70,7 +70,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { )); placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( - "msg_toggle_formatted", + "msg_status_formatted", player -> { UUID uuid = player.getUniqueId(); MsgState state = this.getCachedOrLoadState(uuid); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java index f88543128..143dd1e47 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/ENMsgMessages.java @@ -41,7 +41,7 @@ public class ENMsgMessages extends OkaeriConfig implements MsgMessages { @Getter @Accessors(fluent = true) - public static class ENPlaceholders implements MsgMessages.Placeholders { + public static class ENPlaceholders extends OkaeriConfig implements MsgMessages.Placeholders { private String loading = "Loading..."; private String msgEnabled = "Enabled"; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java index d2c5d9500..581083182 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/messages/PLMsgMessages.java @@ -42,7 +42,7 @@ public class PLMsgMessages extends OkaeriConfig implements MsgMessages { @Getter @Accessors(fluent = true) - public static class PLPlaceholders implements MsgMessages.Placeholders { + public static class PLPlaceholders extends OkaeriConfig implements MsgMessages.Placeholders { private String loading = "Ładowanie..."; private String msgEnabled = "Włączone"; diff --git a/eternalcore-plugin/build.gradle.kts b/eternalcore-plugin/build.gradle.kts index 0bf93dae7..bc0e2fe24 100644 --- a/eternalcore-plugin/build.gradle.kts +++ b/eternalcore-plugin/build.gradle.kts @@ -37,6 +37,10 @@ dependencies { tasks { runServer { minecraftVersion("1.21.8") - downloadPlugins.modrinth("luckperms", "v${Versions.LUCKPERMS}-bukkit") + + downloadPlugins { + modrinth("luckperms", "v${Versions.LUCKPERMS}-bukkit") + modrinth("placeholderapi", Versions.PLACEHOLDER_API) + } } } From cf7151ecb02695f522d102b00f719fdd4de3ab58 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 12:54:40 +0200 Subject: [PATCH 04/10] Refactor `MsgPlaceholderSetup` with new caching system * Replace existing cache in `MsgPlaceholderSetup` with `AsyncPlaceholderCached`. * Introduce `AsyncPlaceholderCacheRegistry` for managing placeholder caches. * Add `AsyncPlaceholderCacheController` to handle cache invalidation on player quit. * Simplify placeholder logic and remove redundant caching methods. --- .../core/feature/msg/MsgPlaceholderSetup.java | 49 +++-------------- .../AsyncPlaceholderCacheController.java | 24 +++++++++ .../cache/AsyncPlaceholderCacheRegistry.java | 53 +++++++++++++++++++ .../cache/AsyncPlaceholderCached.java | 51 ++++++++++++++++++ 4 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheRegistry.java create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index 37839fe26..10f7a29c2 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -4,33 +4,27 @@ import com.eternalcode.core.feature.msg.toggle.MsgToggleService; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; +import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCached; import com.eternalcode.core.placeholder.PlaceholderRegistry; import com.eternalcode.core.placeholder.PlaceholderReplacer; import com.eternalcode.core.publish.Subscribe; import com.eternalcode.core.publish.event.EternalInitializeEvent; import com.eternalcode.core.translation.Translation; import com.eternalcode.core.translation.TranslationManager; -import java.time.Duration; -import java.time.Instant; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; @Controller class MsgPlaceholderSetup { - private static final Duration CACHE_DURATION = Duration.ofSeconds(5); - private final MsgService msgService; - private final MsgToggleService msgToggleService; private final TranslationManager translationManager; - private final ConcurrentHashMap stateCache = new ConcurrentHashMap<>(); + private final AsyncPlaceholderCached stateCache; @Inject MsgPlaceholderSetup(MsgService msgService, MsgToggleService msgToggleService, TranslationManager translationManager) { this.msgService = msgService; - this.msgToggleService = msgToggleService; this.translationManager = translationManager; + this.stateCache = new AsyncPlaceholderCached<>(msgToggleService::getState); } @Subscribe(EternalInitializeEvent.class) @@ -39,10 +33,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "socialspy_status", - player -> { - UUID uuid = player.getUniqueId(); - return String.valueOf(this.msgService.isSpy(uuid)); - } + player -> String.valueOf(this.msgService.isSpy(player.getUniqueId())) )); placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( @@ -59,7 +50,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { "msg_status", player -> { UUID uuid = player.getUniqueId(); - MsgState state = this.getCachedOrLoadState(uuid); + MsgState state = this.stateCache.getCached(uuid); if (state == null) { return translation.msg().placeholders().loading(); @@ -73,7 +64,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { "msg_status_formatted", player -> { UUID uuid = player.getUniqueId(); - MsgState state = this.getCachedOrLoadState(uuid); + MsgState state = this.stateCache.getCached(uuid); if (state == null) { return translation.msg().placeholders().loading(); @@ -86,31 +77,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { )); } - private MsgState getCachedOrLoadState(UUID uuid) { - CachedState cached = this.stateCache.get(uuid); - - if (cached != null && !cached.isExpired()) { - return cached.state(); - } - - CompletableFuture future = this.msgToggleService.getState(uuid); - - if (future.isDone() && !future.isCompletedExceptionally()) { - MsgState state = future.join(); - this.stateCache.put(uuid, new CachedState(state, Instant.now())); - return state; - } - - future.thenAccept(state -> - this.stateCache.put(uuid, new CachedState(state, Instant.now())) - ); - - return null; - } - - private record CachedState(MsgState state, Instant timestamp) { - boolean isExpired() { - return Duration.between(this.timestamp, Instant.now()).compareTo(CACHE_DURATION) > 0; - } + public AsyncPlaceholderCached getStateCache() { + return this.stateCache; } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java new file mode 100644 index 000000000..bb0c8c6ac --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java @@ -0,0 +1,24 @@ +package com.eternalcode.core.placeholder.cache; + +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Controller; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +@Controller +class AsyncPlaceholderCacheController implements Listener { + + private final AsyncPlaceholderCacheRegistry cacheRegistry; + + @Inject + AsyncPlaceholderCacheController(AsyncPlaceholderCacheRegistry cacheRegistry) { + this.cacheRegistry = cacheRegistry; + } + + @EventHandler(priority = EventPriority.MONITOR) + void onPlayerQuit(PlayerQuitEvent event) { + this.cacheRegistry.invalidatePlayer(event.getPlayer().getUniqueId()); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheRegistry.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheRegistry.java new file mode 100644 index 000000000..7b20a99b4 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheRegistry.java @@ -0,0 +1,53 @@ +package com.eternalcode.core.placeholder.cache; + +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Service; +import java.time.Duration; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +@Service +public class AsyncPlaceholderCacheRegistry { + + private static final Duration DEFAULT_EXPIRE_DURATION = Duration.ofMinutes(30); + + private final Map> caches = new ConcurrentHashMap<>(); + + @Inject + public AsyncPlaceholderCacheRegistry() { + } + + public AsyncPlaceholderCached register(String key, Function> loader) { + return this.register(key, loader, DEFAULT_EXPIRE_DURATION); + } + + public AsyncPlaceholderCached register(String key, Function> loader, Duration expireAfterWrite) { + AsyncPlaceholderCached cache = new AsyncPlaceholderCached<>(loader, expireAfterWrite); + this.caches.put(key, cache); + return cache; + } + + @SuppressWarnings("unchecked") + public Optional> get(String key) { + return Optional.ofNullable((AsyncPlaceholderCached) this.caches.get(key)); + } + + public void invalidatePlayer(UUID uuid) { + this.caches.values().forEach(cache -> cache.invalidate(uuid)); + } + + public void invalidateAll() { + this.caches.values().forEach(AsyncPlaceholderCached::clear); + } + + public void unregister(String key) { + AsyncPlaceholderCached cache = this.caches.remove(key); + if (cache != null) { + cache.clear(); + } + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java new file mode 100644 index 000000000..b0d05b58d --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java @@ -0,0 +1,51 @@ +package com.eternalcode.core.placeholder.cache; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public class AsyncPlaceholderCached { + + private final Cache cache; + private final Function> loader; + + public AsyncPlaceholderCached(Function> loader, Duration expireAfterWrite) { + this.loader = loader; + this.cache = CacheBuilder.newBuilder() + .expireAfterWrite(expireAfterWrite) + .build(); + } + + public T getCached(UUID uuid) { + T cached = this.cache.getIfPresent(uuid); + + if (cached != null) { + return cached; + } + + this.loader.apply(uuid).thenAccept(value -> + this.cache.put(uuid, value) + ); + + return null; + } + + public void update(UUID uuid, T value) { + this.cache.put(uuid, value); + } + + public void invalidate(UUID uuid) { + this.cache.invalidate(uuid); + } + + public void clear() { + this.cache.invalidateAll(); + } + + public boolean contains(UUID uuid) { + return this.cache.getIfPresent(uuid) != null; + } +} From 1407a2862f176b5a69b30ffe893f658bdf90e705 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:03:59 +0200 Subject: [PATCH 05/10] Refactor `MsgPlaceholderSetup` to enhance caching with `AsyncPlaceholderCacheRegistry` * Replace individual `stateCache` with dynamically registered cache in the `AsyncPlaceholderCacheRegistry`. * Simplify placeholder setup logic and adjust `MsgToggleService` to utilize the registry for cache management. --- .../core/feature/msg/MsgPlaceholderSetup.java | 35 ++++++++++++------ .../msg/toggle/MsgToggleServiceImpl.java | 36 ++++++++++++------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index 10f7a29c2..b98b93122 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -4,33 +4,50 @@ import com.eternalcode.core.feature.msg.toggle.MsgToggleService; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; -import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCached; import com.eternalcode.core.placeholder.PlaceholderRegistry; import com.eternalcode.core.placeholder.PlaceholderReplacer; +import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCacheRegistry; +import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCached; import com.eternalcode.core.publish.Subscribe; import com.eternalcode.core.publish.event.EternalInitializeEvent; import com.eternalcode.core.translation.Translation; import com.eternalcode.core.translation.TranslationManager; +import java.time.Duration; import java.util.UUID; @Controller -class MsgPlaceholderSetup { +public class MsgPlaceholderSetup { + + public static final String MSG_STATE_CACHE_KEY = "msg_state"; private final MsgService msgService; + private final MsgToggleService msgToggleService; private final TranslationManager translationManager; - private final AsyncPlaceholderCached stateCache; + private final AsyncPlaceholderCacheRegistry cacheRegistry; @Inject - MsgPlaceholderSetup(MsgService msgService, MsgToggleService msgToggleService, TranslationManager translationManager) { + MsgPlaceholderSetup( + MsgService msgService, + MsgToggleService msgToggleService, + TranslationManager translationManager, + AsyncPlaceholderCacheRegistry cacheRegistry + ) { this.msgService = msgService; + this.msgToggleService = msgToggleService; this.translationManager = translationManager; - this.stateCache = new AsyncPlaceholderCached<>(msgToggleService::getState); + this.cacheRegistry = cacheRegistry; } @Subscribe(EternalInitializeEvent.class) void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { Translation translation = this.translationManager.getMessages(); + AsyncPlaceholderCached stateCache = this.cacheRegistry.register( + MSG_STATE_CACHE_KEY, + this.msgToggleService::getState, + Duration.ofMinutes(10) + ); + placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "socialspy_status", player -> String.valueOf(this.msgService.isSpy(player.getUniqueId())) @@ -50,7 +67,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { "msg_status", player -> { UUID uuid = player.getUniqueId(); - MsgState state = this.stateCache.getCached(uuid); + MsgState state = stateCache.getCached(uuid); if (state == null) { return translation.msg().placeholders().loading(); @@ -64,7 +81,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { "msg_status_formatted", player -> { UUID uuid = player.getUniqueId(); - MsgState state = this.stateCache.getCached(uuid); + MsgState state = stateCache.getCached(uuid); if (state == null) { return translation.msg().placeholders().loading(); @@ -76,8 +93,4 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { } )); } - - public AsyncPlaceholderCached getStateCache() { - return this.stateCache; - } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java index 227d40e5d..066f29324 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java @@ -1,41 +1,51 @@ package com.eternalcode.core.feature.msg.toggle; +import com.eternalcode.core.feature.msg.MsgPlaceholderSetup; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; +import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCacheRegistry; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; @Service class MsgToggleServiceImpl implements MsgToggleService { private final MsgToggleRepository msgToggleRepository; - private final ConcurrentHashMap cachedToggleStates; + private final AsyncPlaceholderCacheRegistry cacheRegistry; @Inject - MsgToggleServiceImpl(MsgToggleRepository msgToggleRepository) { - this.cachedToggleStates = new ConcurrentHashMap<>(); + MsgToggleServiceImpl(MsgToggleRepository msgToggleRepository, AsyncPlaceholderCacheRegistry cacheRegistry) { this.msgToggleRepository = msgToggleRepository; - + this.cacheRegistry = cacheRegistry; } - @Override public CompletableFuture getState(UUID playerUniqueId) { - if (this.cachedToggleStates.containsKey(playerUniqueId)) { - return CompletableFuture.completedFuture(this.cachedToggleStates.get(playerUniqueId)); - } - - return this.msgToggleRepository.getPrivateChatState(playerUniqueId); + return this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) + .map(cache -> { + MsgState cached = cache.getCached(playerUniqueId); + if (cached != null) { + return CompletableFuture.completedFuture(cached); + } + + return this.msgToggleRepository.getPrivateChatState(playerUniqueId) + .thenApply(state -> { + cache.update(playerUniqueId, state); + return state; + }); + }) + .orElseGet(() -> this.msgToggleRepository.getPrivateChatState(playerUniqueId)); } @Override public CompletableFuture setState(UUID playerUniqueId, MsgState state) { - this.cachedToggleStates.put(playerUniqueId, state); + this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) + .ifPresent(cache -> cache.update(playerUniqueId, state)); return this.msgToggleRepository.setPrivateChatState(playerUniqueId, state) .exceptionally(throwable -> { - this.cachedToggleStates.remove(playerUniqueId); + this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) + .ifPresent(cache -> cache.invalidate(playerUniqueId)); return null; }); } From a8c66595eba8bb591ca0c8376d136cf566f680c4 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:07:03 +0200 Subject: [PATCH 06/10] Enhance `AsyncPlaceholderCacheController` with event-based cache invalidation * Add `Subscribe` annotations to invalidate cache on `EternalReloadEvent` and `EternalShutdownEvent`. --- .../cache/AsyncPlaceholderCacheController.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java index bb0c8c6ac..543cdf373 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java @@ -2,6 +2,9 @@ import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; +import com.eternalcode.core.publish.Subscribe; +import com.eternalcode.core.publish.event.EternalReloadEvent; +import com.eternalcode.core.publish.event.EternalShutdownEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -21,4 +24,14 @@ class AsyncPlaceholderCacheController implements Listener { void onPlayerQuit(PlayerQuitEvent event) { this.cacheRegistry.invalidatePlayer(event.getPlayer().getUniqueId()); } + + @Subscribe + void onEternalDisable(EternalShutdownEvent event) { + this.cacheRegistry.invalidateAll(); + } + + @Subscribe + void onEternalDisable(EternalReloadEvent event) { + this.cacheRegistry.invalidateAll(); + } } From 2633ef6a292375f975c5bd4e8c7005f95efe808a Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:07:32 +0200 Subject: [PATCH 07/10] Refactor `AsyncPlaceholderCacheController` event methods * Rename `onEternalDisable` to `onDisable` and `onReload`. --- .../placeholder/cache/AsyncPlaceholderCacheController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java index 543cdf373..b8d182a97 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCacheController.java @@ -26,12 +26,12 @@ void onPlayerQuit(PlayerQuitEvent event) { } @Subscribe - void onEternalDisable(EternalShutdownEvent event) { + void onDisable(EternalShutdownEvent event) { this.cacheRegistry.invalidateAll(); } @Subscribe - void onEternalDisable(EternalReloadEvent event) { + void onReload(EternalReloadEvent event) { this.cacheRegistry.invalidateAll(); } } From dc6f963d53865bf0681417e49d4a70720b22a298 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:11:56 +0200 Subject: [PATCH 08/10] the bomb was defused xd --- .../core/feature/msg/MsgPlaceholderSetup.java | 10 +++--- .../msg/toggle/MsgToggleRepository.java | 2 +- .../msg/toggle/MsgToggleServiceImpl.java | 35 +++++++++---------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index b98b93122..959c30d71 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -1,7 +1,7 @@ package com.eternalcode.core.feature.msg; import com.eternalcode.core.feature.msg.toggle.MsgState; -import com.eternalcode.core.feature.msg.toggle.MsgToggleService; +import com.eternalcode.core.feature.msg.toggle.MsgToggleRepository; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; import com.eternalcode.core.placeholder.PlaceholderRegistry; @@ -21,19 +21,19 @@ public class MsgPlaceholderSetup { public static final String MSG_STATE_CACHE_KEY = "msg_state"; private final MsgService msgService; - private final MsgToggleService msgToggleService; + private final MsgToggleRepository msgToggleRepository; private final TranslationManager translationManager; private final AsyncPlaceholderCacheRegistry cacheRegistry; @Inject MsgPlaceholderSetup( MsgService msgService, - MsgToggleService msgToggleService, + MsgToggleRepository msgToggleRepository, TranslationManager translationManager, AsyncPlaceholderCacheRegistry cacheRegistry ) { this.msgService = msgService; - this.msgToggleService = msgToggleService; + this.msgToggleRepository = msgToggleRepository; this.translationManager = translationManager; this.cacheRegistry = cacheRegistry; } @@ -44,7 +44,7 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { AsyncPlaceholderCached stateCache = this.cacheRegistry.register( MSG_STATE_CACHE_KEY, - this.msgToggleService::getState, + this.msgToggleRepository::getPrivateChatState, Duration.ofMinutes(10) ); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleRepository.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleRepository.java index 51c429ae0..3853c49e8 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleRepository.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleRepository.java @@ -4,7 +4,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; -interface MsgToggleRepository { +public interface MsgToggleRepository { CompletableFuture getPrivateChatState(UUID uuid); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java index 066f29324..4fedb03c1 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java @@ -21,31 +21,20 @@ class MsgToggleServiceImpl implements MsgToggleService { @Override public CompletableFuture getState(UUID playerUniqueId) { - return this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) - .map(cache -> { - MsgState cached = cache.getCached(playerUniqueId); - if (cached != null) { - return CompletableFuture.completedFuture(cached); - } - - return this.msgToggleRepository.getPrivateChatState(playerUniqueId) - .thenApply(state -> { - cache.update(playerUniqueId, state); - return state; - }); - }) - .orElseGet(() -> this.msgToggleRepository.getPrivateChatState(playerUniqueId)); + return this.msgToggleRepository.getPrivateChatState(playerUniqueId) + .thenApply(state -> { + this.updateCache(playerUniqueId, state); + return state; + }); } @Override public CompletableFuture setState(UUID playerUniqueId, MsgState state) { - this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) - .ifPresent(cache -> cache.update(playerUniqueId, state)); + this.updateCache(playerUniqueId, state); return this.msgToggleRepository.setPrivateChatState(playerUniqueId, state) .exceptionally(throwable -> { - this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) - .ifPresent(cache -> cache.invalidate(playerUniqueId)); + this.invalidateCache(playerUniqueId); return null; }); } @@ -58,4 +47,14 @@ public CompletableFuture toggleState(UUID playerUniqueId) { .thenApply(aVoid -> newState); }); } + + private void updateCache(UUID uuid, MsgState state) { + this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) + .ifPresent(cache -> cache.update(uuid, state)); + } + + private void invalidateCache(UUID uuid) { + this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) + .ifPresent(cache -> cache.invalidate(uuid)); + } } From aa360ddacfe2b9ce9912b21f18b6cd2687ee9f48 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:30:52 +0200 Subject: [PATCH 09/10] Follow gemini comment --- .../placeholder/cache/AsyncPlaceholderCached.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java index b0d05b58d..1e0bcd597 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/cache/AsyncPlaceholderCached.java @@ -3,14 +3,17 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.time.Duration; +import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; public class AsyncPlaceholderCached { private final Cache cache; private final Function> loader; + private final Map> loading = new ConcurrentHashMap<>(); public AsyncPlaceholderCached(Function> loader, Duration expireAfterWrite) { this.loader = loader; @@ -21,18 +24,21 @@ public AsyncPlaceholderCached(Function> loader, Durat public T getCached(UUID uuid) { T cached = this.cache.getIfPresent(uuid); - if (cached != null) { return cached; } - this.loader.apply(uuid).thenAccept(value -> - this.cache.put(uuid, value) + this.loading.computeIfAbsent(uuid, key -> + this.loader.apply(key).whenComplete((value, throwable) -> { + if (value != null) { + this.cache.put(key, value); + } + this.loading.remove(key); + }) ); return null; } - public void update(UUID uuid, T value) { this.cache.put(uuid, value); } From a1281541d4f65631c73b0f9d27f843d43b401ab4 Mon Sep 17 00:00:00 2001 From: Piotr Zych <77621271+P1otrulla@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:49:36 +0200 Subject: [PATCH 10/10] Follow gemini comment --- .../core/feature/msg/MsgPlaceholderSetup.java | 50 +++++++++++-------- .../msg/toggle/MsgToggleServiceImpl.java | 17 +++---- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java index 959c30d71..99829ed75 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgPlaceholderSetup.java @@ -14,6 +14,7 @@ import com.eternalcode.core.translation.TranslationManager; import java.time.Duration; import java.util.UUID; +import java.util.function.Function; @Controller public class MsgPlaceholderSetup { @@ -65,32 +66,39 @@ void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "msg_status", - player -> { - UUID uuid = player.getUniqueId(); - MsgState state = stateCache.getCached(uuid); - - if (state == null) { - return translation.msg().placeholders().loading(); - } - - return state.name().toLowerCase(); - } + player -> this.formatMsgState( + player.getUniqueId(), + stateCache, + translation, + state -> state.name().toLowerCase() + ) )); placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( "msg_status_formatted", - player -> { - UUID uuid = player.getUniqueId(); - MsgState state = stateCache.getCached(uuid); - - if (state == null) { - return translation.msg().placeholders().loading(); - } - - return state == MsgState.ENABLED + player -> this.formatMsgState( + player.getUniqueId(), + stateCache, + translation, + state -> state == MsgState.ENABLED ? translation.msg().placeholders().msgEnabled() - : translation.msg().placeholders().msgDisabled(); - } + : translation.msg().placeholders().msgDisabled() + ) )); } + + private String formatMsgState( + UUID uuid, + AsyncPlaceholderCached stateCache, + Translation translation, + Function formatter + ) { + MsgState state = stateCache.getCached(uuid); + + if (state == null) { + return translation.msg().placeholders().loading(); + } + + return formatter.apply(state); + } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java index 4fedb03c1..d3d063523 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/toggle/MsgToggleServiceImpl.java @@ -4,8 +4,10 @@ import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCacheRegistry; +import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCached; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; @Service class MsgToggleServiceImpl implements MsgToggleService { @@ -23,18 +25,18 @@ class MsgToggleServiceImpl implements MsgToggleService { public CompletableFuture getState(UUID playerUniqueId) { return this.msgToggleRepository.getPrivateChatState(playerUniqueId) .thenApply(state -> { - this.updateCache(playerUniqueId, state); + this.withCache(cache -> cache.update(playerUniqueId, state)); return state; }); } @Override public CompletableFuture setState(UUID playerUniqueId, MsgState state) { - this.updateCache(playerUniqueId, state); + this.withCache(cache -> cache.update(playerUniqueId, state)); return this.msgToggleRepository.setPrivateChatState(playerUniqueId, state) .exceptionally(throwable -> { - this.invalidateCache(playerUniqueId); + this.withCache(cache -> cache.invalidate(playerUniqueId)); return null; }); } @@ -48,13 +50,8 @@ public CompletableFuture toggleState(UUID playerUniqueId) { }); } - private void updateCache(UUID uuid, MsgState state) { + private void withCache(Consumer> action) { this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) - .ifPresent(cache -> cache.update(uuid, state)); - } - - private void invalidateCache(UUID uuid) { - this.cacheRegistry.get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) - .ifPresent(cache -> cache.invalidate(uuid)); + .ifPresent(action); } }