forked from SteamWar/SteamWar
Add SWPlayer for per player storage and without Memory Leaks
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.message.Message;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Delegate;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SWPlayer {
|
||||
|
||||
private static final Map<Player, SWPlayer> players = new HashMap<>();
|
||||
|
||||
private static class SWPlayerListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
SWPlayer.of(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
SWPlayer swPlayer = players.remove(event.getPlayer());
|
||||
swPlayer.components.forEach((aClass, component) -> {
|
||||
component.onUnmount(swPlayer);
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCRIUSleep(CRIUSleepEvent event) {
|
||||
for (SWPlayer value : players.values()) {
|
||||
value.components.forEach((aClass, component) -> {
|
||||
component.onUnmount(value);
|
||||
});
|
||||
}
|
||||
players.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Component {
|
||||
|
||||
default void onMount(SWPlayer player) {
|
||||
}
|
||||
|
||||
default void onUnmount(SWPlayer player) {
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
Bukkit.getPluginManager().registerEvents(new SWPlayerListener(), Core.getInstance());
|
||||
}
|
||||
|
||||
public static @NonNull SWPlayer of(@NonNull Player player) {
|
||||
return players.computeIfAbsent(player, SWPlayer::new);
|
||||
}
|
||||
|
||||
public static @NonNull Stream<SWPlayer> all() {
|
||||
return players.values().stream();
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static @NonNull Stream<SWPlayer> allWithComponent(Class<? extends Component> component, Class<? extends Component>... components) {
|
||||
Stream<SWPlayer> stream = players.values().stream()
|
||||
.filter(player -> player.components.containsKey(component));
|
||||
if (components != null) {
|
||||
for (Class<? extends Component> comp : components) {
|
||||
stream = stream.filter(player -> player.components.containsKey(comp));
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Delegate
|
||||
@Getter
|
||||
private final Player player;
|
||||
private final Map<Class<? extends Component>, Component> components = new HashMap<>();
|
||||
|
||||
private SWPlayer(@NonNull Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public boolean hasComponent(@NonNull Class<? extends Component> component) {
|
||||
return components.containsKey(component);
|
||||
}
|
||||
|
||||
public <T extends Component> @NonNull Optional<T> getComponent(@NonNull Class<T> clazz) {
|
||||
return Optional.ofNullable((T) components.get(clazz));
|
||||
}
|
||||
|
||||
public <T extends Component> @NonNull T getComponentOrDefault(@NonNull Class<T> clazz, @NonNull Supplier<T> defaultValue) {
|
||||
T value = (T) components.get(clazz);
|
||||
if (value != null) return value;
|
||||
value = defaultValue.get();
|
||||
setComponent(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public <T extends Component> SWPlayer setComponent(@NonNull T value) {
|
||||
Component component = components.put(value.getClass(), value);
|
||||
if (component != null) component.onUnmount(this);
|
||||
value.onMount(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T extends Component> SWPlayer removeComponent(@NonNull Class<T> clazz) {
|
||||
Component component = components.remove(clazz);
|
||||
if (component != null) component.onUnmount(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
private ThreadLocal<Message> messageThreadLocal = ThreadLocal.withInitial(() -> null);
|
||||
|
||||
public SWPlayer using(Message message) {
|
||||
this.messageThreadLocal.set(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
private Message getMessage() {
|
||||
Message message = this.messageThreadLocal.get();
|
||||
if (message == null) throw new IllegalStateException("Use #using(Message) before sending or parsing a message!");
|
||||
return message;
|
||||
}
|
||||
|
||||
public void sendMessage(String message, Object... params) {
|
||||
getMessage().send(message, player, ChatMessageType.SYSTEM, params);
|
||||
}
|
||||
|
||||
public void sendMessagePrefixless(String message, Object... params) {
|
||||
getMessage().sendPrefixless(message, player, ChatMessageType.SYSTEM, params);
|
||||
}
|
||||
|
||||
public void sendActionBar(String message, Object... params) {
|
||||
getMessage().sendPrefixless(message, player, ChatMessageType.ACTION_BAR, params);
|
||||
}
|
||||
|
||||
public void sendMessage(String message, String onHover, ClickEvent onClick, Object... params) {
|
||||
getMessage().send(message, true, player, ChatMessageType.SYSTEM, onHover, onClick, params);
|
||||
}
|
||||
|
||||
public void sendMessagePrefixless(String message, String onHover, ClickEvent onClick, Object... params) {
|
||||
getMessage().send(message, false, player, ChatMessageType.SYSTEM, onHover, onClick, params);
|
||||
}
|
||||
|
||||
public String parsePrefixed(String message, Object... params) {
|
||||
return getMessage().parsePrefixed(message, player, params);
|
||||
}
|
||||
|
||||
public String parse(String message, Object... params) {
|
||||
return getMessage().parse(message, player, params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user