lgbot: auto recording while two humans fight (lgbot_record 2 / QL_RECORD), analyzer pairs any opponents
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3535940331
commit
acf625d72b
8 files changed
+133
-51
No files matched your search
@@ -43,9 +43,12 @@ SWITCH_MARGIN = 150
|
||||
BOT_STEAM_ID = 90071996842377216 # minqlx gives bots this + their client number
|
||||
# lgbot_record 1: every frame, the position/velocity of the bot and each human (as h<client number>,
|
||||
# no names or Steam IDs) go to home/lgbot-rec.csv, for tools/lgbot_rec.py to compare how they move.
|
||||
# Stops by itself after REC_MAX_S.
|
||||
# Stops by itself after REC_MAX_S. lgbot_record 2 (auto): only frames where two humans are fighting
|
||||
# (alive, within REC_FIGHT_DIST on about the same floor), no time limit. Both stop at REC_MAX_BYTES.
|
||||
REC_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "lgbot-rec.csv")
|
||||
REC_MAX_S = 900
|
||||
REC_MAX_BYTES = 200 * 1024 * 1024
|
||||
REC_FIGHT_DIST, REC_FIGHT_DZ = 1000, 250
|
||||
|
||||
|
||||
def is_bot(steam_id):
|
||||
@@ -160,6 +163,15 @@ def approach(cur, want, max_delta):
|
||||
return (cur[0] + dx / d * max_delta, cur[1] + dy / d * max_delta)
|
||||
|
||||
|
||||
def humans_fighting(positions):
|
||||
"""True when two of these (x, y, z) are within duel range of each other on about the same floor."""
|
||||
for i, a in enumerate(positions):
|
||||
for b in positions[i + 1:]:
|
||||
if math.hypot(a[0] - b[0], a[1] - b[1]) <= REC_FIGHT_DIST and abs(a[2] - b[2]) <= REC_FIGHT_DZ:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def pick_target(bot_pos, candidates, current=None):
|
||||
"""Key of the player to fight, from candidates [((x, y, z), key)]. A new target must be within
|
||||
MAX_TARGET_DIST / MAX_TARGET_DZ; the current one is kept up to the STOP limits unless another
|
||||
@@ -237,7 +249,7 @@ if minqlx:
|
||||
self.target_id, self.last_tick = None, None
|
||||
self.dbg_cmd, self.slow_frames, self.stuck = None, 0, 0 # debug stats
|
||||
self.state, self.frame_players = "", [] # for the recorder
|
||||
self.record_on, self.rec, self.rec_start = False, None, 0.0
|
||||
self.record_mode, self.rec, self.rec_start, self.rec_bytes = 0, None, 0.0, 0
|
||||
self.add_hook("frame", self.handle_frame)
|
||||
|
||||
def handle_frame(self):
|
||||
@@ -255,7 +267,7 @@ if minqlx:
|
||||
self.settings = resolve(to_int(self.get_cvar("lgbot_move")), over)
|
||||
self.debug = bool(to_int(self.get_cvar("lgbot_debug")))
|
||||
self.target_bots = bool(to_int(self.get_cvar("lgbot_target_bots")))
|
||||
self.record_on = bool(to_int(self.get_cvar("lgbot_record")))
|
||||
self.record_mode = to_int(self.get_cvar("lgbot_record")) or 0
|
||||
self.read_at = now
|
||||
return self.settings
|
||||
|
||||
@@ -320,23 +332,16 @@ if minqlx:
|
||||
if self.debug:
|
||||
self.debug_line(now, vel, (vx, vy), tpos, bpos, want, direction)
|
||||
|
||||
def record(self, now):
|
||||
if not self.record_on:
|
||||
if self.rec:
|
||||
self.rec.close()
|
||||
self.rec = None
|
||||
return
|
||||
if self.rec is None:
|
||||
self.rec = open(REC_FILE, "a", buffering=1)
|
||||
self.rec_start = now
|
||||
self.rec.write("# start %d map %s\n" % (int(now), self.get_cvar("mapname")))
|
||||
if now - self.rec_start > REC_MAX_S:
|
||||
self.set_cvar("lgbot_record", "0")
|
||||
self.record_on = False
|
||||
def stop_recording(self):
|
||||
if self.rec:
|
||||
self.rec.close()
|
||||
self.rec = None
|
||||
return
|
||||
t = now - self.rec_start
|
||||
|
||||
def record(self, now):
|
||||
mode = self.record_mode
|
||||
if mode not in (1, 2):
|
||||
return self.stop_recording()
|
||||
rows, humans = [], []
|
||||
for p in self.frame_players:
|
||||
if p.team == "spectator":
|
||||
continue
|
||||
@@ -347,8 +352,25 @@ if minqlx:
|
||||
else:
|
||||
who, state = "h%d" % p.id, ""
|
||||
pos, vel = p.position(), p.velocity()
|
||||
self.rec.write("%.3f,%s,%d,%d,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%s\n" % (
|
||||
t, who, int(bool(p.is_alive)), p.health, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z, state))
|
||||
if who != "bot" and p.is_alive:
|
||||
humans.append((pos.x, pos.y, pos.z))
|
||||
rows.append((who, int(bool(p.is_alive)), p.health, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z, state))
|
||||
if mode == 2 and not humans_fighting(humans):
|
||||
return
|
||||
if self.rec is None:
|
||||
self.rec = open(REC_FILE, "a", buffering=1)
|
||||
self.rec_bytes = os.path.getsize(REC_FILE)
|
||||
self.rec_start = now
|
||||
self.rec.write("# start %d map %s\n" % (int(now), self.get_cvar("mapname")))
|
||||
if (mode == 1 and now - self.rec_start > REC_MAX_S) or self.rec_bytes > REC_MAX_BYTES:
|
||||
self.set_cvar("lgbot_record", "0")
|
||||
self.record_mode = 0
|
||||
return self.stop_recording()
|
||||
t = now - self.rec_start
|
||||
for r in rows:
|
||||
line = "%.3f,%s,%d,%d,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f,%s\n" % ((t,) + r)
|
||||
self.rec.write(line)
|
||||
self.rec_bytes += len(line)
|
||||
|
||||
def debug_line(self, now, vel, cmd, tpos, bpos, want, direction):
|
||||
# cos = how well last frame's command survived the frame (1 = exactly our direction);
|
||||
|
||||
Reference in new issue
Block a user