public SetObject(SetObjectType type, string typeName, uint objID)
        {
            ObjectType = typeName;
            ObjectID   = objID;

            foreach (var param in type.Parameters)
            {
                if (param is SetObjectTypeParamGroup group)
                {
                    var g           = new SetObjectParamGroup(group.Padding);
                    var groupParams = g.Parameters;

                    foreach (var p in group.Parameters)
                    {
                        groupParams.Add(new SetObjectParam(p.DataType,
                                                           p.DefaultValue));
                    }

                    Parameters.Add(g);
                    continue;
                }

                Parameters.Add(new SetObjectParam(param.DataType,
                                                  param.DefaultValue));
            }
        }
        LoadObjectTemplates(string directory)
        {
            if (!Directory.Exists(directory))
            {
                throw new DirectoryNotFoundException();
            }

            var objectTemplates = new Dictionary <string, SetObjectType>();

            foreach (string dir in Directory.GetDirectories(directory))
            {
                string category = new DirectoryInfo(dir).Name;
                foreach (string file in Directory.GetFiles(dir, $"*{Extension}"))
                {
                    var template = new SetObjectType()
                    {
                        Category = category
                    };
                    string objTypeName = Path.GetFileNameWithoutExtension(file);
                    template.Load(file);

                    if (objectTemplates.ContainsKey(objTypeName))
                    {
                        Console.WriteLine("WARNING: Skipping over duplicate template \"{0}\".",
                                          objTypeName);
                        continue;
                    }

                    objectTemplates.Add(objTypeName, template);
                }
            }

            return(objectTemplates);
        }
        public static XElement WriteObject(SetObject obj, SetObjectType type = null)
        {
            // Parameters
            var elem = new XElement(obj.ObjectType);

            for (int i = 0; i < obj.Parameters.Count; ++i)
            {
                elem.Add(new XElement((type == null) ?
                                      $"Parameter{i + 1}" : type.Parameters[i].Name,
                                      obj.Parameters[i].Data));
            }

            // MultiSetTransforms
            if (obj.Children.Length > 0)
            {
                var multiSetParam = new XElement("MultiSetParam");
                for (int i = 0; i < obj.Children.Length;)
                {
                    var multiSetElem = new XElement("Element");
                    multiSetElem.AddElem("Index", ++i);
                    WriteTransform(obj.Children[i], multiSetElem);
                    multiSetParam.Add(multiSetElem);
                }

                elem.AddElem("BaseLine", 0);
                elem.AddElem("Count", obj.Children.Length + 1); // TODO: Is this right?
                elem.AddElem("Direction", 0);
                elem.AddElem("Interval", 1.5f);
                elem.AddElem("IntervalBase", 0);
                elem.AddElem("PositionBase", 0);
                elem.AddElem("RotationBase", 0);

                elem.Add(multiSetParam);
            }

            // Transform
            WriteTransform(obj.Transform, elem);

            // Special Parameters
            elem.AddElem("Range", obj.GetCustomDataValue <float>("Range", 100));
            elem.AddElem("SetObjectID", obj.ObjectID);

            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Range")
                {
                    continue;
                }

                elem.Add(new XElement(
                             customData.Key, customData.Value));
            }

            return(elem);
        }
