예제 #1
0
파일: TextEnv.cs 프로젝트: sc2ad/BnkParser
        public void Parse(AssetsFile file, AssetsObject owner, AssetsReader reader)
        {
            Texture = SmartPtr <Texture2DObject> .Read(file, owner, reader);

            Scale  = new Vector2F(reader);
            Offset = new Vector2F(reader);
        }
예제 #2
0
        private List <CloneExclusion> GetExclusionsForObject(AssetsObject o, AssetsFile targetAssetsFile)
        {
            List <CloneExclusion> exclusions = new List <CloneExclusion>();

            //exclude any monobehaviors that the script type can't be found for
            exclusions.Add(new CloneExclusion(ExclusionMode.Remove)
            {
                Filter = (ptr, propInfo) =>
                {
                    var res = ptr != null && ptr.Object is MonoBehaviourObject && targetAssetsFile.Manager.GetScriptObject(ptr.Target.Type.TypeHash) == null;
                    if (res)
                    {
                        Log.LogMsg($"Removing MonoBehaviour object during cloning because type hash '{ptr.Target.Type.TypeHash}' doesn't exist in the target.");
                    }
                    return(res);
                }
            });
            exclusions.Add(new CloneExclusion(ExclusionMode.Remove)
            {
                Filter = (ptr, propInfo) =>
                {
                    var res = ptr != null && ptr.Target.Type.ClassID == AssetsConstants.ClassID.AnimationClassID;
                    if (res)
                    {
                        Log.LogMsg($"Removing Animation object during cloning because it isn't supported yet.");
                    }
                    return(res);
                }
            });
            if (typeof(Transform).IsAssignableFrom(o.GetType()))
            {
                exclusions.Add(new CloneExclusion(ExclusionMode.LeaveRef, propertyName: "Father", pointerTarget: ((Transform)o).Father.Target.Object));
            }
            return(exclusions);
        }
예제 #3
0
 public CloneExclusion(ExclusionMode mode, string propertyName = null, RawPtr pointer = null, AssetsObject pointerTarget = null, Type type = null)
 {
     Mode          = mode;
     PropertyName  = propertyName;
     Pointer       = pointer;
     Type          = type;
     PointerTarget = pointerTarget;
 }
예제 #4
0
 private void Parse(AssetsFile assetsFile, AssetsObject owner, AssetsReader reader)
 {
     Difficulty              = (Difficulty)reader.ReadInt32();
     DifficultyRank          = reader.ReadInt32();
     NoteJumpMovementSpeed   = reader.ReadSingle();
     NoteJumpStartBeatOffset = reader.ReadInt32();
     BeatmapDataPtr          = SmartPtr <BeatmapDataObject> .Read(assetsFile, owner, reader);
 }
예제 #5
0
        public static ISmartPtr <AssetsObject> MakeTypedPointer(AssetsObject owner, AssetsObject target)
        {
            var genericInfoType = typeof(SmartPtr <>).MakeGenericType(target.GetType());
            var constructor     = genericInfoType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(AssetsObject), target.GetType() }, null);

            if (constructor == null)
            {
                throw new Exception("Unable to find the proper SmartPtr constructor!");
            }
            return((ISmartPtr <AssetsObject>)constructor.Invoke(new object[] { owner, target }));
        }
예제 #6
0
 private void TestCloneObject(AssetsObject ao)
 {
     try
     {
         var  cloned  = ao.ObjectInfo.DeepClone();
         Node nOrig   = Node.MakeNode(ao);
         Node nCloned = Node.MakeNode(cloned);
         etLeft.DataSource       = nOrig;
         etRight.DataSource      = nCloned;
         tabControl1.SelectedTab = tpCompare;
     }
     catch (Exception ex)
     {
         Log.LogErr("Failed to clone object!", ex);
         MessageBox.Show("Failed to even clone!");
     }
 }
