public static GameDataSettings CreateDefault(string gameDataPath)
        {
            if (gameDataPath == null)
            {
                throw new ArgumentNullException("gameDataPath");
            }

            var settings = new GameDataSettings();

            settings.Generator           = (int)CodeGenerator.CSharp;
            settings.AutoGeneration      = true;
            settings.LineEnding          = (int)LineEndings.Windows;
            settings.Indentation         = (int)Indentations.Tab;
            settings.AssetGenerationPath = Path.ChangeExtension(gameDataPath, "asset");
            settings.CodeGenerationPath  = Path.ChangeExtension(gameDataPath, "cs");
            settings.GameDataClassName   = Path.GetFileNameWithoutExtension(gameDataPath);
            settings.Namespace           = Path.GetDirectoryName(gameDataPath).Replace("\\", ".").Replace("/", ".");
            settings.DocumentClassName   = "Document";
            settings.Options             = (int)(CodeGenerationOptions.HideLocalizedStrings | CodeGenerationOptions.HideReferences | CodeGenerationOptions.SuppressDataContractAttributes);
            return(settings);
        }
Example #2
0
        private static void Update()
        {
            if (Settings.Current == null)
            {
                return;
            }

            if (LastWatchedGameDataTrackerVersion != GameDataTracker.Version)
            {
                var gameDataPaths = new HashSet <string>(GameDataTracker.All);
                foreach (var gameDataPath in gameDataPaths)
                {
                    if (Watchers.ContainsKey(gameDataPath) || File.Exists(gameDataPath) == false)
                    {
                        continue;
                    }

                    try
                    {
                        var fullPath      = Path.GetFullPath(gameDataPath);
                        var directoryName = Path.GetDirectoryName(fullPath);
                        var watcher       = new FileSystemWatcher(directoryName)
                        {
                            NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
                        };
                        watcher.Filter   = Path.GetFileName(fullPath);
                        watcher.Changed += GameDataChanged;
                        Watchers.Add(gameDataPath, watcher);

                        try { GameDataHashByPath[gameDataPath] = FileAndPathUtils.ComputeHash(gameDataPath); }
                        catch
                        {
                            // ignored
                        }
                        watcher.EnableRaisingEvents = true;
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("Failed to create FileSystemWatcher for GameData " + gameDataPath + ": " + e);
                    }
                }

                foreach (var gameDataPath in Watchers.Keys.ToArray())
                {
                    if (gameDataPaths.Contains(gameDataPath))
                    {
                        continue;
                    }

                    var watcher = Watchers[gameDataPath];
                    Watchers.Remove(gameDataPath);
                    try { watcher.Dispose(); }
                    catch (Exception e) { Debug.LogError("Failed to dispose FileSystemWatcher of GameData: " + e); }
                }
                LastWatchedGameDataTrackerVersion = GameDataTracker.Version;
            }

            var changedAssetsCopy = default(string[]);

            lock (ChangedAssetPaths)
            {
                if (ChangedAssetPaths.Count > 0)
                {
                    changedAssetsCopy = ChangedAssetPaths.ToArray();
                    ChangedAssetPaths.Clear();
                }
            }

            if (changedAssetsCopy != null)
            {
                foreach (var changedAsset in changedAssetsCopy)
                {
                    if (Settings.Current.Verbose)
                    {
                        Debug.Log("Changed Asset: " + changedAsset);
                    }

                    if (!File.Exists(changedAsset) || GameDataTracker.IsTracked(changedAsset) == false)
                    {
                        continue;
                    }
                    var gameDataSettings = GameDataSettings.Load(changedAsset);
                    if (!gameDataSettings.AutoGeneration)
                    {
                        continue;
                    }

                    var assetHash = default(string);
                    try
                    {
                        assetHash = FileAndPathUtils.ComputeHash(changedAsset);
                    }
                    catch (Exception e)
                    {
                        Debug.LogWarning("Failed to compute hash of " + changedAsset + ": " + e);
                        continue;
                    }

                    var oldAssetHash = default(string);
                    if (GameDataHashByPath.TryGetValue(changedAsset, out oldAssetHash) && assetHash == oldAssetHash)
                    {
                        continue;                         // not changed
                    }
                    if (EditorApplication.isUpdating)
                    {
                        continue;
                    }

                    if (Settings.Current.Verbose)
                    {
                        Debug.Log("Asset's " + changedAsset + " hash has changed from " + (oldAssetHash ?? "<none>") + " to " + assetHash);
                    }

                    GameDataHashByPath[changedAsset] = assetHash;
                    CoroutineScheduler.Schedule
                    (
                        Menu.GenerateCodeAndAssetsAsync(
                            path: changedAsset,
                            progressCallback: ProgressUtils.ReportToLog("Generation(Auto): ")),
                        "generation::" + changedAsset
                    );
                }
            }
        }
