public RawMapEntity CreateEntity(MapObjectSpawnDescriptor fromDescriptor) { MapEntityDataDescriptor template = m_editorCore.Templates.MapEntityDataDescriptors.Find(x => x.FourCC == fromDescriptor.FourCC); RawMapEntity obj = new RawMapEntity(); obj.FourCC = fromDescriptor.FourCC; obj.Fields = new PropertyCollection(); // stupid copy paste // See if our template list has a complex version of this file, otherwise grab the default. MapObjectDataDescriptor complexDescriptor = m_editorCore.Templates.MapObjectDataDescriptors.Find(x => x.FourCC == fromDescriptor.FourCC && x.TechnicalName == fromDescriptor.TechnicalName); if (complexDescriptor == null) { complexDescriptor = m_editorCore.Templates.DefaultMapObjectDataDescriptor; } // Determine which field we need to remove, and then insert in the other fields (in order) where it used to be. foreach (var fieldToReplace in complexDescriptor.DataOverrides) { for (int k = 0; k < template.Fields.Count; k++) { if (template.Fields[k].FieldName == fieldToReplace.ParameterName) { // Remove the old field. template.Fields.RemoveAt(k); // Now insert the new fields starting at the location of the one we just replaced. template.Fields.InsertRange(k, fieldToReplace.Values); break; } } } // Finally initialize the fields using default values. for (int i = 0; i < template.Fields.Count; i++) { var templateProperty = template.Fields[i]; string propertyName = templateProperty.FieldName; PropertyType type = templateProperty.FieldType; object value = GetDefaultValue(templateProperty); if (propertyName == "Name") { value = fromDescriptor.TechnicalName; } obj.Fields.Properties.Add(new Property(propertyName, type, value)); } return(obj); }
public void LoadTemplates(string entityDescriptorPath, string objectDescriptorPath) { // Load Entity Data, which describes the layout of various entities in a map. DirectoryInfo mapEntityDescriptorDirectory = new DirectoryInfo(entityDescriptorPath); MapEntityDataDescriptors = new List <MapEntityDataDescriptor>(); foreach (var file in mapEntityDescriptorDirectory.GetFiles()) { var template = JsonConvert.DeserializeObject <MapEntityDataDescriptor>(File.ReadAllText(file.FullName)); MapEntityDataDescriptors.Add(template); } // Then load the Object Data, which describes the layout of specific actors since their parameters change // depending on the actor used. DirectoryInfo objDataDI = new DirectoryInfo(objectDescriptorPath); MapObjectDataDescriptors = new List <MapObjectDataDescriptor>(); foreach (var file in objDataDI.GetFiles()) { var descriptor = JsonConvert.DeserializeObject <MapObjectDataDescriptor>(File.ReadAllText(file.FullName)); MapObjectDataDescriptors.Add(descriptor); if (descriptor.TechnicalName == "DEFAULT_TEMPLATE") { if (DefaultMapObjectDataDescriptor != null) { WLog.Warning(LogCategory.EntityLoading, null, "Found multiple default MapObjectDataDescriptors, ignoring."); continue; } DefaultMapObjectDataDescriptor = descriptor; } } if (DefaultMapObjectDataDescriptor == null) { throw new FileNotFoundException("Default MapObjectDataDescriptor not found!", objectDescriptorPath); } }
private RawMapEntity LoadMapEntityFromStream(string chunkFourCC, EndianBinaryReader reader, MapEntityDataDescriptor template) { RawMapEntity obj = new RawMapEntity(); obj.Fields = new PropertyCollection(); obj.FourCC = chunkFourCC; // We're going to examine the Template's properties and load based on the current template type. for (int i = 0; i < template.Fields.Count; i++) { var templateProperty = template.Fields[i]; string propertyName = templateProperty.FieldName; PropertyType type = templateProperty.FieldType; object value = null; switch (type) { case PropertyType.FixedLengthString: value = reader.ReadString(templateProperty.Length).Trim(new[] { '\0' }); break; case PropertyType.String: value = reader.ReadStringUntil('\0'); break; case PropertyType.Byte: value = reader.ReadByte(); break; case PropertyType.Short: value = reader.ReadInt16(); break; case PropertyType.Int32BitField: case PropertyType.Int32: value = reader.ReadInt32(); break; case PropertyType.Float: value = reader.ReadSingle(); break; case PropertyType.Vector3: value = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); break; case PropertyType.Vector2: value = new Vector2(reader.ReadSingle(), reader.ReadSingle()); break; case PropertyType.Enum: byte enumIndexBytes = reader.ReadByte(); // ToDo: Resolve to actual Enum later. value = enumIndexBytes; break; case PropertyType.ObjectReference: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. value = (int)reader.ReadByte(); break; case PropertyType.ObjectReferenceShort: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. value = (int)reader.ReadUInt16(); break; case PropertyType.ObjectReferenceArray: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. var refList = new BindingList <object>(); for (int refArray = 0; refArray < templateProperty.Length; refArray++) { refList.Add((int)reader.ReadByte()); } value = refList; break; case PropertyType.XYRotation: { Vector3 eulerAngles = new Vector3(); for (int f = 0; f < 2; f++) { eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f)); } Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad); // Swizzling to the ZYX order seems to be the right one. Quaternion finalRot = yAxis * xAxis; value = finalRot; } break; case PropertyType.XYZRotation: { Vector3 eulerAngles = new Vector3(); for (int f = 0; f < 3; f++) { eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f)); } Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad); Quaternion zAxis = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), eulerAngles.Z * MathE.Deg2Rad); // Swizzling to the ZYX order seems to be the right one. Quaternion finalRot = zAxis * yAxis * xAxis; value = finalRot; } break; case PropertyType.YRotation: { float yRotation = reader.ReadInt16() * (180 / 32786f); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), yRotation * MathE.Deg2Rad); value = yAxis; } break; case PropertyType.Color32: value = new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Color24: value = new Color24(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Vector3Byte: type = PropertyType.Vector3Byte; value = new Vector3(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Bits: value = (byte)reader.ReadBits(templateProperty.Length); break; } // This... this could get dicy. If the template we just read was a "Name" then we now have the technical name (and value) // of the object. We can then search for the MapObjectDataDescriptor that matches the technical name, and then edit the // remaining fields. However, this gets somewhat dicey, because we're modifying the length of the Fields array for templates // while iterating through it. However, the Name field always comes before any of the fields we'd want to modify, we're going to // do an in-place replacement of the fields (since Fields.Count will increase) and then we get free loading of the complex templates // without later post-processing them. if (templateProperty.FieldName == "Name") { // See if our template list has a complex version of this file, otherwise grab the default. MapObjectDataDescriptor complexDescriptor = m_editorCore.Templates.MapObjectDataDescriptors.Find(x => x.FourCC == chunkFourCC && x.TechnicalName == templateProperty.FieldName); if (complexDescriptor == null) { complexDescriptor = m_editorCore.Templates.DefaultMapObjectDataDescriptor; } // Determine which field we need to remove, and then insert in the other fields (in order) where it used to be. foreach (var fieldToReplace in complexDescriptor.DataOverrides) { for (int k = 0; k < template.Fields.Count; k++) { if (template.Fields[k].FieldName == fieldToReplace.ParameterName) { // Remove the old field. template.Fields.RemoveAt(k); // Now insert the new fields starting at the location of the one we just replaced. template.Fields.InsertRange(k, fieldToReplace.Values); break; } } } } Property instanceProp = new Property(templateProperty.FieldName, type, value); obj.Fields.Properties.Add(instanceProp); } return(obj); }