public void Parse(AssetsFile file, AssetsObject owner, AssetsReader reader) { Texture = SmartPtr <Texture2DObject> .Read(file, owner, reader); Scale = new Vector2F(reader); Offset = new Vector2F(reader); }
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); }
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; }
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); }
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 })); }
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!"); } }
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))); } }
public static ISmartPtr <T> PtrFrom <T>(this T assetObject, AssetsObject owner) where T : AssetsObject { return(new SmartPtr <T>(owner, assetObject)); }
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); }
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)); }
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)); }
// 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!"); } }
public PropertySheet(AssetsFile file, AssetsObject owner, AssetsReader reader) { Parse(file, owner, reader); }
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)); }
public static ISmartPtr <T> PtrFrom <T>(this IObjectInfo <T> objectInfo, AssetsObject owner) where T : AssetsObject { return(new SmartPtr <T>(owner, objectInfo)); }
public DifficultyBeatmap(AssetsFile assetsFile, AssetsObject owner, AssetsReader reader) { Parse(assetsFile, owner, reader); }
public AlbumArtMetadata(AssetsFile file, AssetsObject o, AssetsReader reader) { assetsFile = file; owner = o; Parse(reader); }
public TexEnv(AssetsFile file, AssetsObject owner, AssetsReader reader) { Parse(file, owner, reader); }
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); } } }
public DecorationEntry(AssetsFile f, AssetsObject o, AssetsReader reader) { file = f; owner = o; Parse(reader); }