Example #1
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;
        }