Esempio n. 4
0
        private static SetObject ReadObject(ExtendedBinaryReader reader,
                                            SetObjectType objTemplate, string objType, SOBJType type,
                                            bool rawDataMode = false) // true = full, false = only remaining bytes
        {
            // For some reason these separate values are saved as one uint rather than two ushorts.
            // Because of this, the values are in a different order depending on endianness, and
            // this is the easiest known way to read them.
            uint   unknownValue = reader.ReadUInt32();
            ushort unknown1     = (ushort)((unknownValue >> 16) & 0xFFFF);
            ushort objID        = (ushort)(unknownValue & 0xFFFF);

            var obj = new SetObject()
            {
                ObjectType = objType,
                ObjectID   = objID
            };

            uint  unknown2 = reader.ReadUInt32();
            uint  unknown3 = reader.ReadUInt32();
            float unknown4 = reader.ReadSingle();

            float rangeIn          = reader.ReadSingle();
            float rangeOut         = reader.ReadSingle();
            uint  parent           = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;
            uint  transformsOffset = reader.ReadUInt32();

            uint transformCount = reader.ReadUInt32();
            uint unknown5       = reader.ReadUInt32();
            uint unknown6       = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;
            uint unknown7       = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;

            // Call me crazy, but I have a weird feeling these values aren't JUST padding
            if (unknown3 != 0 || unknown5 != 0 || unknown6 != 0 || unknown7 != 0)
            {
                Console.WriteLine("WARNING: Not padding?! ({0},{1},{2},{3})",
                                  unknown3, unknown5, unknown6, unknown7);
            }

            // Add custom data to object
            obj.CustomData.Add("Unknown1", new SetObjectParam(typeof(ushort), unknown1));
            obj.CustomData.Add("Unknown2", new SetObjectParam(typeof(uint), unknown2));
            obj.CustomData.Add("Unknown3", new SetObjectParam(typeof(uint), unknown3));
            obj.CustomData.Add("Unknown4", new SetObjectParam(typeof(float), unknown4));
            obj.CustomData.Add("RangeIn", new SetObjectParam(typeof(float), rangeIn));
            obj.CustomData.Add("RangeOut", new SetObjectParam(typeof(float), rangeOut));

            if (type == SOBJType.LostWorld)
            {
                obj.CustomData.Add("Parent", new SetObjectParam(typeof(uint), parent));
            }

            // Skip loading parameters if template doesn't exist
            if (objTemplate != null)
            {
                // Get Raw Byte Length
                var  rawDataLenExtra = objTemplate.GetExtra("RawByteLength");
                long paramBegin      = reader.BaseStream.Position;
                int  rawLength       = 0;

                if (rawDataLenExtra != null &&
                    !string.IsNullOrEmpty(rawDataLenExtra.Value))
                {
                    int.TryParse(rawDataLenExtra.Value, out rawLength);
                }

                // Read all the data then return to beginning
                if (rawDataMode == true && rawLength != 0)
                {
                    obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]),
                                                                          reader.ReadBytes(rawLength)));
                    reader.JumpTo(paramBegin);
                }

                // Parameters
                foreach (var param in objTemplate.Parameters)
                {
                    // For compatibility with SonicGlvl templates.
                    if (param.Name == "Unknown1" || param.Name == "Unknown2" ||
                        param.Name == "Unknown3" || param.Name == "RangeIn" ||
                        param.Name == "RangeOut" || param.Name == "Parent")
                    {
                        continue;
                    }

                    // Read Special Types/Fix Padding
                    if (param.DataType == typeof(uint[]))
                    {
                        // Data Info
                        reader.FixPadding(4);
                        uint arrOffset  = reader.ReadUInt32();
                        uint arrLength  = reader.ReadUInt32();
                        uint arrUnknown = reader.ReadUInt32();
                        long curPos     = reader.BaseStream.Position;

                        // Data
                        var arr = new uint[arrLength];
                        reader.JumpTo(arrOffset, false);

                        for (uint i = 0; i < arrLength; ++i)
                        {
                            arr[i] = reader.ReadUInt32();
                        }

                        obj.Parameters.Add(new SetObjectParam(param.DataType, arr));
                        reader.BaseStream.Position = curPos;
                        continue;
                    }
                    else if (param.DataType == typeof(string))
                    {
                        // Data Info
                        uint   strOffset  = reader.ReadUInt32();
                        uint   strUnknown = reader.ReadUInt32();
                        string str        = null;

                        // Data
                        if (strOffset != 0)
                        {
                            long curPos = reader.BaseStream.Position;
                            reader.JumpTo(strOffset, false);

                            str = reader.ReadNullTerminatedString();
                            reader.BaseStream.Position = curPos;
                        }

                        obj.Parameters.Add(new SetObjectParam(param.DataType, str));
                        continue;
                    }
                    else if (param.DataType == typeof(float) ||
                             param.DataType == typeof(int) || param.DataType == typeof(uint))
                    {
                        reader.FixPadding(4);
                    }
                    else if (type == SOBJType.LostWorld && param.DataType == typeof(Vector3))
                    {
                        reader.FixPadding(16);
                    }

                    // Read Data
                    var objParam = new SetObjectParam(param.DataType,
                                                      reader.ReadByType(param.DataType));
                    obj.Parameters.Add(objParam);
                }

                if (rawDataMode == false)
                {
                    long knownParamLength = (reader.BaseStream.Position - paramBegin);
                    long remainingBytes   = (rawLength - knownParamLength);

                    obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]),
                                                                          reader.ReadBytes((int)remainingBytes)));
                }
            }

            // Transforms
            uint childCount = transformCount - 1;

            obj.Children = new SetObjectTransform[childCount];
            reader.JumpTo(transformsOffset, false);

            obj.Transform = ReadTransform(reader, type == SOBJType.LostWorld);
            for (uint i = 0; i < childCount; ++i)
            {
                obj.Children[i] = ReadTransform(reader,
                                                type == SOBJType.LostWorld);
            }

            return(obj);
        }