from binary import * class MetaMessage(MetaBinary): def __new__(cls, name, bases, ns): r = super(MetaMessage, cls).__new__(cls, name, bases, ns) if 'code' in ns: Message.classes[ns['code']] = r return r class Message(Binary): __metaclass__ = MetaMessage classes = {} layout = [('opcode', BYTE())] @classmethod def read_from_data(cls, data, i): c = ord(data[i]) if c >= 0x80: inst = UpdateEntity() else: inst = cls.classes[c]() i = inst.load_from_data(data, i) return inst, i class Bad(Message): code = 0x00 class Nop(Message): code = 0x01 class Disconnect(Message): code = 0x02 class UpdateStat(Message): code = 0x03 layout = [('index', BYTE()), ('value', LONG())] class Version(Message): code = 0x04 layout = [('serverprotocol', LONG())] class SetView(Message): code = 0x05 layout = [('entity', SHORT())] class Sound(Message): code = 0x06 layout = [('mask', BYTE()), ('vol', CDI(1, SDI(BYTE(), 1/255.0), 1.0)), ('attenuation', CDI(2, SDI(BYTE(), 1/64.0), 1.0)), ('entitychan', SHORT()), ('soundnum', BYTE()), ('origin', COORD()*3)] class Time(Message): code = 0x07 layout = [('time', FLOAT())] class Print(Message): code = 0x08 layout = [('text', STRING())] class Stufftext(Message): code = 0x09 layout = [('text', STRING())] class SetAngle(Message): code = 0x0A layout = [('angles', ANGLE()*3)] class ServerInfo(Message): code = 0x0B layout = [('serverversion', LONG()), ('maxclients', BYTE()), ('multi', BYTE()), ('mapname', STRING()), ('models', STRINGLIST()), ('sounds', STRINGLIST())] class LightStyle(Message): code = 0x0C layout = [('style', BYTE()), ('string', STRING())] class UpdateName(Message): code = 0x0D layout = [('player', BYTE()), ('netname', STRING())] class UpdateFrags(Message): code = 0x0E layout = [('player', BYTE()), ('frags', SHORT())] class ClientData(Message): code = 0x0F layout = [('mask', SHORT()), ('view_ofs_z', CDI(0x0001, BYTE(), 22)), ('punch_angle_x', CDI(0x0002, BYTE(), 0)), ('angles', CDI(0x0004, BYTE(), 0)*1), ('vel', CDI(0x0008, BYTE(), 0)*1), ('angles', Extend(CDI(0x0010, BYTE(), 0)*1)), ('vel', Extend(CDI(0x0020, BYTE(), 0)*1)), ('angles', Extend(CDI(0x0040, BYTE(), 0)*1)), ('vel', Extend(CDI(0x0080, BYTE(), 0)*1)), ('items', LONG()), ('weaponframe', CDI(0x1000, BYTE(), 0)), ('armorvalue', CDI(0x2000, BYTE(), 0)), ('weaponmodel', CDI(0x4000, BYTE(), 0)), ('health', SHORT()), ('currentammo', BYTE()), ('ammo_shells', BYTE()), ('ammo_nails', BYTE()), ('ammo_rockets', BYTE()), ('ammo_cells', BYTE()), ('weapon', BYTE())] class StopSound(Message): code = 0x10 layout = [('entitychan', SHORT())] class UpdateColors(Message): code = 0x11 layout = [('player', BYTE()), ('colors', BYTE())] class Particle(Message): code = 0x12 layout = [('origin', COORD()*3), ('vel', SDI(BYTE(), 0.0625)*3), ('color', BYTE()), ('count', BYTE())] class Damage(Message): code = 0x13 layout = [('save', BYTE()), ('take', BYTE()), ('origin', COORD()*3)] class SpawnStatic(Message): code = 0x14 layout = [('default_modelindex', BYTE()), ('default_frame', BYTE()), ('default_colormap', BYTE()), ('default_skin', BYTE()), ('default_origin', COORD()*1), ('default_angles', ANGLE()*1), ('default_origin', Extend(COORD()*1)), ('default_angles', Extend(ANGLE()*1)), ('default_origin', Extend(COORD()*1)), ('default_angles', Extend(ANGLE()*1))] # 0x15 is obsolete class SpawnBaseline(Message): code = 0x16 layout = [('entity', SHORT()), ('default_modelindex', BYTE()), ('default_frame', BYTE()), ('default_colormap', BYTE()), ('default_skin', BYTE()), ('default_origin', COORD()*1), ('default_angles', ANGLE()*1), ('default_origin', Extend(COORD()*1)), ('default_angles', Extend(ANGLE()*1)), ('default_origin', Extend(COORD()*1)), ('default_angles', Extend(ANGLE()*1))] def serialize(self): args = (self.opcode, self.entity, self.default_modelindex, self.default_frame, self.default_colormap, self.default_skin, 8*self.default_origin[0], 256*self.default_angles[0]/360, 8*self.default_origin[1], 256*self.default_angles[1]/360, 8*self.default_origin[2], 256*self.default_angles[2]/360) return struct.pack( '