Example #1
0
        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);
        }
Example #2
0
        public void LoadFromStream(Scene parentScene, EndianBinaryReader reader)
        {
            var  mapEntities     = new List <RawMapEntity>();
            long fileOffsetStart = reader.BaseStream.Position;

            // File Header
            int chunkCount = reader.ReadInt32();

            // Read the chunk headers
            List <ChunkHeader> chunks = new List <ChunkHeader>();

            for (int i = 0; i < chunkCount; i++)
            {
                ChunkHeader chunk = new ChunkHeader();
                chunk.FourCC       = reader.ReadString(4);
                chunk.ElementCount = reader.ReadInt32();
                chunk.ChunkOffset  = reader.ReadInt32();

                chunk.Layer  = ResolveChunkFourCCToLayer(chunk.FourCC);
                chunk.FourCC = ResolveFourCCWithLayerToName(chunk.FourCC);

                chunks.Add(chunk);
            }

            // For each chunk, read all elements of that type of chunk.
            for (int i = 0; i < chunks.Count; i++)
            {
                ChunkHeader chunk = chunks[i];

                // Find the appropriate JSON template that describes this chunk.
                MapEntityDataDescriptor template = m_editorCore.Templates.MapEntityDataDescriptors.Find(x => x.FourCC == chunk.FourCC);

                if (template == null)
                {
                    WLog.Error(LogCategory.EntityLoading, null, "Unsupported entity FourCC: {0}. Map will save without this data!", chunk.FourCC);
                    continue;
                }

                reader.BaseStream.Position = chunk.ChunkOffset;

                for (int k = 0; k < chunk.ElementCount; k++)
                {
                    RawMapEntity entityInstance = LoadMapEntityFromStream(chunk.FourCC, reader, template);

                    entityInstance.Layer = chunk.Layer;
                    mapEntities.Add(entityInstance);
                }
            }

            m_entityData[parentScene] = mapEntities;
        }
Example #3
0
        public void PostProcessEntities()
        {
            foreach (var kvp in m_entityData)
            {
                foreach (var entity in kvp.Value)
                {
                    MapEntityDataDescriptor origTemplate = m_editorCore.Templates.MapEntityDataDescriptors.Find(x => string.Compare(x.FourCC, entity.FourCC, StringComparison.InvariantCultureIgnoreCase) == 0);
                    if (origTemplate == null)
                    {
                        WLog.Warning(LogCategory.EntityLoading, null, "Failed to find template for entity {0}, not attempting to post-process.", entity);
                        continue;
                    }

                    foreach (Property property in entity.Fields.Properties)
                    {
                        var origTemplateProperty = origTemplate.Fields.Find(x => x.FieldName == property.Name);
                        if (origTemplateProperty == null)
                        {
                            WLog.Warning(LogCategory.EntityLoading, null, "Failed to find property {0} on template {1} for entity {2}, not attempting to post-process.", property.Name, origTemplate.FourCC, entity);
                            continue;
                        }

                        // We cheated earlier and stored the various reference-type ones as their index values. That means the type of the object doesn't actually
                        // reflect the Type field. Thus, we now need to go back, patch up the references, and set them to be their proper type. Yeah!
                        switch (origTemplateProperty.FieldType)
                        {
                        case PropertyType.ObjectReference:
                        case PropertyType.ObjectReferenceShort:
                        {
                            int objIndex = (int)property.Value;
                            property.Value = ResolveEntityReference(entity.FourCC, origTemplateProperty, objIndex, kvp.Key);
                        }
                        break;

                        case PropertyType.ObjectReferenceArray:
                        {
                            BindingList <object> indexes      = (BindingList <object>)property.Value;
                            BindingList <object> resolvedRefs = new BindingList <object>();
                            for (int i = 0; i < indexes.Count; i++)
                            {
                                var obj = ResolveEntityReference(entity.FourCC, origTemplateProperty, (int)indexes[i], kvp.Key);
                                resolvedRefs.Add(obj);
                            }
                            property.Value = resolvedRefs;
                        }
                        break;
                        }
                    }
                }
            }
        }
Example #4
0
        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);
        }