#! /usr/bin/env python import os, re, sys, glob bike_state_size = 39 magic_number = "MX05" class arginfo: def __init__(self): self.sync = False self.filenames = [] self.start = 0 self.end = 2000000000 if sys.platform == "win32": self.glob = True else: self.glob = False args = arginfo() class mxheader: def __init__(self): self.fp = None self.nbikes = 0 self.nbikesout = 0 self.finishtime = 0 self.finishlaps = 0 self.gatetime = 0 self.track = "" self.bikes = [] self.lastread = "" def readheader(filename): h = mxheader() m = re.search(r"((,[0-9]+)+)$", filename) filter = [] if m: filename = filename[:m.start()] sfilter = m.group(0).split(",") for f in sfilter: if f: filter.append(int(f)) errstr = "%s is not a valid MX Simulator recording" % filename h.fp = file(filename, "rb") s = h.fp.readline() s = s.split() foundheader = None if len(s) >= 2 and s[0] == magic_number: h.nbikes = int(s[1]) if h.nbikes > 0: foundheader = 1 if len(s) >= 3: h.finishtime = int(s[2]) if len(s) >= 4: h.finishlaps = int(s[3]) if len(s) >= 5: h.gatetime = int(s[4]) if not foundheader: raise errstr + magic_number h.track = h.fp.readline() if not filter: filter = range(h.nbikes) for i in xrange(h.nbikes): btype = h.fp.readline() bnum = h.fp.readline() bfilter = (i in filter) h.bikes.append((btype, bnum, bfilter)) if bfilter: h.nbikesout += 1 return h def syncgatetime(h, t): while t < h.gatetime: h.fp.read(bike_state_size * h.nbikes) t = t + 1 def writebody(fp, headers): more = True tm = 0.0 while more: more = False for h in headers: s = h.fp.read(bike_state_size * h.nbikes) if s: more = True else: s = h.lastread if tm < args.start or tm > args.end: continue if s: for i in xrange(h.nbikes): if h.bikes[i][2]: fp.write(s[bike_state_size * i:bike_state_size * (i + 1)]) h.lastread = s else: return tm = tm + 1.0 / 128.0 def splicedemos(inputs, output): headers = [] for fn in inputs: headers.append(readheader(fn)) fp = file(output, "wb") nbikes = 0 finishtime = 0 finishlaps = 0 gatetime = 1000000 for h in headers: nbikes = nbikes + h.nbikesout if finishtime < h.finishtime: finishtime = h.finishtime if finishlaps < h.finishlaps: finishlaps = h.finishlaps if h.gatetime > 0 and gatetime > h.gatetime: gatetime = h.gatetime if gatetime == 1000000: gatetime = 0 fp.write("%s %d %d %d %d\n" % (magic_number, nbikes, finishtime, finishlaps, gatetime)) fp.write(headers[0].track); for h in headers: for b in h.bikes: if b[2]: fp.write(b[0]) fp.write(b[1]) if args.sync and gatetime > 0: for h in headers: syncgatetime(h, gatetime) writebody(fp, headers) fp.close() for h in headers: h.fp.close() def parsetime(s): s = s.split(":") if len(s) == 2: return float(s[0]) * 60.0 + float(s[1]) return float(s[0]) def setcut(a): m = re.search(r"([0-9.:]+)-([0-9.:]+)", a) if not m: return False args.start = parsetime(m.group(1)) args.end = parsetime(m.group(2)) return args.start and args.end def parseargs(a): global bike_state_size, magic_number usage = "usage: mxdemosplice.py" + \ " [--sync] [--cut -] " if len(a) == 0: return usage while len(a) > 0: s = a.pop(0) if s == "--help": return usage elif s == "--sync": args.sync = True elif s == "--cut": if not setcut(a.pop(0)): return "--cut requires a time range (e.g. 1:20.0-1:45.0)" elif s == "--v4": bike_state_size = 26 magic_number = "MX04" elif s == "--glob": args.glob = True elif s == "--noglob": args.glob = False elif s[0] == "-": return "invalid option '" + s + "'" elif args.glob: g = glob.glob(s) if g: args.filenames.extend(g) else: args.filenames.append(s) else: args.filenames.append(s) if len(args.filenames) < 2: return "You must give at least an input and output file" return errormsg = parseargs(sys.argv[1:]) if errormsg: sys.stderr.write(errormsg + "\n") sys.exit(1) splicedemos(args.filenames[0:-1], args.filenames[-1])