On behalf of Stephen Thorne of 2007, Stephen Thorne of 2012 would like to apologise for using metaclasses. On Sep 26, 2012 9:47 PM, "James Cameron" <quozl at us.netrek.org> wrote: > G'day Bob, > > This awesome bit of code is from Stephen Thorne, possibly around 26th > June 2007, during an IRC collaboration while we were organising a > holiday technology camp. > > I've gathered it into my mind again just now, so that I can better > explain it. > > The main requirement was a list of packet types and sizes, for > processing the data stream from the server. I had built something > that was a bit ugly, using my limited knowledge of Python. Stephen > optimised it by using metaclasses. I still have the IRC log from > #netrek. > > sp_table is a dictionary of server packet types, indexed by the packet > type, each entry holding a packet size in bytes and a packet handler > object. > > sp_table is populated by the __new__ method of the ServerPacket class, > which is called for each of the SP_* classes as they are defined. The > method calculates the size of the packet using the struct format > string. This saves having to track the packet format or size in more > than one place. > > A lowercase global name is also added. This ensures an instance of > each object is preserved during execution, as well as making the > object available for direct access. Direct access is common for cp_* > objects, but not for sp_* objects. Examples of cp_* access are every > keyboard handler. Examples of sp_* access are the references to > sp_badversion.why and sp_warning.synthetic(). > > When the Client object is created in nt_init(), a pointer to the only > instance of the SP class is given to it, and it is preserved in the > Client object and used whenever a packet is received. In particular, > the find method of the SP class is called. > > So when a packet is received (in tcp_readable); > > - the first byte is examined, > > - the sp_table is referenced, to obtain the packet size, > (self.sp.find()), > > - enough bytes to fill the packet are dequeued from the network > socket, "if we have not got the complete packet, read some more", > > - the packet is passed to a packet type handler, (instance.handler()). > > The only thing I don't quite understand is how sp_table is used > without triggering an error "UnboundLocalError: local variable > 'sp_table' referenced before assignment", but it works. > > sp_table looks like this (print repr(sp_table)): > > {1: (84, <gytha.SP_MESSAGE object at 0xa394b0c>), > 2: (4, <gytha.SP_PLAYER_INFO object at 0xa39436c>), > 3: (8, <gytha.SP_KILLS object at 0xa3943ac>), > 4: (12, <gytha.SP_PLAYER object at 0xa3944ac>), > 5: (8, <gytha.SP_TORP_INFO object at 0xa3947ec>), > 6: (12, <gytha.SP_TORP object at 0xa39484c>), > 7: (16, <gytha.SP_PHASER object at 0xa394a0c>), > 8: (8, <gytha.SP_PLASMA_INFO object at 0xa3948cc>), > 9: (12, <gytha.SP_PLASMA object at 0xa39490c>), > 10: (84, <gytha.SP_WARNING object at 0xa394c0c>), > 11: (84, <gytha.SP_MOTD object at 0xa3940cc>), > 12: (32, <gytha.SP_YOU object at 0xa39416c>), > 13: (4, <gytha.SP_QUEUE object at 0xa3941ec>), > 14: (28, <gytha.SP_STATUS object at 0xa39498c>), > 15: (12, <gytha.SP_PLANET object at 0xa394a8c>), > 16: (4, <gytha.SP_PICKOK object at 0xa39470c>), > 17: (104, <gytha.SP_LOGIN object at 0xa39460c>), > 18: (8, <gytha.SP_FLAGS object at 0xa39452c>), > 19: (4, <gytha.SP_MASK object at 0xa39468c>), > 20: (4, <gytha.SP_PSTATUS object at 0xa39442c>), > 21: (4, <gytha.SP_BADVERSION object at 0xa394cec>), > 22: (4, <gytha.SP_HOSTILE object at 0xa3942ec>), > 23: (56, <gytha.SP_STATS object at 0xa394b8c>), > 24: (52, <gytha.SP_PL_LOGIN object at 0xa39426c>), > 25: (20, <gytha.SP_RESERVED object at 0xa39476c>), > 26: (28, <gytha.SP_PLANET_LOC object at 0xa3945ac>), > 28: (8, <gytha.SP_UDP_REPLY object at 0xa394dac>), > 29: (4, <gytha.SP_SEQUENCE object at 0xa394e0c>), > 32: (32, <gytha.SP_GENERIC_32 object at 0xa394f0c>), > 39: (60, <gytha.SP_SHIP_CAP object at 0xa394e8c>), > 46: (8, <gytha.SP_PING object at 0xa394d2c>), > 60: (88, <gytha.SP_FEATURE object at 0xa394c6c>), > -1: (0, <gytha.SP object at 0xa39406c>)} > > -- > James Cameron > http://quozl.linux.org.au/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mailman.us.netrek.org/pipermail/netrek-dev/attachments/20120926/4383cb77/attachment.html>