public void saveToFile(string filename, bool showGui, bool saveResourceFiles, Logger logger = null) { try{ if (showGui) { ExportUtility.showProgressBar( string.Format("Saving file {0}", System.IO.Path.GetFileName(filename)), "Writing json data", 0, 1); } string targetDir; string projectPath; checkResourceFolder(filename, out targetDir, out projectPath, true); string baseName = System.IO.Path.GetFileNameWithoutExtension(filename); string filesDir = System.IO.Path.Combine(targetDir, baseName); // + "_data"); if (showGui) { confirmAndEraseExistingDirectory(filesDir); } System.IO.Directory.CreateDirectory(filesDir); externResourceList = resourceMapper.saveResourceToFolder(filesDir, showGui, scenes, logger, saveResourceFiles); Utility.saveStringToFile(filename, toJsonString()); if (!saveResourceFiles) { return; } saveAssetFiles(externResourceList.externalAssets, filename, showGui, logger); } finally{ //Otherwise progress bar can get stuck, blocking entirety of editor if (showGui) { ExportUtility.hideProgressBar(); } } }
/* * Essentually the whole unity scene is a resource graph. * There are two resource types - "leaf" resources and "node" resources. * Leafs are only referenced by something, while nodes can reference leafs and other nodes via Ids.... * * Well, the problem is we don't know how deep the rabbit hole goes, and one referenced resource can pull in other referenced * resources and so on. Given that a project can be huge, loading everything into memory at once might be unwise. * * As a result exporter will have to loop through the resources multiple times to acomodate for resoruces that were * possibly introduced. Henc the ugly "saveResourcesToPath" call with many many parameters. * * Originally I tried to avoid that by forcing specific order of initialziation which would eradicat possibility of * missing resources, but then I got prefabs and animator contorllers... */ public JsonExternResourceList saveResourceToFolder(string baseDir, bool showGui, List <JsonScene> scenes, Logger logger, bool collectExternAssets) { Logger.makeValid(ref logger); var result = new JsonExternResourceList(collectExternAssets); //int lastSceneCount = 0; ///var sceneWatcher = scenes.createWatcher.... Nope! var sceneWatcher = scenes.createWatcher(); var terrainWatcher = terrains.createWatcher(); var meshWatcher = meshRegistry.createWatcher(); //meshes.createWatcher(); var materialsWatcher = materials.createWatcher(); var texWatcher = textures.createWatcher(); var cubemapWatcher = cubemaps.createWatcher(); var audioClipWatcher = audioClips.createWatcher(); var skeletonWatcher = skelRegistry.createWatcher(); var prefabWatcher = prefabs.createWatcher(); var animControllerWatcher = animatorControllers.createWatcher(); var animClipWatcher = animationClips.createWatcher(); //processObjects = false; /* processObjects |= */ /* * saveResourcesToPath(result.scenes, ref lastSceneCount, baseDir, scenes, * (objData, i) => objData, (obj) => obj.name, "scene", showGui);//Hmm. This one is not a resource mapper object...*/ bool processObjects = true; while (processObjects) { /* * Here we go, finally. * * This loop is meant to accomodate extensive and interconnected resource graph used by unity. * * Basically, during consturction of one or more JsonObjects, those objects may pull reference to something else that must * ALSO be converted to some sort of json object. * * At this point a new resource reference (ResId) is created, and it has to be exported. * Except... it is possible that the new resource has been pulled at the moment where this particular resource type * has already been saved. * * Hence there's a resource watcher class which will monitor relevant resource registry for new IDs being added. * As long as new ids are being generated, resource loop will continue, once they're no longer added, this is it. * * No more work to do, and the loop terminates. */ processObjects = false; processObjects |= saveResourcesToPath(result.scenes, baseDir, sceneWatcher, (objData) => objData, (obj) => obj.name, "scene", showGui); processObjects |= saveResourcesToPath(result.terrains, baseDir, terrainWatcher, (objData) => new JsonTerrainData(objData, this), (obj) => obj.name, "terrainData", showGui, (asset) => result.registerAsset(asset) ); processObjects |= saveResourcesToPath(result.meshes, baseDir, meshWatcher, (meshKey, idx, id) => makeJsonMesh(meshKey, id), (obj) => obj.name, "mesh", showGui); processObjects |= saveResourcesToPath(result.materials, baseDir, materialsWatcher, (objData) => { var mat = new JsonMaterial(objData, this); if (!mat.supportedShader) { logger.logWarningFormat("Possibly unsupported shader \"{0}\" in material \"{1}\"(#{2}, path \"{3}\"). " + "Correct information transfer is not guaranteed.", mat.shader, mat.name, mat.id, mat.path); } return(mat); }, (obj) => obj.name, "material", showGui); processObjects |= saveResourcesToPath(result.textures, baseDir, texWatcher, (objData) => new JsonTexture(objData, this), (obj) => obj.name, "texture", showGui, (asset) => result.registerAsset(asset) ); processObjects |= saveResourcesToPath(result.cubemaps, baseDir, cubemapWatcher, (objData) => new JsonCubemap(objData, this), (obj) => obj.name, "cubemap", showGui, (asset) => result.registerAsset(asset) ); processObjects |= saveResourcesToPath(result.audioClips, baseDir, audioClipWatcher, (objData) => new JsonAudioClip(objData, this), (obj) => obj.name, "audioClip", showGui); //skeletons are already sorted by id processObjects |= saveResourcesToPath(result.skeletons, baseDir, skeletonWatcher, (objData) => objData, (obj) => obj.name, "skeleton", showGui); processObjects |= saveResourcesToPath( result.prefabs, baseDir, prefabWatcher, (objData) => new JsonPrefabData(objData, this), (obj) => obj.name, "prefab", showGui); processObjects |= saveResourcesToPath(result.animatorControllers, baseDir, animControllerWatcher, (objData, idx, id) => new JsonAnimatorController(objData.controller, objData.animator, id, this), (obj) => obj.name, "animatorController", showGui); processObjects |= saveResourcesToPath(result.animationClips, baseDir, animClipWatcher, (objData, idx, id) => new JsonAnimationClip(objData.animClip, objData.animator, id, this), (obj) => obj.name, "animationClip", showGui); } result.resources = new List <string>(resources); result.resources.Sort(); return(result); }