예제 #7
0
        public void Parse(AssetsFile file, AssetsObject owner, AssetsReader reader)
        {
            var count = reader.ReadInt32();

            for (int i = 0; i < count; i++)
            {
                TexEnvs.Add(new Map <string, TexEnv>(reader.ReadString(), new TexEnv(file, owner, reader)));
            }
            count = reader.ReadInt32();
            for (int i = 0; i < count; i++)
            {
                Floats.Add(new Map <string, Single>(reader.ReadString(), reader.ReadSingle()));
            }

            count = reader.ReadInt32();
            for (int i = 0; i < count; i++)
            {
                Colors.Add(new Map <string, Color>(reader.ReadString(), new Color(reader)));
            }
        }
예제 #8
0
 public static ISmartPtr <T> PtrFrom <T>(this T assetObject, AssetsObject owner) where T : AssetsObject
 {
     return(new SmartPtr <T>(owner, assetObject));
 }
예제 #9
0
        public static IObjectInfo <AssetsObject> FromTypeIndex(AssetsFile assetsFile, int typeIndex, AssetsObject assetsObject)
        {
            var type            = GetObjectType(assetsFile, typeIndex);
            var genericInfoType = typeof(ObjectInfo <>).MakeGenericType(type);
            var constructor     = genericInfoType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Int64), typeof(int), typeof(int), typeof(int), typeof(AssetsFile), type }, null);

            var genericOI = (IObjectInfo <AssetsObject>)constructor.Invoke(new object[] { (Int64)(-1), (int)-1, (int)-1, typeIndex, assetsFile, assetsObject });

            return(genericOI);
        }
예제 #10
0
        public static IObjectInfo <AssetsObject> FromTypeHash(AssetsFile assetsFile, Guid typeHash, AssetsObject assetsObject)
        {
            var typeIndex = assetsFile.Metadata.Types.IndexOf(assetsFile.Metadata.Types.First(x => x.TypeHash == typeHash));

            return(FromTypeIndex(assetsFile, typeIndex, assetsObject));
        }
예제 #11
0
        public static IObjectInfo <AssetsObject> FromClassID(AssetsFile assetsFile, int classID, AssetsObject assetsObject)
        {
            var foundType = assetsFile.Metadata.Types.FirstOrDefault(x => x.ClassID == classID);

            if (foundType == null)
            {
                Log.LogMsg($"Type with class ID {classID} was not found in file {assetsFile.AssetsFilename}, it will be added.");
                if (classID == AssetsConstants.ClassID.MonoBehaviourScriptType || classID == AssetsConstants.ClassID.MonoScriptType)
                {
                    Log.LogErr("Monoscripts and Monobehaviours can't be created in files that don't already have them by using a class ID.");
                    throw new Exception("Class ID not found in file!");
                }
                assetsFile.Metadata.Types.Add(new AssetsType()
                {
                    ClassID = classID
                });
            }
            var typeIndex = assetsFile.Metadata.Types.IndexOf(assetsFile.Metadata.Types.First(x => x.ClassID == classID));

            return(FromTypeIndex(assetsFile, typeIndex, assetsObject));
        }
