source: OniSplit/Xml/ObjcXmlImporter.cs@ 1183

Last change on this file since 1183 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 19.5 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Xml;
4using Oni.Metadata;
5
6namespace Oni.Xml
7{
8 internal class ObjcXmlImporter : RawXmlImporter
9 {
10 private readonly Dictionary<ObjectMetadata.TypeTag, Action> typeReaders = new Dictionary<ObjectMetadata.TypeTag, Action>();
11 private int nextId;
12
13 private ObjcXmlImporter(XmlReader xml, BinaryWriter writer)
14 : base(xml, writer)
15 {
16 InitTypeReaders(typeReaders);
17 }
18
19 public static void Import(XmlReader xml, BinaryWriter writer)
20 {
21 var importer = new ObjcXmlImporter(xml, writer);
22 importer.Import();
23 }
24
25 private void Import()
26 {
27 Writer.Write(39);
28
29 nextId = 1;
30
31 while (Xml.IsStartElement())
32 {
33 int objectStartPosition = Writer.Position;
34 Writer.Write(0);
35
36 BeginStruct(objectStartPosition);
37
38 ReadObject();
39
40 Writer.Position = Utils.Align4(Writer.Position);
41
42 int objectSize = Writer.Position - objectStartPosition - 4;
43 Writer.WriteAt(objectStartPosition, objectSize);
44 }
45
46 Writer.Write(0);
47 }
48
49 private ObjectMetadata.TypeTag ReadObject()
50 {
51 var id = Xml.GetAttribute("Id");
52 int objectId = string.IsNullOrEmpty(id) ? nextId++ : XmlConvert.ToInt32(id);
53 var objectTag = Xml.GetAttribute("Type");
54
55 if (objectTag == null)
56 objectTag = Xml.LocalName;
57
58 var objectType = MetaEnum.Parse<ObjectMetadata.TypeTag>(objectTag);
59
60 Xml.ReadStartElement();
61 Xml.MoveToContent();
62
63 Writer.Write((int)objectType);
64 Writer.Write(objectId);
65 ObjectMetadata.Header.Accept(this);
66 typeReaders[objectType]();
67
68 Xml.ReadEndElement();
69
70 return objectType;
71 }
72
73 private void ReadCharacter()
74 {
75 ObjectMetadata.Character.Accept(this);
76 }
77
78 private void ReadCombatProfile()
79 {
80 ObjectMetadata.CombatProfile.Accept(this);
81 }
82
83 private void ReadConsole()
84 {
85 Xml.ReadStartElement();
86 Xml.MoveToContent();
87
88 ReadStruct(ObjectMetadata.Console);
89 ReadEventList();
90
91 Xml.ReadEndElement();
92 }
93
94 private void ReadDoor()
95 {
96 Xml.ReadStartElement();
97 Xml.MoveToContent();
98
99 ReadStruct(ObjectMetadata.Door);
100 ReadEventList();
101
102 Xml.ReadEndElement();
103 }
104
105 private void ReadFlag()
106 {
107 ObjectMetadata.Flag.Accept(this);
108 }
109
110 private void ReadFurniture()
111 {
112 ObjectMetadata.Furniture.Accept(this);
113 }
114
115 private struct MeleeMove
116 {
117 public int Type;
118 public float[] Params;
119 }
120
121 private void ReadMeleeProfile()
122 {
123 Xml.ReadStartElement();
124 Xml.MoveToContent();
125
126 ReadStruct(ObjectMetadata.MeleeProfile);
127
128 int countFieldsPosition = Writer.Position;
129 Writer.Write(0);
130 Writer.Write(0);
131 Writer.Write(0);
132 Writer.Write(0);
133
134 int attackCount = 0;
135 int evadeCount = 0;
136 int maneuverCount = 0;
137 var moves = new List<MeleeMove>();
138
139 attackCount = ReadMeleeTechniques("Attacks", moves);
140 evadeCount = ReadMeleeTechniques("Evades", moves);
141 maneuverCount = ReadMeleeTechniques("Maneuvers", moves);
142
143 foreach (var move in moves)
144 {
145 Writer.Write(move.Type);
146 Writer.Write(move.Params);
147 }
148
149 int oldPosition = Writer.Position;
150 Writer.Position = countFieldsPosition;
151 Writer.Write(attackCount);
152 Writer.Write(evadeCount);
153 Writer.Write(maneuverCount);
154 Writer.Write(moves.Count);
155 Writer.Position = oldPosition;
156
157 Xml.ReadEndElement();
158 }
159
160 private int ReadMeleeTechniques(string xmlName, List<MeleeMove> moves)
161 {
162 if (Xml.IsStartElement(xmlName) && Xml.IsEmptyElement)
163 {
164 Xml.Skip();
165 return 0;
166 }
167
168 Xml.ReadStartElement(xmlName);
169 Xml.MoveToContent();
170
171 int techniqueCount = 0;
172
173 for (; Xml.IsStartElement("Technique"); techniqueCount++)
174 {
175 Xml.ReadStartElement();
176 Xml.MoveToContent();
177
178 ReadStruct(ObjectMetadata.MeleeTechnique);
179 int moveCountPosition = Writer.Position;
180 Writer.Write(0);
181 Writer.Write(moves.Count);
182
183 int moveCount = 0;
184
185 if (Xml.IsStartElement("Moves") && Xml.IsEmptyElement)
186 {
187 Xml.Skip();
188 }
189 else
190 {
191 Xml.ReadStartElement("Moves");
192 Xml.MoveToContent();
193
194 for (; Xml.IsStartElement(); moveCount++)
195 {
196 ReadMeleeMove(moves);
197 }
198
199 Xml.ReadEndElement();
200 }
201
202 Xml.ReadEndElement();
203
204 Writer.WriteAt(moveCountPosition, moveCount);
205 }
206
207 Xml.ReadEndElement();
208
209 return techniqueCount;
210 }
211
212 private void ReadMeleeMove(List<MeleeMove> moves)
213 {
214 var category = (ObjectMetadata.MeleeMoveCategory)Enum.Parse(typeof(ObjectMetadata.MeleeMoveCategory), Xml.LocalName);
215
216 var typeText = Xml.GetAttribute("Type");
217 int type;
218 var moveParams = new float[3];
219
220 switch (category)
221 {
222 default:
223 case ObjectMetadata.MeleeMoveCategory.Attack:
224 type = Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.MeleeMoveAttackType>(typeText));
225 break;
226 case ObjectMetadata.MeleeMoveCategory.Evade:
227 type = Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.MeleeMoveEvadeType>(typeText));
228 break;
229 case ObjectMetadata.MeleeMoveCategory.Throw:
230 type = Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.MeleeMoveThrowType>(typeText));
231 break;
232
233 case ObjectMetadata.MeleeMoveCategory.Position:
234 ObjectMetadata.MeleeMovePositionType positionType = MetaEnum.Parse<ObjectMetadata.MeleeMovePositionType>(typeText);
235
236 if ((ObjectMetadata.MeleeMovePositionType.RunForward <= positionType
237 && positionType <= ObjectMetadata.MeleeMovePositionType.RunBack)
238 || ObjectMetadata.MeleeMovePositionType.CloseForward <= positionType)
239 {
240 moveParams[0] = XmlConvert.ToSingle(Xml.GetAttribute("MinRunInDist"));
241 moveParams[1] = XmlConvert.ToSingle(Xml.GetAttribute("MaxRunInDist"));
242 moveParams[2] = XmlConvert.ToSingle(Xml.GetAttribute("ToleranceRange"));
243 }
244
245 type = Convert.ToInt32(positionType);
246 break;
247
248 case ObjectMetadata.MeleeMoveCategory.Maneuver:
249 type = Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.MeleeMoveManeuverType>(typeText));
250 ObjectMetadata.MeleeMoveTypeInfo typeInfo = ObjectMetadata.MeleeMoveManeuverTypeInfo[type];
251
252 for (int k = 0; k < typeInfo.ParamNames.Length; k++)
253 moveParams[k] = XmlConvert.ToSingle(Xml.GetAttribute(typeInfo.ParamNames[k]));
254
255 break;
256 }
257
258 moves.Add(new MeleeMove()
259 {
260 Type = (((int)category) << 24) | (type & 0xffffff),
261 Params = moveParams
262 });
263
264 Xml.Skip();
265 }
266
267 private void ReadNeutralBehavior()
268 {
269 Xml.ReadStartElement();
270 Xml.MoveToContent();
271
272 ReadStruct(ObjectMetadata.NeutralBehavior);
273 int countFieldPosition = Writer.Position;
274 Writer.WriteUInt16(0);
275 ReadStruct(ObjectMetadata.NeutralBehaviorParams);
276
277 Xml.ReadStartElement("DialogLines");
278 short count = 0;
279
280 for (; Xml.IsStartElement("DialogLine"); count++)
281 ObjectMetadata.NeutralBehaviorDialogLine.Accept(this);
282
283 Xml.ReadEndElement();
284 Xml.ReadEndElement();
285
286 Writer.WriteAt(countFieldPosition, count);
287 }
288
289 private void ReadParticle()
290 {
291 ObjectMetadata.Particle.Accept(this);
292 }
293
294 private void ReadPatrolPath()
295 {
296 Xml.ReadStartElement();
297 Xml.MoveToContent();
298
299 ReadStruct(ObjectMetadata.PatrolPath);
300 int lengthFieldPosition = Writer.Position;
301 Writer.Write(0);
302 ReadStruct(ObjectMetadata.PatrolPathInfo);
303
304 int count = 0;
305 bool isEmpty = Xml.IsEmptyElement;
306
307 Xml.ReadStartElement("Points");
308
309 if (!isEmpty)
310 {
311 int loopStart = -1;
312
313 for (; Xml.IsStartElement(); count++)
314 {
315 if (ReadPatrolPathPoint())
316 loopStart = count;
317 }
318
319 if (loopStart != -1)
320 {
321 if (loopStart == 0)
322 {
323 Writer.Write((int)ObjectMetadata.PatrolPathPointType.Loop);
324 }
325 else
326 {
327 Writer.Write((int)ObjectMetadata.PatrolPathPointType.LoopFrom);
328 Writer.Write(loopStart);
329 }
330
331 if (Xml.NodeType == XmlNodeType.EndElement && Xml.LocalName == "Loop")
332 Xml.ReadEndElement();
333 }
334
335 Xml.ReadEndElement();
336 }
337
338 Xml.ReadEndElement();
339
340 Writer.WriteAt(lengthFieldPosition, count);
341 }
342
343 private bool ReadPatrolPathPoint()
344 {
345 var pointType = MetaEnum.Parse<ObjectMetadata.PatrolPathPointType>(Xml.LocalName);
346
347 switch (pointType)
348 {
349 case ObjectMetadata.PatrolPathPointType.Loop:
350 if (Xml.IsEmptyElement)
351 {
352 Xml.Skip();
353 }
354 else
355 {
356 Xml.ReadStartElement();
357 Xml.MoveToContent();
358 }
359 return true;
360 }
361
362 Writer.Write((int)pointType);
363
364 switch (pointType)
365 {
366 case ObjectMetadata.PatrolPathPointType.Stop:
367 case ObjectMetadata.PatrolPathPointType.StopLooking:
368 case ObjectMetadata.PatrolPathPointType.StopScanning:
369 case ObjectMetadata.PatrolPathPointType.FreeFacing:
370 break;
371
372 case ObjectMetadata.PatrolPathPointType.IgnorePlayer:
373 Writer.WriteByte(Xml.GetAttribute("Value") == "Yes" ? 1 : 0);
374 break;
375
376 case ObjectMetadata.PatrolPathPointType.ForkScript:
377 case ObjectMetadata.PatrolPathPointType.CallScript:
378 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("ScriptId")));
379 break;
380
381 case ObjectMetadata.PatrolPathPointType.MoveToFlag:
382 case ObjectMetadata.PatrolPathPointType.LookAtFlag:
383 case ObjectMetadata.PatrolPathPointType.MoveAndFaceFlag:
384 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("FlagId")));
385 break;
386
387 case ObjectMetadata.PatrolPathPointType.MovementMode:
388 Writer.Write(Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.PatrolPathMovementMode>(Xml.GetAttribute("Mode"))));
389 break;
390
391 case ObjectMetadata.PatrolPathPointType.LockFacing:
392 Writer.Write(Convert.ToInt32(MetaEnum.Parse<ObjectMetadata.PatrolPathFacing>(Xml.GetAttribute("Facing"))));
393 break;
394
395 case ObjectMetadata.PatrolPathPointType.Pause:
396 Writer.Write(XmlConvert.ToInt32(Xml.GetAttribute("Frames")));
397 break;
398
399 case ObjectMetadata.PatrolPathPointType.GlanceAtFlagFor:
400 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("FlagId")));
401 Writer.Write(XmlConvert.ToInt32(Xml.GetAttribute("Frames")));
402 break;
403
404 case ObjectMetadata.PatrolPathPointType.Scan:
405 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("Frames")));
406 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Rotation")));
407 break;
408
409 case ObjectMetadata.PatrolPathPointType.MoveThroughFlag:
410 case ObjectMetadata.PatrolPathPointType.MoveNearFlag:
411 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("FlagId")));
412 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Distance")));
413 break;
414
415 case ObjectMetadata.PatrolPathPointType.MoveToFlagLookAndWait:
416 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("Frames")));
417 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("FlagId")));
418 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Rotation")));
419 break;
420
421 case ObjectMetadata.PatrolPathPointType.FaceToFlagAndFire:
422 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("FlagId")));
423 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("Frames")));
424 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Spread")));
425 break;
426
427 case ObjectMetadata.PatrolPathPointType.LookAtPoint:
428 case ObjectMetadata.PatrolPathPointType.MoveToPoint:
429 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("X")));
430 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Y")));
431 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Z")));
432 break;
433
434 case ObjectMetadata.PatrolPathPointType.MoveThroughPoint:
435 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("X")));
436 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Y")));
437 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Z")));
438 Writer.Write(XmlConvert.ToSingle(Xml.GetAttribute("Distance")));
439 break;
440
441 default:
442 throw new NotSupportedException(string.Format("Unsupported path point type {0}", pointType));
443 }
444
445 Xml.Skip();
446
447 return false;
448 }
449
450 private void ReadPowerUp()
451 {
452 ObjectMetadata.PowerUp.Accept(this);
453 }
454
455 private void ReadSound()
456 {
457 Xml.ReadStartElement();
458 Xml.MoveToContent();
459
460 ReadStruct(ObjectMetadata.Sound);
461
462 var volumeType = MetaEnum.Parse<ObjectMetadata.SoundVolumeType>(Xml.LocalName);
463
464 Writer.Write((int)volumeType);
465
466 switch (volumeType)
467 {
468 case ObjectMetadata.SoundVolumeType.Box:
469 MetaType.BoundingBox.Accept(this);
470 break;
471
472 case ObjectMetadata.SoundVolumeType.Sphere:
473 ObjectMetadata.SoundSphere.Accept(this);
474 break;
475 }
476
477 ReadStruct(ObjectMetadata.SoundParams);
478
479 if (volumeType == ObjectMetadata.SoundVolumeType.Sphere)
480 Writer.Skip(16);
481
482 Xml.ReadEndElement();
483 }
484
485 private void ReadTriggerVolume()
486 {
487 ObjectMetadata.TriggerVolume.Accept(this);
488 }
489
490 private void ReadTrigger()
491 {
492 Xml.ReadStartElement();
493 Xml.MoveToContent();
494
495 ReadStruct(ObjectMetadata.Trigger);
496 ReadEventList();
497
498 Xml.ReadEndElement();
499 }
500
501 private void ReadTurret()
502 {
503 ObjectMetadata.Turret.Accept(this);
504 }
505
506 private void ReadWeapon()
507 {
508 ObjectMetadata.Weapon.Accept(this);
509 }
510
511 private void ReadEventList()
512 {
513 int countFieldPosition = Writer.Position;
514 Writer.WriteUInt16(0);
515
516 if (Xml.IsStartElement("Events") && Xml.IsEmptyElement)
517 {
518 Xml.ReadStartElement();
519 return;
520 }
521
522 Xml.ReadStartElement("Events");
523 Xml.MoveToContent();
524
525 short eventCount = 0;
526
527 while (Xml.IsStartElement())
528 {
529 var eventType = MetaEnum.Parse<ObjectMetadata.EventType>(Xml.Name);
530
531 Writer.Write((short)eventType);
532
533 switch (eventType)
534 {
535 case ObjectMetadata.EventType.None:
536 break;
537 case ObjectMetadata.EventType.Script:
538 Writer.Write(Xml.GetAttribute("Function"), 32);
539 break;
540 default:
541 Writer.Write(XmlConvert.ToInt16(Xml.GetAttribute("TargetId")));
542 break;
543 }
544
545 eventCount++;
546 Xml.Skip();
547 }
548
549 Writer.WriteAt(countFieldPosition, eventCount);
550 Xml.ReadEndElement();
551 }
552
553 private void InitTypeReaders(Dictionary<ObjectMetadata.TypeTag, Action> typeReaders)
554 {
555 typeReaders.Add(ObjectMetadata.TypeTag.CHAR, ReadCharacter);
556 typeReaders.Add(ObjectMetadata.TypeTag.CMBT, ReadCombatProfile);
557 typeReaders.Add(ObjectMetadata.TypeTag.CONS, ReadConsole);
558 typeReaders.Add(ObjectMetadata.TypeTag.DOOR, ReadDoor);
559 typeReaders.Add(ObjectMetadata.TypeTag.FLAG, ReadFlag);
560 typeReaders.Add(ObjectMetadata.TypeTag.FURN, ReadFurniture);
561 typeReaders.Add(ObjectMetadata.TypeTag.MELE, ReadMeleeProfile);
562 typeReaders.Add(ObjectMetadata.TypeTag.NEUT, ReadNeutralBehavior);
563 typeReaders.Add(ObjectMetadata.TypeTag.PART, ReadParticle);
564 typeReaders.Add(ObjectMetadata.TypeTag.PATR, ReadPatrolPath);
565 typeReaders.Add(ObjectMetadata.TypeTag.PWRU, ReadPowerUp);
566 typeReaders.Add(ObjectMetadata.TypeTag.SNDG, ReadSound);
567 typeReaders.Add(ObjectMetadata.TypeTag.TRGV, ReadTriggerVolume);
568 typeReaders.Add(ObjectMetadata.TypeTag.TRIG, ReadTrigger);
569 typeReaders.Add(ObjectMetadata.TypeTag.TURR, ReadTurret);
570 typeReaders.Add(ObjectMetadata.TypeTag.WEAP, ReadWeapon);
571 }
572 }
573}
Note: See TracBrowser for help on using the repository browser.