1 |
using System; |
2 |
using System.Collections.Generic; |
3 |
using System.Globalization; |
4 |
using System.Xml; |
5 |
using Oni.Metadata; |
6 |
|
7 |
namespace Oni.Xml |
8 |
{ |
9 |
internal class ObjcXmlExporter : RawXmlExporter |
10 |
{ |
11 |
private readonly Dictionary<ObjectMetadata.TypeTag, Action> typeWriters = new Dictionary<ObjectMetadata.TypeTag, Action>(); |
12 |
private int objectEndPosition; |
13 |
|
14 |
private ObjcXmlExporter(BinaryReader reader, XmlWriter xml) |
15 |
: base(reader, xml) |
16 |
{ |
17 |
InitTypeWriters(typeWriters); |
18 |
} |
19 |
|
20 |
public static void Export(BinaryReader reader, XmlWriter xml) |
21 |
{ |
22 |
var exporter = new ObjcXmlExporter(reader, xml); |
23 |
exporter.Export(); |
24 |
} |
25 |
|
26 |
private void Export() |
27 |
{ |
28 |
int size = Reader.ReadInt32(); |
29 |
int version = Reader.ReadInt32(); |
30 |
|
31 |
Xml.WriteStartElement("Objects"); |
32 |
|
33 |
while (true) |
34 |
{ |
35 |
int objectSize = Reader.ReadInt32(); |
36 |
|
37 |
if (objectSize == 0) |
38 |
break; |
39 |
|
40 |
int readerPosition = Reader.Position; |
41 |
objectEndPosition = readerPosition + objectSize; |
42 |
|
43 |
BeginStruct(Reader.Position); |
44 |
|
45 |
var objectType = (ObjectMetadata.TypeTag)Reader.ReadInt32(); |
46 |
int objectId = Reader.ReadInt32(); |
47 |
|
48 |
Xml.WriteStartElement(objectType.ToString()); |
49 |
Xml.WriteAttributeString("Id", XmlConvert.ToString(objectId)); |
50 |
|
51 |
Xml.WriteStartElement("Header"); |
52 |
ObjectMetadata.Header.Accept(this); |
53 |
Xml.WriteEndElement(); |
54 |
|
55 |
Xml.WriteStartElement("OSD"); |
56 |
typeWriters[objectType](); |
57 |
Xml.WriteEndElement(); |
58 |
|
59 |
Xml.WriteEndElement(); |
60 |
|
61 |
Reader.Position = objectEndPosition; |
62 |
} |
63 |
|
64 |
Xml.WriteEndElement(); |
65 |
} |
66 |
|
67 |
private void WriteCharacter() |
68 |
{ |
69 |
ObjectMetadata.Character.Accept(this); |
70 |
} |
71 |
|
72 |
private void WriteCombatProfile() |
73 |
{ |
74 |
ObjectMetadata.CombatProfile.Accept(this); |
75 |
} |
76 |
|
77 |
private void WriteConsole() |
78 |
{ |
79 |
ObjectMetadata.Console.Accept(this); |
80 |
WriteEventList(); |
81 |
} |
82 |
|
83 |
private void WriteDoor() |
84 |
{ |
85 |
ObjectMetadata.Door.Accept(this); |
86 |
WriteEventList(); |
87 |
} |
88 |
|
89 |
private void WriteFlag() |
90 |
{ |
91 |
ObjectMetadata.Flag.Accept(this); |
92 |
} |
93 |
|
94 |
private void WriteFurniture() |
95 |
{ |
96 |
ObjectMetadata.Furniture.Accept(this); |
97 |
} |
98 |
|
99 |
private void WriteMeleeProfile() |
100 |
{ |
101 |
ObjectMetadata.MeleeProfile.Accept(this); |
102 |
|
103 |
int attackCount = Reader.ReadInt32(); |
104 |
int evadeCount = Reader.ReadInt32(); |
105 |
int maneuverCount = Reader.ReadInt32(); |
106 |
int moveCount = Reader.ReadInt32(); |
107 |
|
108 |
int moveTablePosition = Reader.Position + (attackCount + evadeCount + maneuverCount) * 88; |
109 |
|
110 |
Xml.WriteStartElement("Attacks"); |
111 |
for (int i = 0; i < attackCount; i++) |
112 |
WriteMeleeTechnique(moveTablePosition); |
113 |
Xml.WriteEndElement(); |
114 |
|
115 |
Xml.WriteStartElement("Evades"); |
116 |
for (int i = 0; i < evadeCount; i++) |
117 |
WriteMeleeTechnique(moveTablePosition); |
118 |
Xml.WriteEndElement(); |
119 |
|
120 |
Xml.WriteStartElement("Maneuvers"); |
121 |
for (int i = 0; i < maneuverCount; i++) |
122 |
WriteMeleeTechnique(moveTablePosition); |
123 |
Xml.WriteEndElement(); |
124 |
} |
125 |
|
126 |
private void WriteMeleeTechnique(int moveTablePosition) |
127 |
{ |
128 |
Xml.WriteStartElement("Technique"); |
129 |
|
130 |
ObjectMetadata.MeleeTechnique.Accept(this); |
131 |
|
132 |
int moveCount = Reader.ReadInt32(); |
133 |
int moveStart = Reader.ReadInt32(); |
134 |
|
135 |
int oldPosition = Reader.Position; |
136 |
Reader.Position = moveTablePosition + moveStart * 16; |
137 |
|
138 |
Xml.WriteStartElement("Moves"); |
139 |
|
140 |
for (int j = 0; j < moveCount; j++) |
141 |
WriteMeleeMove(); |
142 |
|
143 |
Xml.WriteEndElement(); |
144 |
Xml.WriteEndElement(); |
145 |
|
146 |
Reader.Position = oldPosition; |
147 |
} |
148 |
|
149 |
private void WriteMeleeMove() |
150 |
{ |
151 |
int categoryType = Reader.ReadInt32(); |
152 |
float[] moveParams = Reader.ReadSingleArray(3); |
153 |
|
154 |
var category = (ObjectMetadata.MeleeMoveCategory)(categoryType >> 24); |
155 |
Xml.WriteStartElement(category.ToString()); |
156 |
|
157 |
switch (category) |
158 |
{ |
159 |
default: |
160 |
case ObjectMetadata.MeleeMoveCategory.Attack: |
161 |
Xml.WriteAttributeString("Type", ((ObjectMetadata.MeleeMoveAttackType)(categoryType & 0xffffff)).ToString()); |
162 |
break; |
163 |
|
164 |
case ObjectMetadata.MeleeMoveCategory.Evade: |
165 |
Xml.WriteAttributeString("Type", ((ObjectMetadata.MeleeMoveEvadeType)(categoryType & 0xffffff)).ToString()); |
166 |
break; |
167 |
|
168 |
case ObjectMetadata.MeleeMoveCategory.Throw: |
169 |
Xml.WriteAttributeString("Type", ((ObjectMetadata.MeleeMoveThrowType)(categoryType & 0xffffff)).ToString()); |
170 |
break; |
171 |
|
172 |
case ObjectMetadata.MeleeMoveCategory.Maneuver: |
173 |
ObjectMetadata.MeleeMoveTypeInfo typeInfo = ObjectMetadata.MeleeMoveManeuverTypeInfo[categoryType & 0xffffff]; |
174 |
Xml.WriteAttributeString("Type", typeInfo.Type.ToString()); |
175 |
|
176 |
for (int k = 0; k < typeInfo.ParamNames.Length; k++) |
177 |
Xml.WriteAttributeString(typeInfo.ParamNames[k], XmlConvert.ToString(moveParams[k])); |
178 |
|
179 |
break; |
180 |
|
181 |
case ObjectMetadata.MeleeMoveCategory.Position: |
182 |
ObjectMetadata.MeleeMovePositionType moveType = (ObjectMetadata.MeleeMovePositionType)(categoryType & 0xffffff); |
183 |
Xml.WriteAttributeString("Type", moveType.ToString()); |
184 |
|
185 |
if ((ObjectMetadata.MeleeMovePositionType.RunForward <= moveType && moveType <= ObjectMetadata.MeleeMovePositionType.RunBack) |
186 |
|| ObjectMetadata.MeleeMovePositionType.CloseForward <= moveType) |
187 |
{ |
188 |
Xml.WriteAttributeString("MinRunInDist", XmlConvert.ToString(moveParams[0])); |
189 |
Xml.WriteAttributeString("MaxRunInDist", XmlConvert.ToString(moveParams[1])); |
190 |
Xml.WriteAttributeString("ToleranceRange", XmlConvert.ToString(moveParams[2])); |
191 |
} |
192 |
|
193 |
break; |
194 |
} |
195 |
|
196 |
Xml.WriteEndElement(); |
197 |
} |
198 |
|
199 |
private void WriteNeutralBehavior() |
200 |
{ |
201 |
ObjectMetadata.NeutralBehavior.Accept(this); |
202 |
int lineCount = Reader.ReadInt16(); |
203 |
ObjectMetadata.NeutralBehaviorParams.Accept(this); |
204 |
|
205 |
Xml.WriteStartElement("DialogLines"); |
206 |
MetaType.Array(lineCount, ObjectMetadata.NeutralBehaviorDialogLine).Accept(this); |
207 |
Xml.WriteEndElement(); |
208 |
} |
209 |
|
210 |
private void WriteParticle() |
211 |
{ |
212 |
ObjectMetadata.Particle.Accept(this); |
213 |
} |
214 |
|
215 |
private void WritePatrolPath() |
216 |
{ |
217 |
ObjectMetadata.PatrolPath.Accept(this); |
218 |
int length = Reader.ReadInt32(); |
219 |
ObjectMetadata.PatrolPathInfo.Accept(this); |
220 |
|
221 |
int startPosition = Reader.Position; |
222 |
int loopStartPoint = -1; |
223 |
|
224 |
var pointType = (ObjectMetadata.PatrolPathPointType)Reader.ReadInt32(); |
225 |
|
226 |
for (int i = 0; i < length; i++) |
227 |
{ |
228 |
if (pointType == ObjectMetadata.PatrolPathPointType.Loop) |
229 |
loopStartPoint = 0; |
230 |
else if (pointType == ObjectMetadata.PatrolPathPointType.LoopFrom) |
231 |
loopStartPoint = Reader.ReadInt32(); |
232 |
else |
233 |
Reader.Position += ObjectMetadata.GetPatrolPathPointSize(pointType); |
234 |
|
235 |
pointType = (ObjectMetadata.PatrolPathPointType)Reader.ReadInt32(); |
236 |
} |
237 |
|
238 |
Reader.Position = startPosition; |
239 |
|
240 |
Xml.WriteStartElement("Points"); |
241 |
|
242 |
for (int i = 0; i < length; i++) |
243 |
{ |
244 |
if (loopStartPoint == i) |
245 |
Xml.WriteStartElement("Loop"); |
246 |
|
247 |
WritePatrolPathPoint(); |
248 |
} |
249 |
|
250 |
if (loopStartPoint != -1) |
251 |
Xml.WriteEndElement(); |
252 |
|
253 |
Xml.WriteEndElement(); |
254 |
} |
255 |
|
256 |
private void WritePatrolPathPoint() |
257 |
{ |
258 |
var pointType = (ObjectMetadata.PatrolPathPointType)Reader.ReadInt32(); |
259 |
|
260 |
switch (pointType) |
261 |
{ |
262 |
case ObjectMetadata.PatrolPathPointType.Loop: |
263 |
return; |
264 |
|
265 |
case ObjectMetadata.PatrolPathPointType.LoopFrom: |
266 |
Reader.Skip(4); |
267 |
return; |
268 |
} |
269 |
|
270 |
Xml.WriteStartElement(pointType.ToString()); |
271 |
|
272 |
switch (pointType) |
273 |
{ |
274 |
case ObjectMetadata.PatrolPathPointType.Stop: |
275 |
case ObjectMetadata.PatrolPathPointType.StopLooking: |
276 |
case ObjectMetadata.PatrolPathPointType.StopScanning: |
277 |
case ObjectMetadata.PatrolPathPointType.FreeFacing: |
278 |
break; |
279 |
|
280 |
case ObjectMetadata.PatrolPathPointType.IgnorePlayer: |
281 |
Xml.WriteAttributeString("Value", Reader.ReadBoolean() ? "Yes" : "No"); |
282 |
break; |
283 |
|
284 |
case ObjectMetadata.PatrolPathPointType.MoveToFlag: |
285 |
case ObjectMetadata.PatrolPathPointType.LookAtFlag: |
286 |
case ObjectMetadata.PatrolPathPointType.MoveAndFaceFlag: |
287 |
Xml.WriteAttributeString("FlagId", XmlConvert.ToString(Reader.ReadInt16())); |
288 |
break; |
289 |
|
290 |
case ObjectMetadata.PatrolPathPointType.ForkScript: |
291 |
case ObjectMetadata.PatrolPathPointType.CallScript: |
292 |
Xml.WriteAttributeString("ScriptId", XmlConvert.ToString(Reader.ReadInt16())); |
293 |
break; |
294 |
|
295 |
case ObjectMetadata.PatrolPathPointType.Pause: |
296 |
Xml.WriteAttributeString("Frames", XmlConvert.ToString(Reader.ReadInt32())); |
297 |
break; |
298 |
|
299 |
case ObjectMetadata.PatrolPathPointType.MovementMode: |
300 |
Xml.WriteAttributeString("Mode", ((ObjectMetadata.PatrolPathMovementMode)Reader.ReadInt32()).ToString()); |
301 |
break; |
302 |
|
303 |
case ObjectMetadata.PatrolPathPointType.LockFacing: |
304 |
Xml.WriteAttributeString("Facing", ((ObjectMetadata.PatrolPathFacing)Reader.ReadInt32()).ToString()); |
305 |
break; |
306 |
|
307 |
case ObjectMetadata.PatrolPathPointType.MoveThroughFlag: |
308 |
case ObjectMetadata.PatrolPathPointType.MoveNearFlag: |
309 |
Xml.WriteAttributeString("FlagId", XmlConvert.ToString(Reader.ReadInt16())); |
310 |
Xml.WriteAttributeString("Distance", XmlConvert.ToString(Reader.ReadSingle())); |
311 |
break; |
312 |
|
313 |
case ObjectMetadata.PatrolPathPointType.GlanceAtFlagFor: |
314 |
Xml.WriteAttributeString("FlagId", XmlConvert.ToString(Reader.ReadInt16())); |
315 |
Xml.WriteAttributeString("Frames", XmlConvert.ToString(Reader.ReadInt32())); |
316 |
break; |
317 |
|
318 |
case ObjectMetadata.PatrolPathPointType.Scan: |
319 |
Xml.WriteAttributeString("Frames", XmlConvert.ToString(Reader.ReadInt16())); |
320 |
Xml.WriteAttributeString("Rotation", XmlConvert.ToString(Reader.ReadSingle())); |
321 |
break; |
322 |
|
323 |
case ObjectMetadata.PatrolPathPointType.MoveToFlagLookAndWait: |
324 |
Xml.WriteAttributeString("Frames", XmlConvert.ToString(Reader.ReadInt16())); |
325 |
Xml.WriteAttributeString("FlagId", XmlConvert.ToString(Reader.ReadInt16())); |
326 |
Xml.WriteAttributeString("Rotation", XmlConvert.ToString(Reader.ReadSingle())); |
327 |
break; |
328 |
|
329 |
case ObjectMetadata.PatrolPathPointType.FaceToFlagAndFire: |
330 |
Xml.WriteAttributeString("FlagId", XmlConvert.ToString(Reader.ReadInt16())); |
331 |
Xml.WriteAttributeString("Frames", XmlConvert.ToString(Reader.ReadInt16())); |
332 |
Xml.WriteAttributeString("Spread", XmlConvert.ToString(Reader.ReadSingle())); |
333 |
break; |
334 |
|
335 |
case ObjectMetadata.PatrolPathPointType.LookAtPoint: |
336 |
case ObjectMetadata.PatrolPathPointType.MoveToPoint: |
337 |
Xml.WriteAttributeString("X", XmlConvert.ToString(Reader.ReadSingle())); |
338 |
Xml.WriteAttributeString("Y", XmlConvert.ToString(Reader.ReadSingle())); |
339 |
Xml.WriteAttributeString("Z", XmlConvert.ToString(Reader.ReadSingle())); |
340 |
break; |
341 |
|
342 |
case ObjectMetadata.PatrolPathPointType.MoveThroughPoint: |
343 |
Xml.WriteAttributeString("X", XmlConvert.ToString(Reader.ReadSingle())); |
344 |
Xml.WriteAttributeString("Y", XmlConvert.ToString(Reader.ReadSingle())); |
345 |
Xml.WriteAttributeString("Z", XmlConvert.ToString(Reader.ReadSingle())); |
346 |
Xml.WriteAttributeString("Distance", XmlConvert.ToString(Reader.ReadSingle())); |
347 |
break; |
348 |
|
349 |
default: |
350 |
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Unsupported path point type {0}", pointType)); |
351 |
} |
352 |
|
353 |
Xml.WriteEndElement(); |
354 |
} |
355 |
|
356 |
private void WritePowerUp() |
357 |
{ |
358 |
ObjectMetadata.PowerUp.Accept(this); |
359 |
} |
360 |
|
361 |
private void WriteSound() |
362 |
{ |
363 |
ObjectMetadata.Sound.Accept(this); |
364 |
|
365 |
var volumeType = (ObjectMetadata.SoundVolumeType)Reader.ReadInt32(); |
366 |
|
367 |
switch (volumeType) |
368 |
{ |
369 |
case ObjectMetadata.SoundVolumeType.Box: |
370 |
Xml.WriteStartElement("Box"); |
371 |
MetaType.BoundingBox.Accept(this); |
372 |
Xml.WriteEndElement(); |
373 |
break; |
374 |
|
375 |
case ObjectMetadata.SoundVolumeType.Sphere: |
376 |
Xml.WriteStartElement("Sphere"); |
377 |
ObjectMetadata.SoundSphere.Accept(this); |
378 |
Xml.WriteEndElement(); |
379 |
break; |
380 |
} |
381 |
|
382 |
ObjectMetadata.SoundParams.Accept(this); |
383 |
} |
384 |
|
385 |
private void WriteTriggerVolume() |
386 |
{ |
387 |
ObjectMetadata.TriggerVolume.Accept(this); |
388 |
} |
389 |
|
390 |
private void WriteTrigger() |
391 |
{ |
392 |
ObjectMetadata.Trigger.Accept(this); |
393 |
WriteEventList(); |
394 |
} |
395 |
|
396 |
private void WriteTurret() |
397 |
{ |
398 |
ObjectMetadata.Turret.Accept(this); |
399 |
} |
400 |
|
401 |
private void WriteWeapon() |
402 |
{ |
403 |
ObjectMetadata.Weapon.Accept(this); |
404 |
} |
405 |
|
406 |
private void WriteEventList() |
407 |
{ |
408 |
Xml.WriteStartElement("Events"); |
409 |
|
410 |
int count = Reader.ReadInt16(); |
411 |
|
412 |
for (int i = 0; i < count; i++) |
413 |
{ |
414 |
var eventType = (ObjectMetadata.EventType)Reader.ReadInt16(); |
415 |
|
416 |
Xml.WriteStartElement(eventType.ToString()); |
417 |
|
418 |
switch (eventType) |
419 |
{ |
420 |
case ObjectMetadata.EventType.None: |
421 |
break; |
422 |
case ObjectMetadata.EventType.Script: |
423 |
Xml.WriteAttributeString("Function", Reader.ReadString(32)); |
424 |
break; |
425 |
default: |
426 |
Xml.WriteAttributeString("TargetId", XmlConvert.ToString(Reader.ReadInt16())); |
427 |
break; |
428 |
} |
429 |
|
430 |
Xml.WriteEndElement(); |
431 |
} |
432 |
|
433 |
Xml.WriteEndElement(); |
434 |
} |
435 |
|
436 |
private void InitTypeWriters(Dictionary<ObjectMetadata.TypeTag, Action> typeWriters) |
437 |
{ |
438 |
typeWriters.Add(ObjectMetadata.TypeTag.CHAR, WriteCharacter); |
439 |
typeWriters.Add(ObjectMetadata.TypeTag.CMBT, WriteCombatProfile); |
440 |
typeWriters.Add(ObjectMetadata.TypeTag.CONS, WriteConsole); |
441 |
typeWriters.Add(ObjectMetadata.TypeTag.DOOR, WriteDoor); |
442 |
typeWriters.Add(ObjectMetadata.TypeTag.FLAG, WriteFlag); |
443 |
typeWriters.Add(ObjectMetadata.TypeTag.FURN, WriteFurniture); |
444 |
typeWriters.Add(ObjectMetadata.TypeTag.MELE, WriteMeleeProfile); |
445 |
typeWriters.Add(ObjectMetadata.TypeTag.NEUT, WriteNeutralBehavior); |
446 |
typeWriters.Add(ObjectMetadata.TypeTag.PART, WriteParticle); |
447 |
typeWriters.Add(ObjectMetadata.TypeTag.PATR, WritePatrolPath); |
448 |
typeWriters.Add(ObjectMetadata.TypeTag.PWRU, WritePowerUp); |
449 |
typeWriters.Add(ObjectMetadata.TypeTag.SNDG, WriteSound); |
450 |
typeWriters.Add(ObjectMetadata.TypeTag.TRGV, WriteTriggerVolume); |
451 |
typeWriters.Add(ObjectMetadata.TypeTag.TRIG, WriteTrigger); |
452 |
typeWriters.Add(ObjectMetadata.TypeTag.TURR, WriteTurret); |
453 |
typeWriters.Add(ObjectMetadata.TypeTag.WEAP, WriteWeapon); |
454 |
} |
455 |
} |
456 |
} |