private static ObjectInfo GetObjectInfo(ref ArrayEntry objectEntry, SM3DWorldZone zone) { Dictionary <string, DictionaryEntry> properties = new Dictionary <string, DictionaryEntry>(); Dictionary <string, DictionaryEntry> links = new Dictionary <string, DictionaryEntry>(); ObjectInfo info = new ObjectInfo(); foreach (DictionaryEntry entry in objectEntry.IterDictionary()) { switch (entry.Key) { case "Comment": case "IsLinkDest": case "LayerConfigName": #if ODYSSEY case "SrcUnitLayerList": case "PlacementFileName": case "comment": #endif break; //ignore these case "Id": info.ID = entry.Parse(); break; case "Links": foreach (DictionaryEntry linkEntry in entry.IterDictionary()) { links.Add(linkEntry.Key, linkEntry); } break; case "ModelName": info.ModelName = entry.Parse() ?? ""; break; case "Rotate": dynamic _data = entry.Parse(); info.Rotation = new Vector3( _data["X"], _data["Y"], _data["Z"] ); break; case "Scale": _data = entry.Parse(); info.Scale = new Vector3( _data["X"], _data["Y"], _data["Z"] ); break; case "Translate": _data = entry.Parse(); info.Position = new Vector3( _data["X"] / 100f, _data["Y"] / 100f, _data["Z"] / 100f ); break; case "UnitConfigName": info.ObjectName = entry.Parse(); break; case "UnitConfig": _data = entry.Parse(); info.DisplayTranslation = new Vector3( _data["DisplayTranslate"]["X"] / 100f, _data["DisplayTranslate"]["Y"] / 100f, _data["DisplayTranslate"]["Z"] / 100f ); info.DisplayRotation = new Vector3( _data["DisplayRotate"]["X"], _data["DisplayRotate"]["Y"], _data["DisplayRotate"]["Z"] ); info.DisplayScale = new Vector3( _data["DisplayScale"]["X"], _data["DisplayScale"]["Y"], _data["DisplayScale"]["Z"] ); info.ClassName = _data["ParameterConfigName"]; break; default: if (!properties.ContainsKey(entry.Key)) { properties.Add(entry.Key, entry); } break; } } info.PropertyEntries = properties; info.LinkEntries = links; return(info); }
/// <summary> /// Parses a 3d World from an ArrayEntry /// </summary> /// <param name="objectEntry"></param> /// <param name="zone"></param> /// <param name="objectsByReference"></param> /// <returns></returns> public static I3dWorldObject ParseObject(ArrayEntry objectEntry, SM3DWorldZone zone, Dictionary <long, I3dWorldObject> objectsByReference, out bool alreadyInLinks, Dictionary <string, I3dWorldObject> linkedObjsByID, bool isLinked = false) { ObjectInfo info = GetObjectInfo(ref objectEntry, zone); I3dWorldObject obj; bool loadLinks; if ((info.ClassName == "Area") || info.ObjectName.Contains("Area") && AreaModelNames.Contains(info.ModelName)) { obj = new AreaObject(in info, zone, out loadLinks); } else if (info.PropertyEntries.TryGetValue("RailPoints", out DictionaryEntry railPointEntry) && railPointEntry.NodeType == ByamlFile.ByamlNodeType.Array) //at this point we can be sure it's a rail { obj = new Rail(in info, zone, out loadLinks); } else { obj = new General3dWorldObject(in info, zone, out loadLinks); } if (isLinked && linkedObjsByID != null) { if (!linkedObjsByID.ContainsKey(info.ID)) { linkedObjsByID.Add(info.ID, obj); } else { alreadyInLinks = true; obj = linkedObjsByID[info.ID]; if (!isLinked) { alreadyInLinks = !zone.LinkedObjects.Remove(obj); } //in case this object was already read in another file if (!objectsByReference.ContainsKey(objectEntry.Position)) { objectsByReference.Add(objectEntry.Position, obj); } return(obj); } } alreadyInLinks = false; if (!objectsByReference.ContainsKey(objectEntry.Position)) { objectsByReference.Add(objectEntry.Position, obj); } else if (!isLinked) { obj = objectsByReference[objectEntry.Position]; zone.LinkedObjects.Remove(obj); return(obj); } if (loadLinks) { var links = new Dictionary <string, List <I3dWorldObject> >(); foreach (DictionaryEntry link in info.LinkEntries.Values) { links.Add(link.Key, new List <I3dWorldObject>()); foreach (ArrayEntry linked in link.IterArray()) { if (objectsByReference.ContainsKey(linked.Position)) { links[link.Key].Add(objectsByReference[linked.Position]); objectsByReference[linked.Position].AddLinkDestination(link.Key, obj); } else { I3dWorldObject _obj = ParseObject(linked, zone, objectsByReference, out bool linkedAlreadyReferenced, linkedObjsByID, true); _obj.AddLinkDestination(link.Key, obj); links[link.Key].Add(_obj); if (zone != null && !linkedAlreadyReferenced) { zone.LinkedObjects.Add(_obj); } } } } if (links.Count > 0) { obj.Links = links; } } return(obj); }
/// <summary> /// Parses a 3d World from an ArrayEntry /// </summary> /// <param name="objectEntry"></param> /// <param name="zone"></param> /// <param name="objectsByReference"></param> /// <returns></returns> public static I3dWorldObject ParseObject(ArrayEntry objectEntry, SM3DWorldZone zone, Dictionary <long, I3dWorldObject> objectsByReference, out bool alreadyInLinks, Dictionary <string, I3dWorldObject> linkedObjsByID, bool isLinked = false) { ObjectInfo info = GetObjectInfo(ref objectEntry, zone); I3dWorldObject obj; bool loadLinks; if (Enum.GetNames(typeof(Rail.RailObjType)).Contains(info.ClassName)) { obj = new Rail(info, zone, out loadLinks); } else { obj = new General3dWorldObject(info, zone, out loadLinks); } if (linkedObjsByID != null && isLinked) { if (!linkedObjsByID.ContainsKey(info.ID)) { linkedObjsByID.Add(info.ID, obj); } else { alreadyInLinks = true; obj = linkedObjsByID[info.ID]; if (!isLinked) { alreadyInLinks = !zone.LinkedObjects.Remove(obj); } //in case this object was already read in another file if (!objectsByReference.ContainsKey(objectEntry.Position)) { objectsByReference.Add(objectEntry.Position, obj); } return(obj); } } alreadyInLinks = false; if (!objectsByReference.ContainsKey(objectEntry.Position)) { objectsByReference.Add(objectEntry.Position, obj); } else if (!isLinked) { obj = objectsByReference[objectEntry.Position]; zone.LinkedObjects.Remove(obj); return(obj); } if (loadLinks) { obj.Links = new Dictionary <string, List <I3dWorldObject> >(); foreach (DictionaryEntry link in info.LinkEntries.Values) { obj.Links.Add(link.Key, new List <I3dWorldObject>()); foreach (ArrayEntry linked in link.IterArray()) { if (objectsByReference.ContainsKey(linked.Position)) { obj.Links[link.Key].Add(objectsByReference[linked.Position]); objectsByReference[linked.Position].AddLinkDestination(link.Key, obj); } else { I3dWorldObject _obj = ParseObject(linked, zone, objectsByReference, out bool linkedAlreadyReferenced, linkedObjsByID, true); _obj.AddLinkDestination(link.Key, obj); obj.Links[link.Key].Add(_obj); if (zone != null && !linkedAlreadyReferenced) { zone.LinkedObjects.Add(_obj); } } } } if (obj.Links.Count == 0) { obj.Links = null; } } return(obj); }