예제 #12
0
        // yeesh, so much copy/paste code.  I WILL DO BETTER THAN THIS

        //todo: refactor
        private void DoPaste(Node targetNode)
        {
            try
            {
                var node      = GetClipData();
                var sourceObj = node?.Obj as AssetsObject;
                var targetObj = targetNode?.Obj;

                AssetsFile   targetFile            = null;
                Node         targetOwnerNode       = null;
                AssetsObject targetOwnerObj        = null;
                object       targetDirectParentObj = null;

                if (node == null || node.Obj == null || node.StubToNode != null || sourceObj == null || targetObj == null)
                {
                    return;
                }
                bool isFile = false;
                if (targetObj is AssetsFile)
                {
                    isFile          = true;
                    targetFile      = targetObj as AssetsFile;
                    targetOwnerNode = targetNode.Parent;
                }
                else
                {
                    targetOwnerNode       = FindFirstParent(targetNode);
                    targetOwnerObj        = targetOwnerNode?.Obj as AssetsObject;
                    targetDirectParentObj = targetNode?.Parent?.Obj;
                    if (targetOwnerObj == null)
                    {
                        Log.LogErr($"Tried to paste, but couldn't find the assetsobject owner on node '{targetNode.Text}'");
                        return;
                    }
                    if (targetDirectParentObj == null)
                    {
                        Log.LogErr($"Tried to paste, but couldn't find the actual parent on node '{targetNode.Text}'");
                        return;
                    }
                    if (string.IsNullOrWhiteSpace(targetNode.ParentPropertyName))
                    {
                        Log.LogErr($"Tried to paste, but parent property name was null on node '{targetNode.Text}'");
                        return;
                    }
                    targetFile = targetOwnerObj.ObjectInfo.ParentFile;
                }
                List <AssetsObject> addedObjects = new List <AssetsObject>();
                AssetsObject        cloned       = null;
                try
                {
                    var exclus = GetExclusionsForObject(sourceObj, targetFile);
                    cloned = sourceObj.ObjectInfo.DeepClone(targetFile, addedObjects: addedObjects, exclusions: exclus);
                }
                catch (Exception ex)
                {
                    Log.LogErr($"Exception trying to clone object of type {sourceObj.GetType().Name}!", ex);
                    try
                    {
                        foreach (var ao in addedObjects)
                        {
                            targetFile.DeleteObject(ao);
                        }
                    }
                    catch (Exception ex2)
                    {
                        Log.LogErr("Failed to clean up after bad clone!", ex2);
                        MessageBox.Show("A clone failed and the rollback failed too.  The assets files are in an unknown state!");
                    }
                    return;
                }
                bool updated = false;
                if (isFile)
                {
                    updated = true;
                }
                else
                {
                    var ptrList = targetObj as IEnumerable <ISmartPtr <AssetsObject> >;
                    if (ptrList != null)
                    {
                        try
                        {
                            var pointer = ReflectionHelper.MakeTypedPointer(targetOwnerObj, cloned);
                            ReflectionHelper.AddObjectToEnum(pointer, ptrList);
                            updated = true;
                        }
                        catch (Exception ex)
                        {
                            Log.LogErr($"Adding object to collection failed!", ex);
                            MessageBox.Show("Object was created, but could not be attached to the collection!");
                            return;
                        }
                    }

                    var ptr = targetObj as ISmartPtr <AssetsObject>;
                    if (ptr != null)
                    {
                        try
                        {
                            var pointer    = ReflectionHelper.MakeTypedPointer(targetOwnerObj, cloned);
                            var oldPointer = ReflectionHelper.GetPtrFromPropName(targetDirectParentObj, targetNode.ParentPropertyName);
                            ReflectionHelper.AssignPtrToPropName(targetDirectParentObj, targetNode.ParentPropertyName, pointer);
                            oldPointer.Dispose();
                            updated = true;
                        }
                        catch (Exception ex)
                        {
                            Log.LogErr($"Replacing pointer failed on {targetDirectParentObj?.GetType()?.Name}.{targetNode.ParentPropertyName}!");
                        }
                    }
                }
                if (updated)
                {
                    var res = (tvExplorer.Nodes[0].Tag as Node).GetNodePath(targetNode);
                    //update node, hopefully we won't have to repopulate the entire thing?



                    if (!isFile)
                    {
                        Node newNode = Node.MakeNode(targetOwnerObj);
                        var  targetOwnerParentNode = targetOwnerNode.Parent;
                        var  idx = targetOwnerNode.Parent.Nodes.IndexOf(targetOwnerNode);
                        targetOwnerParentNode.Nodes.RemoveAt(idx);
                        targetOwnerParentNode.Nodes.Insert(idx, newNode);
                        newNode.Parent             = targetOwnerParentNode;
                        newNode.ParentPropertyName = targetOwnerNode.ParentPropertyName;
                    }
                    else
                    {
                        Node newNode = Node.MakeNode((AssetsFile)targetObj);
                        var  idx     = targetNode.Parent.Nodes.IndexOf(targetNode);
                        targetNode.Parent.Nodes.RemoveAt(idx);
                        targetNode.Parent.Nodes.Insert(idx, newNode);
                        newNode.Parent             = targetNode;
                        newNode.ParentPropertyName = null;
                    }

                    //TODO: find a better way to refresh only the altered tree node and not the whole thing

                    var ds = DataSource;
                    DataSource = null;
                    DataSource = ds;

                    TreeNode tn = tvExplorer.Nodes[0];
                    while (res.Count > 0)
                    {
                        tn = tn.Nodes[res.Pop()] as TreeNode;
                    }
                    tn.EnsureVisible();
                    SelectedNode = tn;
                    tn.Expand();

                    return;
                }
            }
            catch (Exception ex)
            {
                Log.LogErr($"Exception trying to paste object!", ex);
                MessageBox.Show("Failed to paste object!");
            }
        }
