예제 #1
0
    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);
    }
예제 #2
0
 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;
         }
     }
 }
예제 #3
0
    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();
    }
예제 #4
0
    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);
    }
예제 #5
0
    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);
    }