Example #3
0
        public static IEnumerable GenerateAssetsAsync(string[] paths, Action <string, float> progressCallback = null)
        {
            var total = paths.Length;

            for (var i = 0; i < paths.Length; i++)
            {
                var gameDataPath = paths[i];
                if (File.Exists(gameDataPath) == false)
                {
                    continue;
                }
                if (progressCallback != null)
                {
                    progressCallback(string.Format(Resources.UI_UNITYPLUGIN_PROGRESS_CURRENT_TARGET_IS, gameDataPath), (float)i / total);
                }


                var gameDataObj = AssetDatabase.LoadAssetAtPath(gameDataPath, typeof(UnityEngine.Object));
                var assetImport = AssetImporter.GetAtPath(gameDataPath);
                if (assetImport == null)
                {
                    continue;
                }

                var gameDataSettings    = GameDataSettings.Load(gameDataObj);
                var assetGenerationPath = FileAndPathUtils.MakeProjectRelative(gameDataSettings.AssetGenerationPath);
                if (string.IsNullOrEmpty(assetGenerationPath))
                {
                    continue;
                }

                // trying to touch gamedata file
                var touchGamedata = new Coroutine <FileStream>(TouchGameDataFile(gameDataPath));
                yield return(touchGamedata);

                if (touchGamedata.GetResult().Length == 0)
                {
                    continue;
                }

                using (var file = touchGamedata.GetResult())
                {
                    var gameDataBytes = new byte[file.Length];
                    int read, offset = 0;
                    while ((read = file.Read(gameDataBytes, offset, gameDataBytes.Length - offset)) > 0)
                    {
                        offset += read;
                    }

                    var gameDataType = Type.GetType(gameDataSettings.Namespace + "." + gameDataSettings.GameDataClassName + ", Assembly-CSharp", throwOnError: false) ??
                                       Type.GetType(gameDataSettings.Namespace + "." + gameDataSettings.GameDataClassName + ", Assembly-CSharp-firstpass", throwOnError: false) ??
                                       Type.GetType(gameDataSettings.Namespace + "." + gameDataSettings.GameDataClassName + ", Assembly-CSharp-Editor", throwOnError: false);
                    if (gameDataType == null)
                    {
                        Debug.LogError(Resources.UI_UNITYPLUGIN_GENERATE_ASSET_CANT_FIND_GAMEDATA_CLASS);
                        continue;
                    }

                    var assetDirectory = Path.GetDirectoryName(assetGenerationPath);
                    if (assetDirectory != null && !Directory.Exists(assetDirectory))
                    {
                        Directory.CreateDirectory(assetDirectory);
                    }

                    var gameDataAsset = ScriptableObject.CreateInstance(gameDataType);
                    gameDataAsset.SetFieldValue("dataBytes", gameDataBytes);
                    gameDataAsset.SetFieldValue("format", 0);
                    AssetDatabase.CreateAsset(gameDataAsset, assetGenerationPath);
                    AssetDatabase.SaveAssets();
                }
            }
            if (progressCallback != null)
            {
                progressCallback(Resources.UI_UNITYPLUGIN_GENERATE_REFRESHING_ASSETS, 0.99f);
            }
            AssetDatabase.Refresh(ImportAssetOptions.Default);
            if (progressCallback != null)
            {
                progressCallback(Resources.UI_UNITYPLUGIN_PROGRESS_DONE, 1);
            }
        }