예제 #13
0
 public PropertySheet(AssetsFile file, AssetsObject owner, AssetsReader reader)
 {
     Parse(file, owner, reader);
 }
예제 #14
0
        private void Parse(AssetsFile assetsFile, AssetsObject owner, AssetsReader reader)
        {
            BeatmapCharacteristic = SmartPtr <AssetsObject> .Read(assetsFile, owner, reader);

            DifficultyBeatmaps = reader.ReadArrayOf(x => new DifficultyBeatmap(assetsFile, owner, x));
        }
예제 #15
0
 public static ISmartPtr <T> PtrFrom <T>(this IObjectInfo <T> objectInfo, AssetsObject owner) where T : AssetsObject
 {
     return(new SmartPtr <T>(owner, objectInfo));
 }
예제 #16
0
 public DifficultyBeatmap(AssetsFile assetsFile, AssetsObject owner, AssetsReader reader)
 {
     Parse(assetsFile, owner, reader);
 }
예제 #17
0
 public AlbumArtMetadata(AssetsFile file, AssetsObject o, AssetsReader reader)
 {
     assetsFile = file;
     owner      = o;
     Parse(reader);
 }
예제 #18
0
파일: TextEnv.cs 프로젝트: sc2ad/BnkParser
 public TexEnv(AssetsFile file, AssetsObject owner, AssetsReader reader)
 {
     Parse(file, owner, reader);
 }
