1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """ submodule for xml map parsing """
24
25 from fife import fife
26
27 from fife.extensions.serializers import ET
28 from fife.extensions.serializers import SerializerError, InvalidFormat
29 from fife.extensions.serializers import NameClash, NotFound, WrongFileType
30 from fife.extensions.serializers.xmlanimation import loadXMLAnimation
31
33 """ The B{XMLObjectSaver} serializes a fife.Object instance by saving
34 it back to it's XML file
35
36 @note:
37 - this code does NOT allow the creation of a new xml file
38 - this code does NOT touch atlas or animation definitions
39 - this code does NOT allow saving to non-well-formed xml files
40 - this code DOES save blocking & static flag, as well as
41 image offsets
42
43 @type engine: fife
44 @ivar engine: pointer to initialized fife engine instance
45 @type img_manager: fife.ImageManager
46 @ivar img_manager: pointer to fife image manager
47 @type compat: bool
48 @ivar compat: flag to either use outdated xml definitions or new approach
49 @type debug: bool
50 @ivar debug: flag to activate/deactivate debug output
51 @type vfs: fife.VFS
52 @ivar vfs: pointer to fife vfs
53 @type change: bool
54 @ivar change: flag if object data differs from file data
55 """
56 PROCESSING_INSTRUCTION = '<?fife type="object"?>'
57 - def __init__(self, engine, debug=False, compat=True):
58 """
59
60 @type engine: fife
61 @param engine: intialized fife engine
62 """
63 self.compat = compat
64 self.debug = debug
65 self.engine = engine
66 self.img_manager = engine.getImageManager()
67 self.vfs = self.engine.getVFS()
68 self.change = False
69
70 - def save(self, object):
71 """ saves the data of a fife.Object to it's xml file
72
73 @type object: fife.Object
74 @param object: the object which should be saved
75 @rtype result: bool
76 @return result: flag wether the saving was successful or not
77 """
78 self.change = False
79 result = False
80
81 file = object.getFilename()
82 if not file:
83 raise SerializerError("Object cannot be saved, no file found %s" % object)
84 return result
85
86 if not self.vfs.exists(file):
87 raise NotFound("File not within vfs: %s" % file)
88 return result
89
90 file_handle = self.vfs.open(file)
91 file_handle.thisown = 1
92 tree = ET.parse(file_handle)
93 root = tree.getroot()
94
95 object_id = object.getId()
96 blocking = object.isBlocking()
97 static = object.isStatic()
98
99
100
101
102 if hasattr(object, 'getCostId'):
103 cost_id = object.getCostId()
104 else:
105 cost_id = ''
106 if hasattr(object, 'getCost'):
107 cost = object.getCost()
108 else:
109 cost = 0.0
110 if hasattr(object, 'getCellStackPosition'):
111 cellstack_pos = object.getCellStackPosition()
112 else:
113 cellstack_pos = 0
114
115 if self.debug:
116 print "XML tree dump: (pre-save)"
117 ET.dump(root)
118 print "Object data: "
119 print "\tid", object_id
120 print "\tblocking", blocking
121 print "\tstatic", static
122 print "\tcost id", cost_id
123 print "\tcost", cost
124
125
126 if root.tag != 'assets':
127 self.compat = True
128
129
130 if self.compat:
131 objects = [root,]
132
133 else:
134 objects = root.findall("object")
135
136 for obj in objects:
137 _id = obj.get("id")
138 if _id != object_id:
139 if self.debug:
140 print "...ommitting object %s " % _id
141 continue
142
143 if 'blocking' not in obj.attrib or int(obj.attrib['blocking']) != int(blocking):
144 self.change = True
145 if 'static' not in obj.attrib or int(obj.attrib['static']) != int(static):
146 self.change = True
147 if 'cost_id' not in obj.attrib or str(obj.attrib['cost_id']) != str(cost_id):
148 self.change = True
149 if 'cost' not in obj.attrib or float(obj.attrib['cost']) != float(cost):
150 self.change = True
151 if 'cellstack_position' not in obj.attrib or int(obj.attrib['cellstack_position']) != int(cellstack_pos):
152 self.change = True
153
154 obj.attrib['blocking'] = str(int(blocking))
155 obj.attrib['static'] = str(int(static))
156 if cost_id and cost:
157 obj.attrib['cost_id'] = str(cost_id)
158 obj.attrib['cost'] = str(cost)
159 obj.attrib['cellstack_position'] = str(cellstack_pos)
160
161 if self.debug and self.change:
162 print "\tSet new data in xml tree: "
163 print "\t\tblocking: ", obj.attrib['blocking']
164 print "\t\tstatic: ", obj.attrib['static']
165
166 images = obj.findall("image")
167 actions = obj.findall("action")
168
169 if self.debug:
170 print "\tAttempting to save image data: "
171 print "\t...found these image elements: "
172 print "\t", images
173 print "object dump: "
174 print ET.dump(obj)
175
176 self.save_images(images, object)
177 self.save_actions(actions, object)
178
179 if not self.change:
180 return result
181
182 xmlcontent = ET.tostring(root)
183
184 if self.debug:
185 print "XML tree dump: (post-manipulation)"
186 ET.dump(root)
187
188
189 file = open(file, 'w')
190 file.write(XMLObjectSaver.PROCESSING_INSTRUCTION+'\n')
191 file.write(xmlcontent + "\n")
192 file.close()
193 result = True
194 return result
195
197 """ save action definitions
198
199 @type actions: list
200 @param actions: list of <action> elements
201 @type object: fife.Object
202 @param object: the object which should be saved
203 """
204 for element in actions:
205
206 if 'animation_id' not in element.attrib:
207 break
208
209 animation_id = element.attrib['animation_id']
210 self.save_animation(animation_id, object)
211
213 """ save animation definitions for the given id
214
215 @type animation_id: str
216 @param animation_id: id of the animation data structure
217 @type object: fife.Object
218 @param object: the object which should be saved
219 """
220 pass
221
223 """ save image definitions
224
225 @type images: list
226 @param images: list of <image> elements
227 @type object: fife.Object
228 @param object: the object which should be saved
229 """
230 visual = object.get2dGfxVisual()
231 angles = visual.getStaticImageAngles()
232 if self.debug:
233 print "\t\tobject angles: ", angles
234
235 for element in images:
236 angle = int(element.get("direction"))
237 if angle not in angles: continue
238
239 index = visual.getStaticImageIndexByAngle(angle)
240 image = self.img_manager.get(index)
241 x_offset = image.getXShift()
242 y_offset = image.getYShift()
243
244 if 'x_offset' not in element.attrib or int(element.attrib['x_offset']) != x_offset:
245 self.change = True
246 if 'y_offset' not in element.attrib or int(element.attrib['y_offset']) != y_offset:
247 self.change = True
248
249 element.attrib['x_offset'] = str(x_offset)
250 element.attrib['y_offset'] = str(y_offset)
251
252 if self.debug and self.change:
253 print "\tSet new data in xml tree: (<image>) "
254 print "\t\tx offset: ", element.attrib['x_offset']
255 print "\t\ty offset: ", element.attrib['y_offset']
256
258 """
259
260 """
262 """
263
264 """
265 self.engine = engine
266 self.imgMgr = engine.getImageManager()
267 self.anim_pool = None
268 self.model = engine.getModel()
269 self.vfs = engine.getVFS()
270 self.source = None
271 self.filename = ''
272
274 """
275
276 """
277 self.source = location
278 self.filename = self.source
279 self.node = None
280 self.file = None
281 if hasattr(location, 'node'):
282 self.node = location.node
283 else:
284 isobjectfile = True
285 f = self.vfs.open(self.filename)
286 f.thisown = 1
287
288 obj_identifier = '<?fife type="object"?>'
289 try:
290 s = f.readString(len(obj_identifier))
291 except fife.IndexOverflow:
292 isobjectfile = False
293
294 if isobjectfile and not s.startswith(obj_identifier):
295 isobjectfile = False
296
297 if not isobjectfile:
298 return
299
300
301
302 raise WrongFileType('Tried to open non-object file %s with XMLObjectLoader.' % self.filename)
303
304 self.do_load_resource(f)
305
307 """
308
309 """
310 if file:
311 tree = ET.parse(file)
312 self.node = tree.getroot()
313 self.parse_object(self.node)
314
316 """
317
318 """
319 if self.node.tag != 'object':
320 raise InvalidFormat('Expected <object> tag, but found <%s>.' % self.node.tag)
321
322 _id = object.get('id')
323 if not _id:
324 raise InvalidFormat('<object> declared without an id attribute.')
325 _id = str(_id)
326
327 nspace = object.get('namespace')
328 if not nspace:
329 raise InvalidFormat('<object> %s declared without a namespace attribute.' % str(_id))
330 nspace = str(nspace)
331
332 obj = None
333 parent = object.get('parent', None)
334 if parent:
335 query = self.metamodel.getObjects('id', str(parent))
336 if len(query) == 0:
337 raise NotFound('No objects found with identifier %s.' % str(parent))
338 elif len(query) > 1:
339 raise NameClash('%d objects found with identifier %s.' % (len(query), str(parent)))
340 parent = query[0]
341
342
343 if not bool(self.model.getObject(_id, nspace)):
344 obj = self.model.createObject(_id, nspace, parent)
345 else:
346 print NameClash('Tried to create already existing object \n\t...ignoring: %s, %s' % (_id, nspace))
347 return
348
349 obj.setFilename(self.source)
350 fife.ObjectVisual.create(obj)
351 obj.setBlocking(bool( int(object.get('blocking', False)) ))
352 obj.setStatic(bool( int(object.get('static', False)) ))
353
354 pather = object.get('pather', 'RoutePather')
355 obj.setPather( self.model.getPather(pather) )
356
357 self.parse_images(object, obj)
358 self.parse_actions(object, obj)
359
379
392
411