finalized strikesystem
This commit is contained in:
@ -14,13 +14,12 @@ import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
public class CordLeak {
|
||||
private static final Path saveFile = Paths.get(Main.instance().getDataFolder().getAbsolutePath(), "cordleak.json");
|
||||
private static final Map<UUID, Location> locations = new HashMap<>();
|
||||
private static final Map<UUID, LeakInfo> leaks = new HashMap<>();
|
||||
|
||||
static {
|
||||
load();
|
||||
@ -36,18 +35,66 @@ public class CordLeak {
|
||||
}
|
||||
}
|
||||
|
||||
public record LeakInfo(Location location, Instant leakedAt) {}
|
||||
|
||||
private record LeakInfoDto(LocationDto location, long leakedAt) {
|
||||
static LeakInfoDto from(LeakInfo info) {
|
||||
return new LeakInfoDto(LocationDto.from(info.location), info.leakedAt.toEpochMilli());
|
||||
}
|
||||
|
||||
LeakInfo toLeakInfo() {
|
||||
return new LeakInfo(this.location.toLocation(), Instant.ofEpochMilli(this.leakedAt));
|
||||
}
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
IteratorUtil.onlinePlayers(player -> locations.put(player.getUniqueId(), player.getLocation()));
|
||||
IteratorUtil.onlinePlayers(player -> {
|
||||
UUID uuid = player.getUniqueId();
|
||||
Location loc = player.getLocation();
|
||||
|
||||
leaks.compute(uuid, (key, existing) -> {
|
||||
// Falls bereits geleakt, nicht aktualisieren
|
||||
if (existing != null && !existing.leakedAt.equals(Instant.EPOCH)) {
|
||||
return existing;
|
||||
}
|
||||
return new LeakInfo(loc, existing != null ? existing.leakedAt : Instant.EPOCH);
|
||||
});
|
||||
});
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), CordLeak::save);
|
||||
}
|
||||
|
||||
public static void markAsLeaked(UUID uuid) {
|
||||
LeakInfo existing = leaks.get(uuid);
|
||||
if (existing == null) return;
|
||||
leaks.put(uuid, new LeakInfo(existing.location, Instant.now()));
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), CordLeak::save);
|
||||
}
|
||||
|
||||
public static LeakInfo getLastKnownLocation(UUID uuid) {
|
||||
return leaks.get(uuid);
|
||||
}
|
||||
|
||||
public static Map<UUID, LeakInfo> getAllLeaked() {
|
||||
Map<UUID, LeakInfo> result = new HashMap<>();
|
||||
Instant cutoff = Instant.now().minusSeconds(3 * 24 * 60 * 60); // 3 Tage in Sekunden
|
||||
|
||||
for (Map.Entry<UUID, LeakInfo> entry : leaks.entrySet()) {
|
||||
LeakInfo info = entry.getValue();
|
||||
if (info.leakedAt.isAfter(cutoff)) {
|
||||
result.put(entry.getKey(), info);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void load() {
|
||||
if (!Files.exists(saveFile)) return;
|
||||
try (Reader reader = Files.newBufferedReader(saveFile)) {
|
||||
Type type = new TypeToken<Map<String, LocationDto>>() {}.getType();
|
||||
Map<String, LocationDto> raw = new Gson().fromJson(reader, type);
|
||||
for (Map.Entry<String, LocationDto> entry : raw.entrySet()) {
|
||||
locations.put(UUID.fromString(entry.getKey()), entry.getValue().toLocation());
|
||||
Type type = new TypeToken<Map<String, LeakInfoDto>>() {}.getType();
|
||||
Map<String, LeakInfoDto> raw = new Gson().fromJson(reader, type);
|
||||
for (Map.Entry<String, LeakInfoDto> entry : raw.entrySet()) {
|
||||
leaks.put(UUID.fromString(entry.getKey()), entry.getValue().toLeakInfo());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Main.logger().warning("Failed to load CordLeak data: " + e.getMessage());
|
||||
@ -57,9 +104,9 @@ public class CordLeak {
|
||||
private static void save() {
|
||||
try {
|
||||
Files.createDirectories(saveFile.getParent());
|
||||
Map<String, LocationDto> raw = new HashMap<>();
|
||||
for (Map.Entry<UUID, Location> entry : locations.entrySet()) {
|
||||
raw.put(entry.getKey().toString(), LocationDto.from(entry.getValue()));
|
||||
Map<String, LeakInfoDto> raw = new HashMap<>();
|
||||
for (Map.Entry<UUID, LeakInfo> entry : leaks.entrySet()) {
|
||||
raw.put(entry.getKey().toString(), LeakInfoDto.from(entry.getValue()));
|
||||
}
|
||||
try (Writer writer = Files.newBufferedWriter(saveFile)) {
|
||||
new Gson().toJson(raw, writer);
|
||||
@ -68,8 +115,4 @@ public class CordLeak {
|
||||
Main.logger().warning("Failed to save CordLeak data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Location getLastKnownLocation(UUID uuid) {
|
||||
return locations.get(uuid);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ public class InvClear {
|
||||
}
|
||||
|
||||
public static void add(UUID player) {
|
||||
Main.logger().info(String.format("Cannot clear inv because Player is offline. Remembering %s", player));
|
||||
players.add(player);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), InvClear::save);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.strike;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
@ -8,5 +10,16 @@ public class OnStrikeActionListener extends ApplianceListener<Strike> {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
this.getAppliance().checkJoin(event.getPlayer());
|
||||
|
||||
var leaks = CordLeak.getAllLeaked();
|
||||
var text = Component.text();
|
||||
if(!leaks.isEmpty()) {
|
||||
text.append(Component.text("Geleakte Koordinaten:", NamedTextColor.AQUA));
|
||||
leaks.forEach((uuid, leakInfo) -> {
|
||||
this.getAppliance().appendCordLeak(text, uuid);
|
||||
});
|
||||
|
||||
event.getPlayer().sendMessage(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -32,9 +34,6 @@ public class Strike extends Appliance {
|
||||
);
|
||||
}
|
||||
|
||||
public void leakCoordinates() {
|
||||
}
|
||||
|
||||
record StrikeInfo(List<UUID> users, int totalWeight) {
|
||||
}
|
||||
@Override
|
||||
@ -47,8 +46,31 @@ public class Strike extends Appliance {
|
||||
this.processUpdate(data);
|
||||
return HttpServer.nothing;
|
||||
});
|
||||
|
||||
apiBuilder.get("cords", req -> {
|
||||
Map<UUID, CordLeak.LeakInfo> raw = CordLeak.getAllLeaked();
|
||||
Map<String, LeakInfoDto> dto = new HashMap<>();
|
||||
for (Map.Entry<UUID, CordLeak.LeakInfo> entry : raw.entrySet()) {
|
||||
dto.put(entry.getKey().toString(), LeakInfoDto.from(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return dto;
|
||||
});
|
||||
}
|
||||
|
||||
record LocationDto(String world, double x, double y, double z, float yaw, float pitch) {
|
||||
static LocationDto from(Location loc) {
|
||||
return new LocationDto(loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
||||
}
|
||||
}
|
||||
|
||||
record LeakInfoDto(String name, LocationDto location, long leakedAt) {
|
||||
static LeakInfoDto from(UUID uuid, CordLeak.LeakInfo info) {
|
||||
String name = Bukkit.getOfflinePlayer(uuid).getName();
|
||||
return new LeakInfoDto(name, LocationDto.from(info.location()), info.leakedAt().toEpochMilli());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processUpdate(StrikeInfo data) {
|
||||
try {
|
||||
VaroTeam select = null;
|
||||
@ -59,46 +81,33 @@ public class Strike extends Appliance {
|
||||
Objects.requireNonNull(select);
|
||||
VaroTeam team = select;
|
||||
|
||||
switch(data.totalWeight) {
|
||||
case 0 -> team.members.forEach(member -> {
|
||||
Main.logger().info(String.format("Unbanning player %s because there are now 0 Strikes!", member.player.getName()));
|
||||
if(data.totalWeight < 3) {
|
||||
team.members.forEach(member -> {
|
||||
Main.logger().info(String.format("Unbanning player %s because there are less than 3 Strikes!", member.player.getName()));
|
||||
Bukkit.getBanList(BanListType.PROFILE).pardon(member.player.getPlayerProfile());
|
||||
});
|
||||
}
|
||||
|
||||
switch(data.totalWeight) {
|
||||
case 1 -> {
|
||||
Main.logger().info(String.format("Cord leak for Team %s", team.name));
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> text = Component.text()
|
||||
.append(
|
||||
Component.text(
|
||||
String.format("Das Team %s hat einen Strike erhalten. Daher werden folgende Koordinaten des Teams veröffentlicht:", team.name),
|
||||
NamedTextColor.RED
|
||||
)
|
||||
);
|
||||
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> text = Component.text();
|
||||
IteratorUtil.onlinePlayers(player -> player.sendMessage(Component.text(
|
||||
String.format("Das Team %s hat einen Strike erhalten. Daher werden folgende Koordinaten des Teams veröffentlicht:", team.name),
|
||||
NamedTextColor.RED
|
||||
)));
|
||||
|
||||
data.users.forEach(uuid -> {
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
|
||||
Location cords = CordLeak.getLastKnownLocation(uuid);
|
||||
if(cords == null) return;
|
||||
|
||||
text.appendNewline();
|
||||
text.append(Component.text(Objects.requireNonNull(player.getName()), NamedTextColor.DARK_AQUA));
|
||||
text.append(Component.text(": ", NamedTextColor.GRAY));
|
||||
text.append(Component.text(
|
||||
String.format(
|
||||
"(%s) %d, %d, %d",
|
||||
cords.getWorld().getName(),
|
||||
cords.getBlockX(),
|
||||
cords.getBlockY(),
|
||||
cords.getBlockZ()
|
||||
),
|
||||
NamedTextColor.AQUA)
|
||||
);
|
||||
CordLeak.markAsLeaked(uuid);
|
||||
this.appendCordLeak(text, uuid);
|
||||
});
|
||||
|
||||
IteratorUtil.onlinePlayers(player -> player.sendMessage(text));
|
||||
IteratorUtil.onlinePlayers(p -> p.sendMessage(text));
|
||||
}
|
||||
|
||||
case 2 -> team.members.forEach(member -> {
|
||||
Main.logger().info(String.format("Clearing Inventory of %s", member.player.getName()));
|
||||
Optional<Player> player = Optional.ofNullable(Bukkit.getPlayer(member.player.getUniqueId()));
|
||||
player.ifPresentOrElse(
|
||||
p -> p.getInventory().clear(),
|
||||
@ -110,9 +119,9 @@ public class Strike extends Appliance {
|
||||
team.members.forEach(member -> {
|
||||
Main.logger().info(String.format("Banning player %s because of third Strike!", member.player.getName()));
|
||||
Bukkit.getBanList(BanListType.PROFILE)
|
||||
.addBan(member.player.getPlayerProfile(), "projektausschluiss", (Date) null, null);
|
||||
.addBan(member.player.getPlayerProfile(), "projektausschluss", (Date) null, null);
|
||||
});
|
||||
team.getOnlinePlayers().forEach(Player::kick);
|
||||
Bukkit.getScheduler().runTask(Main.instance(), () -> team.getOnlinePlayers().forEach(Player::kick));
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
@ -121,6 +130,31 @@ public class Strike extends Appliance {
|
||||
}
|
||||
}
|
||||
|
||||
public void appendCordLeak(ComponentBuilder<TextComponent, TextComponent.Builder> text, UUID playerToLeak) {
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(playerToLeak);
|
||||
CordLeak.LeakInfo cords = CordLeak.getLastKnownLocation(playerToLeak);
|
||||
if(cords == null) return;
|
||||
|
||||
String timestamp = DateTimeFormatter.ofPattern("dd.MM HH:mm")
|
||||
.withZone(ZoneId.of("Europe/Berlin"))
|
||||
.format(cords.leakedAt());
|
||||
|
||||
text.appendNewline();
|
||||
text.append(Component.text(Objects.requireNonNull(player.getName()), NamedTextColor.DARK_AQUA));
|
||||
text.append(Component.text(": ", NamedTextColor.GRAY));
|
||||
text.append(Component.text(
|
||||
String.format(
|
||||
"(%s) %d, %d, %d - Uhrzeit: %s",
|
||||
cords.location().getWorld().getName(),
|
||||
cords.location().getBlockX(),
|
||||
cords.location().getBlockY(),
|
||||
cords.location().getBlockZ(),
|
||||
timestamp
|
||||
),
|
||||
NamedTextColor.AQUA)
|
||||
);
|
||||
}
|
||||
|
||||
public void checkJoin(@NotNull Player player) {
|
||||
if(InvClear.contains(player.getUniqueId())) {
|
||||
player.getInventory().clear();
|
||||
|
@ -5,6 +5,7 @@ import eu.mhsl.craftattack.spawn.core.Main;
|
||||
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
|
||||
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
|
||||
import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.playTimer.PlayTimer;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
@ -46,19 +47,24 @@ class ConnectivityChangeListener extends ApplianceListener<Teams> {
|
||||
|
||||
VaroTeam team = Main.instance().getAppliance(Teams.class).getTeamFromPlayer(event.getPlayer().getUniqueId());
|
||||
Objects.requireNonNull(team, "Team not found for player " + event.getPlayer().getUniqueId());
|
||||
Main.logger().info(String.format("Team %s got a Strike, because they %s left early!", team.name, event.getPlayer().getName()));
|
||||
|
||||
VaroReportRepository.StrikeCreationInfo report = new VaroReportRepository.StrikeCreationInfo(
|
||||
null,
|
||||
event.getPlayer().getUniqueId(),
|
||||
"early left",
|
||||
"player left the server too early",
|
||||
null,
|
||||
null,
|
||||
1
|
||||
);
|
||||
ReqResp<Void> response = Main.instance().getRepositoryLoader().getRepository(VaroReportRepository.class).createStrike(report);
|
||||
Main.logger().info(String.format("Autostrike response for Team %s: %s", team.name, response));
|
||||
if(Main.instance().getAppliance(PlayTimer.class).isEnabled()) {
|
||||
Main.logger().info(String.format("Team %s got a Strike, because they %s left early!", team.name, event.getPlayer().getName()));
|
||||
|
||||
VaroReportRepository.StrikeCreationInfo report = new VaroReportRepository.StrikeCreationInfo(
|
||||
null,
|
||||
event.getPlayer().getUniqueId(),
|
||||
"early left",
|
||||
"player left the server too early",
|
||||
null,
|
||||
null,
|
||||
1
|
||||
);
|
||||
ReqResp<Void> response = Main.instance().getRepositoryLoader().getRepository(VaroReportRepository.class).createStrike(report);
|
||||
Main.logger().info(String.format("Autostrike response for Team %s: %s", team.name, response));
|
||||
} else {
|
||||
Main.logger().info("Allow ealry leave because PlayTimer is not active!");
|
||||
}
|
||||
|
||||
this.getAppliance().enforceTeamLeave(event.getPlayer());
|
||||
}
|
||||
|
Reference in New Issue
Block a user