forked from SteamWar/SteamWar
Add SWPlayer for per player storage and without Memory Leaks
This commit is contained in:
+39
-60
@@ -21,9 +21,10 @@ package de.steamwar.bausystem.features.countingwand;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.region.Point;
|
import de.steamwar.bausystem.region.Point;
|
||||||
import de.steamwar.bausystem.shared.Pair;
|
|
||||||
import de.steamwar.bausystem.utils.ItemUtils;
|
import de.steamwar.bausystem.utils.ItemUtils;
|
||||||
|
import de.steamwar.core.SWPlayer;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
|
import lombok.Data;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -31,13 +32,32 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Countingwand {
|
public class Countingwand {
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CountingWandComponent implements SWPlayer.Component {
|
||||||
|
private Point pos1;
|
||||||
|
private Point pos2;
|
||||||
|
|
||||||
|
public boolean set(boolean pos1, Point point) {
|
||||||
|
if (this.pos1 == null || this.pos2 == null) {
|
||||||
|
this.pos1 = point;
|
||||||
|
this.pos2 = point;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Point current = pos1 ? this.pos1 : this.pos2;
|
||||||
|
if (current.equals(point)) return false;
|
||||||
|
if (pos1) {
|
||||||
|
this.pos1 = point;
|
||||||
|
} else {
|
||||||
|
this.pos2 = point;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static ItemStack getWandItem(Player player) {
|
public static ItemStack getWandItem(Player player) {
|
||||||
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
||||||
ItemUtils.setItem(itemStack, "countingwand");
|
ItemUtils.setItem(itemStack, "countingwand");
|
||||||
@@ -47,61 +67,20 @@ public class Countingwand {
|
|||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, Pair<Point, Point>> selections = new HashMap<>();
|
public boolean isCountingwand(ItemStack itemStack) {
|
||||||
|
return ItemUtils.isItem(itemStack, "countingwand");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCountingwand(ItemStack itemStack) {
|
public void checkSelection(final Point point, final boolean pos1, final Player p) {
|
||||||
return ItemUtils.isItem(itemStack, "countingwand");
|
SWPlayer player = SWPlayer.of(p);
|
||||||
}
|
CountingWandComponent countingWandComponent = player.getComponentOrDefault(CountingWandComponent.class, CountingWandComponent::new);
|
||||||
|
if (countingWandComponent.set(pos1, point)) {
|
||||||
public void checkSelection(final Point point, final boolean pos1, final Player p) {
|
Point point1 = countingWandComponent.pos1;
|
||||||
Pair<Point, Point> selection = selections.get(p.getUniqueId().toString());
|
Point point2 = countingWandComponent.pos2;
|
||||||
final boolean newPos;
|
int amount = (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
|
||||||
if (selection != null) {
|
String dimension = player.using(BauSystem.MESSAGE).parse("COUNTINGWAND_MESSAGE_VOLUME", amount);
|
||||||
if (pos1) {
|
String volume = player.parse("COUNTINGWAND_MESSAGE_DIMENSION", Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
|
||||||
newPos = !point.equals(selection.setKey(point));
|
player.sendMessage(pos1 ? "COUNTINGWAND_MESSAGE_RCLICK" : "COUNTINGWAND_MESSAGE_LCLICK", point.getX(), point.getY(), point.getZ(), dimension, volume);
|
||||||
} else {
|
}
|
||||||
newPos = !point.equals(selection.setValue(point));
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pos1) {
|
|
||||||
selection = new Pair<>(point, null);
|
|
||||||
} else {
|
|
||||||
selection = new Pair<>(null, point);
|
|
||||||
}
|
|
||||||
selections.put(p.getUniqueId().toString(), selection);
|
|
||||||
newPos = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newPos) {
|
|
||||||
String dimension = getDimensions(p, selection.getKey(), selection.getValue());
|
|
||||||
String volume = getVolume(p, selection.getKey(), selection.getValue());
|
|
||||||
if (pos1) {
|
|
||||||
BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_RCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
|
|
||||||
} else {
|
|
||||||
BauSystem.MESSAGE.send("COUNTINGWAND_MESSAGE_LCLICK", p, point.getX(), point.getY(), point.getZ(), dimension, volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removePlayer(Player p) {
|
|
||||||
selections.remove(p.getUniqueId().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVolume(Player player, final Point point1, final Point point2) {
|
|
||||||
if (point1 == null || point2 == null) {
|
|
||||||
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, 0);
|
|
||||||
}
|
|
||||||
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_VOLUME", player, getAmount(point1, point2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDimensions(Player player, final Point point1, final Point point2) {
|
|
||||||
if (point1 == null || point2 == null) {
|
|
||||||
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, 0, 0, 0);
|
|
||||||
}
|
|
||||||
return BauSystem.MESSAGE.parse("COUNTINGWAND_MESSAGE_DIMENSION", player, Math.abs(point1.getX() - point2.getX()) + 1, Math.abs(point1.getY() - point2.getY()) + 1, Math.abs(point1.getZ() - point2.getZ()) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAmount(final Point point1, final Point point2) {
|
|
||||||
return (Math.abs(point1.getX() - point2.getX()) + 1) * (Math.abs(point1.getY() - point2.getY()) + 1) * (Math.abs(point1.getZ() - point2.getZ()) + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
-6
@@ -27,7 +27,6 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.util.RayTraceResult;
|
import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -67,9 +66,4 @@ public class CountingwandListener implements Listener {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onLeave(PlayerQuitEvent event) {
|
|
||||||
Countingwand.removePlayer(event.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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