2 # -*- coding: utf-8 -*-
4 GalTacK networking - code common to all the GalTacK networking.
6 Currently this consists of data structures.
8 # Copyright (C) 2007 Felix Rabe <public@felixrabe.textdriven.com>
9 # Copyright (C) 2007 Michael Carter
11 # Permission is hereby granted, free of charge, to any person obtaining a
12 # copy of this software and associated documentation files (the
13 # "Software"), to deal in the Software without restriction, including
14 # without limitation the rights to use, copy, modify, merge, publish,
15 # distribute, sublicense, and/or sell copies of the Software, and to permit
16 # persons to whom the Software is furnished to do so, subject to the
17 # following conditions:
19 # The above copyright notice and this permission notice shall be included
20 # in all copies or substantial portions of the Software.
22 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
27 # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
28 # THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 # Recommended line length or text width: 75 characters.
35 class TableRowData(object):
37 Base class for rows of tables.
39 Actually, it is very easy to use. Take the *Info classes further down
40 this file as a starting point.
43 # COL_SPEC example to document the structure - override in derived
45 # (You can use TableRowData.build_col_spec_from_string() to build
46 # COL_SPEC and COL_SPEC_DICT automatically.)
53 "default": "No Name (default, optional)",
56 "name": "user_password",
58 "caption": "Password",
60 "default": "", # unset
65 "caption": "Logged In?",
72 # COL_SPEC_DICT example to document the structure - override in derived
74 # (You can use TableRowData.build_col_spec_dict() to build
75 # COL_SPEC_DICT automatically.)
77 "user_name": COL_SPEC
[0],
78 "user_password": COL_SPEC
[1],
79 "logged_in": COL_SPEC
[2],
83 def __init__(self
, *args
, **kwargs
):
85 Initialize in a user-friendly way.
88 TableRowData("Peter").user_name == "Peter"
89 TableRowData(user_name = "Peter")["user_name"] == "Peter"
92 for i
, arg
in enumerate(args
):
93 spec
= self
.COL_SPEC
[i
]
94 self
.__data
[spec
["name"]] = spec
["type"](arg
)
95 for spec
in self
.COL_SPEC
:
99 self
.__data
[n
] = t(kwargs
.pop(n
))
100 elif n
not in self
.__data
:
101 self
.__data
[n
] = t(spec
["default"])
102 super(TableRowData
, self
).__init
__(self
, **kwargs
)
106 Implement copy.copy(TableRowData_instance) properly.
108 row_data
= self
.__class
__()
109 for key
, value
in self
.__data
.iteritems():
110 row_data
[key
] = copy
.copy(value
)
114 def build_col_spec_from_string(string
):
116 Build COL_SPEC and COL_SPEC_DICT by parsing a string.
118 Return: (COL_SPEC, COL_SPEC_DICT)
121 TableRowData.build_col_spec_from_string(
123 user_name; str; User; No Name (default, optional)
124 user_password; str; (Password)
125 logged_in; bool; (Logged In?); False
127 ) == (TableRowData.COL_SPEC, TableRowData.COL_SPEC_DICT)
129 lines
= string
.strip().split("\n")
130 lines
= map(lambda line
:
131 map( lambda i
: i
.strip(), line
.split(";") ),
138 type = __builtins__
[line
[1]]
143 if caption
[0] == "(" and caption
[-1] == ")":
144 caption
= caption
[1:-1]
152 default
= type(eval(line
[-1]))
160 col_spec
.append(spec_dict
)
161 return (col_spec
, TableRowData
.build_col_spec_dict(col_spec
))
164 def build_col_spec_dict(col_spec
):
166 Build COL_SPEC_DICT from COL_SPEC.
168 Return: COL_SPEC_DICT
171 TableRowData.build_col_spec_dict(
172 TableRowData.COL_SPEC
173 ) == TableRowData.COL_SPEC_DICT
176 for spec
in col_spec
:
177 col_spec_dict
[spec
["name"]] = spec
180 def get_data_tuple(self
):
182 Get a tuple containing all the data.
185 for spec
in self
.COL_SPEC
:
186 tup
.append(self
.__data
[spec
["name"]])
189 def get_visible_data_tuple(self
):
191 Get a tuple containing all the visible data.
194 for i
, x
in enumerate(self
.get_tuple()):
195 if self
.COL_SPEC
[i
]["visible"] == True:
200 def get_col_types(cls
):
202 Get a tuple containing all the data types.
204 return tuple(s
["type"] for s
in cls
.COL_SPEC
)
207 def get_visible_col_types(cls
):
209 Get a tuple containing all the visible data types.
212 for i
, x
in enumerate(cls
.get_types()):
213 if cls
.COL_SPEC
[i
]["visible"] == True:
217 def __getitem__(self
, name
):
219 Make self["user_name"] and self[0] work.
226 spec
= self
.COL_SPEC
[i
]
227 return self
.__data
[spec
["name"]]
229 return self
.__data
[name
]
231 raise AttributeError, name
233 def __getattr__(self
, name
):
235 Make self.user_name work.
237 return self
.__getitem
__(name
)
239 def _get_field_spec(self
, name_or_index_or_spec
):
241 Return the COL_SPEC entry for the given name or index.
243 You can pass a COL_SPEC entry as well if you called
244 self._get_field_spec before.
246 if isinstance(name_or_index_or_spec
, dict):
247 return name_or_index_or_spec
# spec
250 i
= int(name_or_index_or_spec
)
253 return self
.COL_SPEC
[i
] # index
254 name
= name_or_index_or_spec
255 if name
not in self
.__data
:
256 raise AttributeError, "unknown field name '%s'" % name
257 return self
.COL_SPEC_DICT
[name
] # name
259 def __setitem__(self
, spec
, value
):
261 Implement self["password"] (or self[1]) = "my0dear1secret".
263 spec
= self
._get
_field
_spec
(spec
)
264 self
.__data
[spec
["name"]] = spec
["type"](value
)
266 def __setattr__(self
, name
, value
):
268 Make self.password = 'my0dear1secret' work.
270 if name
== "_TableRowData__data":
271 return super(TableRowData
, self
).__setattr
__(name
, value
)
272 return self
.__setitem
__(name
, value
)
274 def format(self
, use_caption
= True):
276 Format this row of data for human eyes.
279 n
= use_caption
and "caption" or "name"
280 maxlen
= max(len(s
[n
]) for s
in self
.COL_SPEC
)
281 for spec
in self
.COL_SPEC
:
282 lines
.append(("%%-%us%%r" % (maxlen
+ 2)) %
284 self
.__data
[spec
["name"]]))
286 return "\n".join(lines
)
289 class ServerInfo(TableRowData
):
291 Information about a GalTacK server.
294 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
295 bots_ok; bool; (Bots Ok)
298 version; str; Version
301 pwd_protected; bool; Protected
302 status; str; (Status)
303 addr; str; (IP Address)
304 port; int; (Port); 9031
305 secret; str; (Secret Hash)
306 passwd; str; (Password)
310 class UserInfo(TableRowData
):
312 Information about a GalTacK user.
315 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
318 passwd; str; Password
319 platform; str; Platform; linux2
320 version; str; Version; 1.2.0
324 class PlayerPlayersInfo(TableRowData
):
326 Information about a GalTacK player.
329 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
341 class PlayerStartInfo(TableRowData
):
343 In-game information about a GalTacK player.
346 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
354 class OptionB64Info(TableRowData
):
356 In-game, base64-encoded information about GalTacK "options".
359 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
369 class PlayerB64Info(TableRowData
):
371 In-game, base64-encoded information about a GalTacK player.
374 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
382 class PlanetB64Info(TableRowData
):
384 (In-game) information about a GalTacK planet.
387 COL_SPEC
, COL_SPEC_DICT
= TableRowData
.build_col_spec_from_string("""
389 x; int; X Position; 0
390 y; int; Y Position; 0
391 owner_num; int; Owner (Number); 0
392 prod; int; Production; 0
393 troops; int; Troops; 0
394 junk1; str; Junk 1; 0
395 junk2; str; Junk 2; 0
396 junk3; str; Junk 3; 0
397 junk4; str; Junk 4; 0
398 junk5; str; Junk 5; 0
399 junk6; str; Junk 6; 0
400 junk7; str; Junk 7; 0
401 junk8; str; Junk 8; 0
402 junk9; str; Junk 9; 0
403 radius; float; (Radius); 0.0
404 level_scale; float; (Level Scale); 1.0
405 dispx; int; (Displayed X Pos.); -1
406 dispy; int; (Displayed Y Pos.); -1
409 def __init__(self
, *a
, **kw
):
410 super(PlanetB64Info
, self
).__init
__(*a
, **kw
)
411 self
.prod
= self
.prod
# triggers __setitem__ (from __setattr__)
413 def __setitem__(self
, spec
, value
):
414 spec
= self
._get
_field
_spec
(spec
)
415 super(PlanetB64Info
, self
).__setitem
__(spec
, value
)
417 if name
== "prod" or name
== "level_scale":
418 self
.radius
= int( (12 + self
.prod
/ 10) * self
.level_scale
)