Example #4
0
        public static IEnumerable GenerateCodeAndAssetsAsync(string path = null, Action <string, float> progressCallback = null)
        {
            var checkRequirements = CharonCli.CheckRequirementsAsync();

            yield return(checkRequirements);

            switch (checkRequirements.GetResult())
            {
            case RequirementsCheckResult.MissingRuntime: yield return(UpdateRuntimeWindow.ShowAsync()); break;

            case RequirementsCheckResult.WrongVersion:
            case RequirementsCheckResult.MissingExecutable: yield return(CharonCli.DownloadCharon(progressCallback)); break;

            case RequirementsCheckResult.Ok: break;

            default: throw new InvalidOperationException("Unknown Tools check result.");
            }

            var paths             = !string.IsNullOrEmpty(path) ? new[] { path } : GameDataTracker.All.ToArray();
            var total             = paths.Length;
            var forceReImportList = new List <string>();

            for (var i = 0; i < paths.Length; i++)
            {
                var gameDataPath = paths[i];
                if (File.Exists(gameDataPath) == false)
                {
                    continue;
                }
                if (progressCallback != null)
                {
                    progressCallback(string.Format(Resources.UI_UNITYPLUGIN_PROGRESS_CURRENT_TARGET_IS, gameDataPath), (float)i / total);
                }

                var gameDataObj = AssetDatabase.LoadAssetAtPath(gameDataPath, typeof(UnityEngine.Object));
                var assetImport = AssetImporter.GetAtPath(gameDataPath);
                if (assetImport == null)
                {
                    continue;
                }

                var gameDataSettings   = GameDataSettings.Load(gameDataObj);
                var codeGenerationPath = FileAndPathUtils.MakeProjectRelative(gameDataSettings.CodeGenerationPath);
                if (gameDataSettings.Generator == (int)GameDataSettings.CodeGenerator.None)
                {
                    continue;
                }

                var generationOptions = gameDataSettings.Options;
                if (Array.IndexOf(Settings.SupportedExtensions, Settings.EXTENSION_FORMULAS) == -1)                 // no expression library installed
                {
                    generationOptions |= (int)CodeGenerationOptions.DisableFormulas;
                }

                // trying to touch gamedata file
                var touchGamedata = new Coroutine <FileStream>(TouchGameDataFile(gameDataPath));
                yield return(touchGamedata);

                if (touchGamedata.GetResult().Length == 0)
                {
                    continue;
                }
                touchGamedata.GetResult().Dispose();                 // release touched file

                var generator = (GameDataSettings.CodeGenerator)gameDataSettings.Generator;
                switch (generator)
                {
                case GameDataSettings.CodeGenerator.CSharpCodeAndAsset:
                    if (!string.IsNullOrEmpty(gameDataSettings.AssetGenerationPath))
                    {
                        AssetGenerator.AddPath(gameDataPath);
                        generationOptions &= ~(int)(CodeGenerationOptions.DisableJsonSerialization |
                                                    CodeGenerationOptions.DisableBsonSerialization |
                                                    CodeGenerationOptions.DisableMessagePackSerialization |
                                                    CodeGenerationOptions.DisableXmlSerialization
                                                    );
                    }
                    goto generateCSharpCode;

                case GameDataSettings.CodeGenerator.CSharp:
generateCSharpCode:
                    if (Settings.Current.Verbose)
                    {
                        Debug.Log(string.Format("Generating C# code for '{0}'...", gameDataPath));
                    }
                    if (progressCallback != null)
                    {
                        progressCallback(string.Format(Resources.UI_UNITYPLUGIN_GENERATE_CODE_FOR, gameDataPath), (float)i / total);
                    }

                    var generateProcess = generator == GameDataSettings.CodeGenerator.CSharp
                                                        ? CharonCli.GenerateCSharpCodeAsync
                                          (
                        gameDataPath,
                        Path.GetFullPath(codeGenerationPath),
                        (CodeGenerationOptions)generationOptions,
                        gameDataSettings.DocumentClassName,
                        gameDataSettings.GameDataClassName,
                        gameDataSettings.Namespace
                                          )
                                                        : CharonCli.GenerateUnityCSharpCodeAsync
                                          (
                        gameDataPath,
                        Path.GetFullPath(codeGenerationPath),
                        (CodeGenerationOptions)generationOptions,
                        gameDataSettings.DocumentClassName,
                        gameDataSettings.GameDataClassName,
                        gameDataSettings.Namespace
                                          );
                    yield return(generateProcess);

                    if (Settings.Current.Verbose)
                    {
                        Debug.Log(string.Format("Generation complete, exit code: '{0}'", generateProcess.GetResult().ExitCode));
                    }
                    using (var generateResult = generateProcess.GetResult())
                    {
                        if (generateResult.ExitCode != 0)
                        {
                            Debug.LogWarning(string.Format(Resources.UI_UNITYPLUGIN_GENERATE_FAILED_DUE_ERRORS, gameDataPath, generateResult.GetErrorData()));
                        }
                        else
                        {
                            if (Settings.Current.Verbose)
                            {
                                Debug.Log(string.Format("Code generation for '{0}' is complete.", gameDataPath));
                            }

                            forceReImportList.Add(codeGenerationPath);

                            if (gameDataSettings.LineEnding != 0 ||
                                gameDataSettings.Indentation != 0)
                            {
                                if (progressCallback != null)
                                {
                                    progressCallback(string.Format(Resources.UI_UNITYPLUGIN_GENERATE_REFORMAT_CODE, gameDataPath), (float)i / total);
                                }

                                var code = new StringBuilder(File.ReadAllText(codeGenerationPath));
                                switch ((GameDataSettings.LineEndings)gameDataSettings.LineEnding)
                                {
                                case GameDataSettings.LineEndings.Windows:
                                    // already windows
                                    break;

                                case GameDataSettings.LineEndings.Unix:
                                    code.Replace("\r\n", "\n");
                                    break;

                                default:
                                    throw new InvalidOperationException(string.Format("Unknown LineEnding value '{0}' is set for {1}", gameDataSettings.LineEnding, gameDataPath));
                                }
                                switch ((GameDataSettings.Indentations)gameDataSettings.Indentation)
                                {
                                case GameDataSettings.Indentations.Tab:
                                    // already tabs
                                    break;

                                case GameDataSettings.Indentations.FourSpaces:
                                    code.Replace("\t", "    ");
                                    break;

                                case GameDataSettings.Indentations.TwoSpaces:
                                    code.Replace("\t", "  ");
                                    break;

                                default:
                                    throw new InvalidOperationException(string.Format("Unknown indentation value '{0}' is set for {1}", gameDataSettings.Indentation, gameDataPath));
                                }
                                File.WriteAllText(codeGenerationPath, code.ToString());
                            }
                        }
                    }
                    break;

                default:
                    Debug.LogError("Unknown code/asset generator type " + (GameDataSettings.CodeGenerator)gameDataSettings.Generator + ".");
                    break;
                }
            }
            if (progressCallback != null)
            {
                progressCallback(Resources.UI_UNITYPLUGIN_GENERATE_REFRESHING_ASSETS, 0.99f);
            }
            foreach (var forceReImportPath in forceReImportList)
            {
                AssetDatabase.ImportAsset(forceReImportPath, ImportAssetOptions.ForceUpdate);
            }
            if (progressCallback != null)
            {
                progressCallback(Resources.UI_UNITYPLUGIN_PROGRESS_DONE, 1);
            }
        }
        public static GameDataSettings CreateDefault(string gameDataPath)
        {
            if (gameDataPath == null) throw new ArgumentNullException("gameDataPath");

            var settings = new GameDataSettings();
            settings.Generator = (int)CodeGenerator.CSharp;
            settings.AutoGeneration = true;
            settings.LineEnding = (int) LineEndings.Windows;
            settings.Indentation = (int) Indentations.Tab;
            settings.AssetGenerationPath = Path.ChangeExtension(gameDataPath, "asset");
            settings.CodeGenerationPath = Path.ChangeExtension(gameDataPath, "cs");
            settings.GameDataClassName = Path.GetFileNameWithoutExtension(gameDataPath);
            settings.Namespace = Path.GetDirectoryName(gameDataPath).Replace("\\", ".").Replace("/", ".");
            settings.DocumentClassName = "Entry";
            settings.Options = (int)(CodeGenerationOptions.HideLocalizedStrings | CodeGenerationOptions.HideReferences | CodeGenerationOptions.SuppressDataContractAttributes);
            return settings;
        }