11package com.lambda.client.module.modules.misc
22
33import com.lambda.client.event.events.ConnectionEvent
4+ import com.lambda.client.event.events.RenderWorldEvent
45import com.lambda.client.event.listener.asyncListener
6+ import com.lambda.client.event.listener.listener
57import com.lambda.client.manager.managers.WaypointManager
68import com.lambda.client.module.Category
79import com.lambda.client.module.Module
8- import com.lambda.client.util.EntityUtils.flooredPosition
10+ import com.lambda.client.module.modules.client.GuiColors
911import com.lambda.client.util.EntityUtils.isFakeOrSelf
1012import com.lambda.client.util.TickTimer
1113import com.lambda.client.util.TimeUnit
14+ import com.lambda.client.util.graphics.ESPRenderer
1215import com.lambda.client.util.math.CoordinateConverter.asString
16+ import com.lambda.client.util.math.VectorUtils.toBlockPos
1317import com.lambda.client.util.text.MessageSendHelper
1418import com.lambda.client.util.threads.onMainThread
1519import com.lambda.client.util.threads.safeListener
1620import com.mojang.authlib.GameProfile
1721import net.minecraft.client.entity.EntityOtherPlayerMP
18- import net.minecraft.util.math.BlockPos
22+ import net.minecraft.util.text.TextFormatting
1923import net.minecraftforge.fml.common.gameevent.TickEvent
24+ import java.util.concurrent.ConcurrentHashMap
2025
2126object LogoutLogger : Module(
2227 name = " LogoutLogger" ,
2328 description = " Logs when a player leaves the game" ,
2429 category = Category .MISC
2530) {
26- private val saveWaypoint by setting(" Save Waypoint" , true )
31+ private val saveWaypoint by setting(" Save Waypoint" , false )
2732 private val print by setting(" Print To Chat" , true )
33+ private val esp by setting(" ESP" , true )
34+ private val espFilledAlpha by setting(" ESP Filled Alpha" , 47 , 0 .. 255 , 1 , { esp })
35+ private val espOutlineAlpha by setting(" ESP Outline Alpha" , 0 , 0 .. 255 , 1 , { esp })
36+ private val espColor by setting(" ESP Color" , GuiColors .primary, false , { esp })
37+ private val clearEsp by setting(" Clear ESP" , true , { esp })
2838
29- private val loggedPlayers = LinkedHashMap <GameProfile , BlockPos >()
30- private val timer = TickTimer (TimeUnit .SECONDS )
39+ private val loggedPlayers = ConcurrentHashMap <GameProfile , EntityOtherPlayerMP >()
40+ val loggedOutPlayers = ConcurrentHashMap <GameProfile , EntityOtherPlayerMP >()
41+ private val renderer = ESPRenderer ()
42+ private val renderTimer = TickTimer (TimeUnit .SECONDS )
3143
3244 init {
3345 asyncListener<ConnectionEvent .Disconnect > {
3446 onMainThread {
3547 loggedPlayers.clear()
48+ if (clearEsp) loggedOutPlayers.clear()
3649 }
3750 }
3851
3952 safeListener<TickEvent .ClientTickEvent > {
4053 if (it.phase != TickEvent .Phase .END ) return @safeListener
4154
42- for (loadedPlayer in world.playerEntities) {
43- if (loadedPlayer !is EntityOtherPlayerMP ) continue
44- if (loadedPlayer.isFakeOrSelf) continue
55+ world.playerEntities
56+ .filterIsInstance<EntityOtherPlayerMP >()
57+ .filter { entityOtherPlayerMP -> ! entityOtherPlayerMP.isFakeOrSelf }
58+ .forEach { entityOtherPlayerMP ->
59+ @Suppress(" UNNECESSARY_SAFE_CALL" )
60+ connection.getPlayerInfo(entityOtherPlayerMP.gameProfile.id)?.let { networkPlayerInfo ->
61+ loggedPlayers[networkPlayerInfo.gameProfile] = entityOtherPlayerMP
4562
46- val info = connection.getPlayerInfo(loadedPlayer.gameProfile.id) ? : continue
47- loggedPlayers[info.gameProfile] = loadedPlayer.flooredPosition
48- }
49-
50- if (timer.tick(1L )) {
51- val toRemove = ArrayList <GameProfile >()
63+ loggedOutPlayers.entries.removeIf { (profile, _) ->
64+ profile.id == networkPlayerInfo.gameProfile.id
65+ }
66+ }
67+ }
5268
53- loggedPlayers.entries.removeIf { (profile, pos) ->
54- @Suppress(" SENSELESS_COMPARISON" )
55- if (connection.getPlayerInfo(profile.id) == null ) {
56- if (saveWaypoint) WaypointManager .add(pos, " ${profile.name} Logout Spot" )
57- if (print) MessageSendHelper .sendChatMessage(" ${profile.name} logged out at ${pos.asString()} " )
58- true
59- } else {
60- false
69+ loggedPlayers.entries.removeIf { (profile, entityOtherPlayerMP) ->
70+ @Suppress(" SENSELESS_COMPARISON" )
71+ if (connection.getPlayerInfo(profile.id) == null ) {
72+ if (saveWaypoint) {
73+ WaypointManager .add(entityOtherPlayerMP.entityBoundingBox.center.toBlockPos(), " ${profile.name} Logout Spot" )
6174 }
75+ if (print) {
76+ MessageSendHelper .sendChatMessage(" $chatName ${TextFormatting .RED }${profile.name}${TextFormatting .RESET } logged out at (${entityOtherPlayerMP.entityBoundingBox.center.toBlockPos().asString()} )" )
77+ }
78+
79+ // prevent render glitches caused by interpolation
80+ entityOtherPlayerMP.prevPosX = entityOtherPlayerMP.posX
81+ entityOtherPlayerMP.prevPosY = entityOtherPlayerMP.posY
82+ entityOtherPlayerMP.prevPosZ = entityOtherPlayerMP.posZ
83+
84+ loggedOutPlayers[profile] = entityOtherPlayerMP
85+ true
86+ } else {
87+ false
6288 }
89+ }
90+ }
91+
92+ onDisable {
93+ if (clearEsp) loggedOutPlayers.clear()
94+ }
6395
64- loggedPlayers.keys.removeAll(toRemove.toSet())
96+ listener<RenderWorldEvent > {
97+ if (! esp) return @listener
98+
99+ renderer.aFilled = espFilledAlpha
100+ renderer.aOutline = espOutlineAlpha
101+
102+ if (renderTimer.tick(1 )) {
103+ renderer.clear()
104+ loggedOutPlayers.values.forEach {
105+ renderer.add(it, espColor)
106+ }
65107 }
108+ renderer.render(false )
66109 }
67110 }
68111}
0 commit comments