diff --git a/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogEntry.java b/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogEntry.java index 99fcd6e..39ed6ec 100644 --- a/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogEntry.java +++ b/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogEntry.java @@ -31,6 +31,14 @@ public static LogEntry of(DamageSource source, LivingEntity target, @Nullable Li } private static Path path(Player player, @Nullable LivingEntity other, String type, String time) { + return entityPath(player.getScoreboardName(), other, type, time); + } + + private static Path entityPath(UUID uuid, @Nullable LivingEntity other, String type, String time) { + return entityPath(uuid.toString(), other, type, time); + } + + private static Path entityPath(String id, @Nullable LivingEntity other, String type, String time) { String otherType; if (other == null) { otherType = "null"; @@ -40,7 +48,7 @@ private static Path path(Player player, @Nullable LivingEntity other, String typ otherType = rl.getPath().replaceAll("/", "_"); } return FMLPaths.GAMEDIR.get().resolve("logs/damage_tracker/" + - player.getScoreboardName() + "-" + type + "/" + otherType + "/" + time + ".txt"); + id + "-" + type + "/" + otherType + "/" + time + ".txt"); } private final DamageSource source; @@ -61,8 +69,12 @@ private LogEntry(DamageSource source, LivingEntity target, @Nullable LivingEntit info = L2DamageTrackerConfig.COMMON.printDamageTrace.get(); if (target instanceof ServerPlayer player && LogHelper.savePlayerHurt(player)) saves.add(path(player, attacker, "hurt", time)); + else if (!(target instanceof ServerPlayer) && LogHelper.saveEntityHurt(target)) + saves.add(entityPath(target.getUUID(), attacker, "hurt", time)); if (attacker instanceof ServerPlayer player && LogHelper.savePlayerAttack(player)) saves.add(path(player, target, "attack", time)); + else if (attacker != null && !(attacker instanceof ServerPlayer) && LogHelper.saveEntityAttack(attacker)) + saves.add(entityPath(attacker.getUUID(), target, "attack", time)); trace = !saves.isEmpty(); log = info || trace; if (log) { diff --git a/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogHelper.java b/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogHelper.java index bbd4e99..04f99dc 100644 --- a/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogHelper.java +++ b/src/main/java/dev/xkmc/l2damagetracker/contents/attack/LogHelper.java @@ -2,10 +2,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xkmc.l2damagetracker.init.data.L2DamageTrackerConfig; @@ -13,10 +11,11 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.selector.EntitySelector; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.LivingEntity; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -27,16 +26,12 @@ public enum Type { ATTACK, HURT } - private record Key(Type type, UUID uuid) { + private record Key(Type type, UUID uuid) {} - } - - private record Val(long time, String playerName, @Nullable CommandSource source) { - - } + private record Val(long time, UUID uuid, @Nullable CommandSource source) {} private static final Map MAP = new HashMap<>(); - private static final Val NULL = new Val(0, "", null); + private static final Val NULL = new Val(0, new UUID(0, 0), null); public static boolean savePlayerHurt(ServerPlayer player) { @@ -53,57 +48,59 @@ private static long time(ServerPlayer player) { return player.server.overworld().getGameTime(); } + public static boolean saveEntityHurt(LivingEntity entity) { + if (entity.level() instanceof ServerLevel sl) + return MAP.getOrDefault(new Key(Type.HURT, entity.getUUID()), NULL).time() > sl.getGameTime(); + return false; + } + + public static boolean saveEntityAttack(LivingEntity entity) { + if (entity.level() instanceof ServerLevel sl) + return MAP.getOrDefault(new Key(Type.ATTACK, entity.getUUID()), NULL).time() > sl.getGameTime(); + return false; + } + public static void buildCommand(LiteralArgumentBuilder base) { base.requires(e -> e.hasPermission(2)) - .then(Commands.literal("player") - .then(argument("player", EntityArgument.players()) - .then(Commands.literal("attack") - .then(Commands.argument("time", IntegerArgumentType.integer(1, 20 * 60 * 60 * 24)) - .executes(ctx -> onStart(ctx, Type.ATTACK)))) - .then(Commands.literal("hurt") - .then(Commands.argument("time", IntegerArgumentType.integer(1, 20 * 60 * 60 * 24)) - .executes(ctx -> onStart(ctx, Type.HURT))))) - ); + .then(Commands.argument("entities", EntityArgument.entities()) + .then(Commands.literal("attack") + .then(Commands.argument("time", IntegerArgumentType.integer(1, 20 * 60 * 60 * 24)) + .executes(ctx -> onStart(ctx, Type.ATTACK)))) + .then(Commands.literal("hurt") + .then(Commands.argument("time", IntegerArgumentType.integer(1, 20 * 60 * 60 * 24)) + .executes(ctx -> onStart(ctx, Type.HURT))))); } public static void tick(MinecraftServer server) { Multimap removed = HashMultimap.create(); + long gameTime = server.overworld().getGameTime(); MAP.entrySet().removeIf(ent -> { - var player = server.getPlayerList().getPlayer(ent.getKey().uuid()); - if (player == null || ent.getValue().time() < time(player)) { - removed.put(ent.getValue().source(), ent.getValue().playerName()); - return true; - } - return false; + Val val = ent.getValue(); + if (val.time() >= gameTime) return false; + removed.put(val.source(), val.uuid().toString()); + return true; }); for (var ent : removed.asMap().entrySet()) { - String pl = ent.getValue().size() == 1 ? new ArrayList<>(ent.getValue()).get(0) : ent.getValue().size() + " players"; + String pl = ent.getValue().size() == 1 ? new ArrayList<>(ent.getValue()).get(0) : ent.getValue().size() + " entities"; ent.getKey().sendSystemMessage(Component.literal("Finished damage profiling for " + pl)); } - } - private static int onStart(CommandContext ctx, Type type) throws CommandSyntaxException { int time = ctx.getArgument("time", Integer.class); - EntitySelector sel = ctx.getArgument("player", EntitySelector.class); - var list = sel.findPlayers(ctx.getSource()); + var list = EntityArgument.getEntities(ctx, "entities"); + long expires = ctx.getSource().getServer().overworld().getGameTime() + time; for (var e : list) { - MAP.put(new Key(type, e.getUUID()), new Val(e.server.overworld().getGameTime() + time, e.getScoreboardName(), ctx.getSource().source)); + MAP.put(new Key(type, e.getUUID()), new Val(expires, e.getUUID(), ctx.getSource().source)); } int sec = time / 20; int min = sec / 60; int hrs = min / 60; String str = String.format("%02d:%02d:%02d", hrs % 24, min % 60, sec % 60); String side = type.name().toLowerCase(Locale.ROOT); - String pl = list.size() == 1 ? list.get(0).getScoreboardName() : list.size() + " players"; + String pl = list.size() == 1 ? list.iterator().next().getUUID().toString() : list.size() + " entities"; ctx.getSource().sendSuccess(() -> Component.literal("Start profiling " + side + " of " + pl + " with time " + str), true); return 1; } - protected static RequiredArgumentBuilder argument(String name, ArgumentType type) { - return RequiredArgumentBuilder.argument(name, type); - } - - }