예제 #19
0
        private static void ClonePropsInObj(object curObj, AssetsObject parentObj, Dictionary <AssetsObject, AssetsObject> clonedObjects, AssetsFile toFile, List <AssetsObject> addedObjects, List <CloneExclusion> exclusions)
        {
            var file        = parentObj.ObjectInfo.ParentFile.AssetsFilename;
            var updateProps = curObj.GetType().GetProperties().ToList();

            //remove any array properties that are a string or a value type
            updateProps.Where(x => x.PropertyType.IsArray && (x.PropertyType.GetElementType().IsValueType || x.PropertyType.GetElementType() == typeof(string)))
            .ToList().ForEach(x => updateProps.Remove(x));

            //look through any properties that are smart pointers, clone their targets and make a new pointer, then remove them from the list of props to update
            var propsToClone = updateProps.Where(x => typeof(ISmartPtr <AssetsObject>).IsAssignableFrom(x.PropertyType)).ToList();

            foreach (var prop in propsToClone)
            {
                var baseVal = prop.GetValue(curObj, null);
                if (baseVal == null)
                {
                    continue;
                }
                var          propPtr      = (prop.GetValue(curObj, null) as ISmartPtr <AssetsObject>);
                var          propObj      = propPtr.Target.Object;
                AssetsObject assignObject = null;

                switch (exclusions.GetExclusionMode(propPtr, prop))
                {
                case ExclusionMode.LeaveRef:
                    assignObject = propObj;
                    break;

                case ExclusionMode.Remove:
                    assignObject = null;
                    Log.LogErr($"WARNING: Cloner is leaving the pointer NULL on property '{curObj.GetType().Name}.{prop.Name}'");
                    break;

                default:
                    assignObject = DeepClone(propObj, toFile, addedObjects, clonedObjects, exclusions);
                    break;
                }

                prop.SetValue(curObj, ReflectionHelper.MakeTypedPointer(parentObj, assignObject), null);
            }
            propsToClone.ForEach(x => updateProps.Remove(x));

            //look through any properties that lists of smart pointers, this code isn't ideal because it only actually supports things that have a default indexer
            //  I should clean this up to work better
            var listsToClone = updateProps.Where(x => typeof(IEnumerable <ISmartPtr <AssetsObject> >).IsAssignableFrom(x.PropertyType)).ToList();

            foreach (var listProp in listsToClone)
            {
                var listVal = listProp.GetValue(curObj, null) as IEnumerable <ISmartPtr <AssetsObject> >;

                if (listVal == null)
                {
                    continue;
                }
                if (listProp.PropertyType.IsArray)
                {
                    Array listArr = (Array)listVal;
                    for (int i = 0; i < listArr.Length; i++)
                    {
                        var ptrVal = listArr.GetValue(i) as ISmartPtr <AssetsObject>;
                        ISmartPtr <AssetsObject> clonedObj = null;
                        switch (exclusions.GetExclusionMode(ptrVal, listProp))
                        {
                        case ExclusionMode.LeaveRef:
                            clonedObj = listArr.GetValue(i) as ISmartPtr <AssetsObject>;
                            break;

                        case ExclusionMode.Remove:
                            clonedObj = null;
                            break;

                        default:
                            clonedObj = ReflectionHelper.MakeTypedPointer(DeepClone(ptrVal.Target.Object, toFile, addedObjects, clonedObjects, exclusions), parentObj);
                            break;
                        }
                        if (clonedObj == null)
                        {
                            listArr.RemoveAt(i);
                            i--;
                        }
                        else
                        {
                            listArr.SetValue(clonedObj, i);
                        }
                    }
                }
                else
                {
                    var indexerProp = listVal.GetType().GetProperties().Where(x => x.Name == "Item").FirstOrDefault();

                    if (indexerProp == null)
                    {
                        throw new NotSupportedException($"Couldn't find the default indexer property on {curObj.GetType().Name}.{listProp.Name}!");
                    }
                    for (int i = 0; i < listVal.Count(); i++)
                    {
                        var          ptrVal    = indexerProp.GetValue(listVal, new object[] { i }) as ISmartPtr <AssetsObject>;
                        AssetsObject clonedObj = null;
                        switch (exclusions.GetExclusionMode(ptrVal, listProp))
                        {
                        case ExclusionMode.LeaveRef:
                            clonedObj = ptrVal.Target.Object;
                            break;

                        case ExclusionMode.Remove:
                            clonedObj = null;
                            break;

                        default:
                            clonedObj = DeepClone(ptrVal.Target.Object, toFile, addedObjects, clonedObjects, exclusions);
                            break;
                        }

                        //if the cloned object comes back null, remove it from the list instead of setting it null
                        if (clonedObj == null)
                        {
                            ReflectionHelper.InvokeRemoveAt(listVal, i);
                        }
                        else
                        {
                            indexerProp.SetValue(listVal, ReflectionHelper.MakeTypedPointer(parentObj as AssetsObject, clonedObj), new object[] { i });
                        }
                    }
                }
            }
            listsToClone.ForEach(x => updateProps.Remove(x));

            //look through any objects that are plain old lists of whatever.  this is to catch lists of "structs" that may have pointers in them
            var plainEnumerableToClone = updateProps.Where(x => !x.PropertyType.IsValueType && !(x.PropertyType == typeof(string)) && typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList();

            foreach (var enumProp in plainEnumerableToClone)
            {
                var listVal = enumProp.GetValue(curObj, null) as IEnumerable;

                if (listVal == null)
                {
                    continue;
                }

                foreach (var plainObj in listVal)
                {
                    //pass in the parent AssetsObject that was passed to us since that object will be the "owner", not the struct object
                    ClonePropsInObj(plainObj, parentObj, clonedObjects, toFile, addedObjects, exclusions);
                }
            }
            plainEnumerableToClone.ForEach(x => updateProps.Remove(x));
            //look through any "struct" type properties that may have pointers in them
            var plainObjToClone = updateProps.Where(x => !x.PropertyType.IsValueType && !(x.PropertyType == typeof(string)));

            foreach (var plainProp in plainObjToClone)
            {
                var objVal = plainProp.GetValue(curObj, null) as IEnumerable;
                if (objVal == null)
                {
                    continue;
                }

                foreach (var plainObj in objVal)
                {
                    //pass in the parent AssetsObject that was passed to us since that object will be the "owner", not the struct object
                    ClonePropsInObj(plainObj, parentObj, clonedObjects, toFile, addedObjects, exclusions);
                }
            }
        }
예제 #20
0
 public DecorationEntry(AssetsFile f, AssetsObject o, AssetsReader reader)
 {
     file  = f;
     owner = o;
     Parse(reader);
 }