public static string[] OnWillSaveAssets(string[] paths) { string sceneName = string.Empty; foreach (string path in paths) { if (path.Contains(".unity")) { sceneName = Path.GetFileNameWithoutExtension(path); } } if (sceneName.Length == 0) { return(paths); } GameObject[] allGameObjects = UnityEngine.Object.FindObjectsOfType <GameObject>(); foreach (GameObject go in allGameObjects) { EditDiffer editDiffer = go.GetComponent <EditDiffer>(); if (editDiffer == null) { continue; } Dictionary <Component, long> componentMaps = editDiffer.componentMaps; Component[] components = go.GetComponents <Component>(); List <long> newIds = new List <long>(); foreach (Component c in components) { if (componentMaps.ContainsKey(c)) { newIds.Add(componentMaps[c]); } else { newIds.Add(-1); } } editDiffer.componentIds = newIds; } SceneView sv = EditorWindow.GetWindow <SceneView>(); if (sv == null) { return(paths); } sv.ShowNotification(new GUIContent("Scene saved & components updated. Use HKEdit->Save Scene to save diff.")); return(paths); }
public static void AddEditDiffer() { foreach (GameObject obj in Selection.gameObjects) { if (obj != null) { EditDiffer differ = obj.GetComponent <EditDiffer>(); if (differ == null) { differ = obj.AddComponent <EditDiffer>(); } differ.pathId = differ.NextPathID(); differ.newAsset = true; } } }
public HKSave(string path, string diff) { LoadProgress("Load Scene", "Generating diff...", 0); am = new AssetsManager(); assetsFileInstance = am.LoadAssetsFile(diff, false); assetsFile = assetsFileInstance.file; assetsTable = assetsFileInstance.table; am.LoadClassPackage(Path.Combine(Application.dataPath, "cldb.dat")); //FileStream stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); //BinaryWriter writer = new BinaryWriter(stream); GameObject[] sceneObjs = GameObject.FindObjectsOfType <GameObject>(); List <GameObjectAdd> addList = new List <GameObjectAdd>(); List <GameObjectRemove> removeList = new List <GameObjectRemove>(); List <GameObjectChange> changeList = new List <GameObjectChange>(); List <GameObject> newGameObjects = new List <GameObject>(); List <GameObjectInfo> newGoInfos = new List <GameObjectInfo>(); int i = 0; foreach (GameObject obj in sceneObjs) { LoadProgress("Load Scene", "Generating diff...", ((float)i / sceneObjs.Length) * 100f); EditDiffer differ = obj.GetComponent <EditDiffer>(); if (differ != null) { if (!differ.newAsset) { List <ComponentChangeOrAdd> changes = new List <ComponentChangeOrAdd>(); List <ComponentRemove> removes = new List <ComponentRemove>(); ulong origPathId = differ.pathId; CompareTransform(obj, origPathId, changes); if (changes.Count > 0 || removes.Count > 0) { changeList.Add(new GameObjectChange() { pathId = (long)origPathId, changes = changes, removes = removes }); } } else { //bool parentIsNew = false; ulong parentPathId = ulong.MaxValue; if (obj.transform.parent == null) { parentPathId = 0; } else { EditDiffer ed = obj.transform.parent.gameObject.GetComponent <EditDiffer>(); if (ed != null) { parentPathId = ed.pathId; //if (ed.newAsset) //{ // parentIsNew = true; //} } else { Debug.LogWarning("editdiff missing from " + obj.name + "'s parent"); } } bool newAsset = differ.origPathId == 0; //when a new asset was created *not* by cloning addList.Add(new GameObjectAdd() { pathId = differ.pathId, parentId = parentPathId, goNew = newAsset }); newGameObjects.Add(obj); if (newAsset) { newGoInfos.Add(new GameObjectInfo(obj.name, differ.fileId, differ.origPathId, differ.pathId)); } } } i++; } LoadProgress("Create Diff Bundle", 0); CreateBundle(path, addList, removeList, changeList, newGameObjects, newGoInfos); EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("HKEdit", "Diff saved. Because of a Unity bug, please clear and reopen the map to continue working. All errors shown after save are normal.", "OK"); //stream.Close(); }
private void CreateBundle(string path, List <GameObjectAdd> addList, List <GameObjectRemove> removeList, List <GameObjectChange> changeList, List <GameObject> newGameObjects, List <GameObjectInfo> newGoInfos) { byte[] data = null; using (MemoryStream ms = new MemoryStream()) using (BinaryWriter w = new BinaryWriter(ms)) { DiffFile file = new DiffFile() { magic = 0x45574B48, version = 1, unityCompiledVersion = Application.unityVersion, adds = addList, removes = removeList, changes = changeList, infos = newGoInfos }; file.Write(w); data = ms.ToArray(); } //unity doesn't trust us to import files from //memory so we have to create a file to import it string dataPath = "Assets/ABTemp/HKWEDiffData.bytes"; File.WriteAllBytes(dataPath, data); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); List <string> buildAssets = new List <string>(); buildAssets.Add("Assets/ABTemp/HKWEDiffData.bytes"); foreach (GameObject go in newGameObjects) { EditDiffer ed = go.GetComponent <EditDiffer>(); string pName = "Assets/ABTemp/HKWEA_" + go.name.Substring(0, Math.Min(go.name.Length, 8)) + "_" + ed.fileId + "_" + ed.origPathId + "_" + ed.pathId + ".prefab"; //Debug.Log("creating asset " + pName); GameObject pgo = PrefabUtility.CreatePrefab(pName, go, ReplacePrefabOptions.Default); PrefabUtility.DisconnectPrefabInstance(go); UnityEngine.Object.DestroyImmediate(pgo.GetComponent <EditDiffer>(), true); EditorUtility.SetDirty(pgo); buildAssets.Add(pName); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); //Debug.Log("printing assets"); //foreach (string str in buildAssets) //{ // Debug.Log(str); //} AssetBundleBuild[] buildMap = new AssetBundleBuild[1]; buildMap[0].assetBundleName = Path.GetFileName(path); buildMap[0].assetNames = buildAssets.ToArray(); BuildPipeline.BuildAssetBundles(Path.GetDirectoryName(path), buildMap, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.StandaloneWindows64); DecompressBundle(path); File.Delete(path); File.Move(path + ".up", path); //File.Delete(dataPath); }
public GameObject RecurseGameObjects(AssetFileInfoEx info, bool topRoot, bool hideOnCreation = false) { AssetTypeValueField gameObject = am.GetATI(assetsFile, info).GetBaseField(); string name = gameObject.Get("m_Name").GetValue().AsString(); AssetTypeValueField m_Component = gameObject.Get("m_Component").Get("Array"); AssetsManager.AssetExternal transformComponent = am.GetExtAsset(assetsFileInstance, m_Component[0].Get("component")); AssetTypeValueField transform = transformComponent.instance.GetBaseField(); if (name == "TileMap Render Data" || name == "Template-TileMap (1) Render Data") //should be .EndsWith(" Render Data") { return(TilemapRenderData(transform, name)); } if (topRoot && transform.Get("m_Father").Get("m_PathID").GetValue().AsInt64() != 0) { return(null); } if (!topRoot && transform.Get("m_Father").Get("m_PathID").GetValue().AsInt64() == 0) { return(null); } GameObject gameObjectInstance = new GameObject(name); //if this object or parent object is mask bool isMask = hideOnCreation; int m_Tag = (ushort)gameObject.Get("m_Tag").GetValue().AsUInt(); if (m_Tag >= 20000) { int tagIndex = m_Tag - 20000; gameObjectInstance.tag = UnityEditorInternal.InternalEditorUtility.tags[tagIndex]; } else if (m_Tag != 0) { string[] tags = new[] { "Respawn", "Finished", "EditorOnly", "MainCamera", "Player", "GameController" }; gameObjectInstance.tag = tags[m_Tag - 1]; } gameObjectInstance.layer = (int)gameObject.Get("m_Layer").GetValue().AsUInt(); EditDiffer differ = gameObjectInstance.AddComponent <EditDiffer>(); differ.fileId = 0; differ.pathId = info.index; differ.origPathId = differ.pathId; Transform transformInstance = gameObjectInstance.transform; AssetTypeValueField m_LocalPosition = transform.Get("m_LocalPosition"); AssetTypeValueField m_LocalRotation = transform.Get("m_LocalRotation"); AssetTypeValueField m_LocalScale = transform.Get("m_LocalScale"); Vector3 localPosition = GetVector3(m_LocalPosition); Quaternion localRotation = GetQuaternion(m_LocalRotation); Vector3 localScale = GetVector3(m_LocalScale); for (uint i = 1; i < m_Component.GetValue().AsArray().size; i++) { //faster to check for only info but also keeps us from reading //particle systems which tend to update literally every minor update //if we end up needing more types we can use typetree2cldb on an editor file AssetsManager.AssetExternal component = am.GetExtAsset(assetsFileInstance, m_Component[i].Get("component"), true); if (component.info.curFileType == SPRITERENDERER) { component = am.GetExtAsset(assetsFileInstance, m_Component[i].Get("component")); AssetTypeValueField baseField = component.instance.GetBaseField(); AssetTypeValueField m_Sprite = baseField.Get("m_Sprite"); int fileId = m_Sprite.Get("m_FileID").GetValue().AsInt(); long pathId = m_Sprite.Get("m_PathID").GetValue().AsInt64(); AssetsManager.AssetExternal sprite = am.GetExtAsset(assetsFileInstance, m_Sprite); if (sprite.info == null) //spriterenderer with no sprite lol { continue; } AssetsFileInstance spriteInst; if (m_Sprite.Get("m_FileID").GetValue().AsInt() == 0) { spriteInst = assetsFileInstance; } else { spriteInst = assetsFileInstance.dependencies[m_Sprite.Get("m_FileID").GetValue().AsInt() - 1]; } Sprite spriteInstance = bundleAssets[assetMap[new AssetID(Path.GetFileName(spriteInst.path), pathId)]] as Sprite; SpriteRenderer sr = gameObjectInstance.AddComponent <SpriteRenderer>(); string[] sortingLayers = new[] { "Default", "Far BG 2", "Far BG 1", "Mid BG", "Immediate BG", "Actors", "Player", "Tiles", "MID Dressing", "Immediate FG", "Far FG", "Vignette", "Over", "HUD" }; sr.sortingLayerName = sortingLayers[baseField.Get("m_SortingLayer").GetValue().AsInt()]; sr.sortingOrder = baseField.Get("m_SortingOrder").GetValue().AsInt(); sr.sprite = spriteInstance; AssetTypeValueField m_Materials = baseField.Get("m_Materials").Get("Array"); if (m_Materials.GetValue().AsArray().size > 0) { AssetTypeValueField m_Material = m_Materials[0]; int matFileId = m_Material.Get("m_FileID").GetValue().AsInt(); long matPathId = m_Material.Get("m_PathID").GetValue().AsInt64(); AssetsFileInstance materialInst; if (m_Material.Get("m_FileID").GetValue().AsInt() == 0) { materialInst = assetsFileInstance; } else { materialInst = assetsFileInstance.dependencies[matFileId - 1]; } if (assetMap.ContainsKey(new AssetID(Path.GetFileName(materialInst.path), matPathId))) { Material mat = bundleAssets[assetMap[new AssetID(Path.GetFileName(materialInst.path), matPathId)]] as Material; if (mat.shader.name != "Sprites/Lit") //honestly this shader confuses me. it is the only shader { //with no code and only references the generic material sr.material = mat; } //else //{ // mat.shader = sr.sharedMaterial.shader; // sr.sharedMaterial = mat; //} if (mat.shader.name == "Hollow Knight/Grass-Default" || mat.shader.name == "Hollow Knight/Grass-Diffuse") { sr.sharedMaterial.SetFloat("_SwayAmount", 0f); //stops grass animation } } //else //{ // Debug.Log("failed to find " + Path.GetFileName(materialInst.path) + "/" + matPathId + ".dat"); //} } } if (component.info.curFileType == MONOBEHAVIOUR) { component = am.GetExtAsset(assetsFileInstance, m_Component[i].Get("component")); AssetTypeValueField baseField = component.instance.GetBaseField(); int monoTypeId = assetsFileInstance.file.typeTree.pTypes_Unity5[component.info.curFileTypeOrIndex].scriptIndex; if (!monoBehaviourIds.ContainsKey(monoTypeId)) { //map out the monobehaviour script indexes to their name for fast lookup AssetTypeValueField m_Script = baseField.Get("m_Script"); AssetsManager.AssetExternal script = am.GetExtAsset(assetsFileInstance, m_Script); string scriptName = script.instance.GetBaseField().Get("m_Name").GetValue().AsString(); monoBehaviourIds[monoTypeId] = scriptName; } if (monoBehaviourIds[monoTypeId] == "tk2dSprite") { string managedPath = Path.Combine(Path.GetDirectoryName(assetsFileInstance.path), "Managed"); baseField = am.GetMonoBaseFieldCached(assetsFileInstance, component.info, managedPath); AssetTypeValueField collection = baseField.Get("collection"); int _spriteId = baseField.Get("_spriteId").GetValue().AsInt(); int fileId = collection.Get("m_FileID").GetValue().AsInt(); //long pathId = collection.Get("m_PathID").GetValue().AsInt64(); AssetsManager.AssetExternal sprite = am.GetExtAsset(assetsFileInstance, collection); if (sprite.info == null) { continue; } AssetsFileInstance spriteFileInstance = assetsFileInstance.dependencies[fileId - 1]; AssetTypeValueField spriteBaseField = am.GetMonoBaseFieldCached(spriteFileInstance, sprite.info, managedPath); //this is a bad hack but it works for some reason so here it is //the reason the pivot is being set and not the actual position //is so we don't modify the values on the transform component Texture2D image = spriteLoader.LoadTK2dSpriteNative(am, spriteBaseField, spriteFileInstance, _spriteId); AssetTypeValueField boundsData = spriteBaseField.Get("spriteDefinitions")[(uint)_spriteId].Get("boundsData")[0]; float xOff = boundsData.Get("x").GetValue().AsFloat() * 100; float yOff = boundsData.Get("y").GetValue().AsFloat() * 100; Vector2 offset = new Vector2((image.width / 2f - xOff) / image.width, (image.height / 2f - yOff) / image.height); Sprite spriteInstance = Sprite.Create(image, new Rect(0, 0, image.width, image.height), offset, 100f); SpriteRenderer sr = gameObjectInstance.AddComponent <SpriteRenderer>(); sr.sortingLayerName = "Default"; sr.sortingOrder = 0; sr.sprite = spriteInstance; } else if (monoBehaviourIds[monoTypeId] == "PlayMakerFSM") { //string managedPath = Path.Combine(Path.GetDirectoryName(assetsFileInstance.path), "Managed"); //baseField = am.GetMonoBaseFieldCached(assetsFileInstance, component.info, managedPath); string fsmName = ReadFSMName(component.info, assetsFileInstance.file.reader);//baseField.Get("fsm").Get("name").GetValue().AsString(); if (fsmName == "remasker" || fsmName == "unmasker" || fsmName == "remasker_inverse" || fsmName == "Remove") { isMask = true; } } } } transformInstance.localScale = localScale; transformInstance.localPosition = localPosition; transformInstance.localRotation = localRotation; Renderer ren = gameObjectInstance.GetComponent <Renderer>(); if (isMask && ren != null) { ren.enabled = false; } AssetTypeValueField childrenArray = transform.Get("m_Children").Get("Array"); uint childrenCount = childrenArray.GetValue().AsArray().size; for (uint i = 0; i < childrenCount; i++) { AssetTypeValueField childTf = am.GetExtAsset(assetsFileInstance, childrenArray[i]).instance.GetBaseField(); AssetFileInfoEx childGo = am.GetExtAsset(assetsFileInstance, childTf.Get("m_GameObject")).info; RecurseGameObjects(childGo, false, isMask).transform.SetParent(transformInstance, false); } return(gameObjectInstance); }