// ------------------------------------------------------------------------- /// Deletes the generate code files. /// /// @param iStorage The VS storage to convert to code. /// public void DeleteGeneratedFilesFor(iCS_IStorage iStorage) { var fileName = NameUtility.ToTypeName(iStorage.TypeName); var folder = CodeGenerationUtility.GetCodeGenerationFolder(iStorage); CSharpFileUtils.DeleteCSharpFile(folder, fileName); }
string GenerateHandleMessageMethodCode(string senderTypeName, IEnumerable <MethodInfo> methods) { var handleMessageCode = methods.Select(method => { var parameters = method.GetParameters(); var readMessageDataCode = parameters.Select(param => { var postfix = TypeUtility.GetPacketReaderReadMethodPostfix(param.ParameterType); return($"var {param.Name} = reader.Read{postfix}();"); }) .Join($"{Environment.NewLine} "); var paramNamesCode = CodeGenerationUtility.GenerateParameterNameCode(parameters); var code = $@"void Handle{method.Name}({senderTypeName} sender, PacketReader reader) {{ {readMessageDataCode} Handle_{method.Name}(sender{paramNamesCode}); on{method.Name}?.Invoke(sender{paramNamesCode}); }}"; return(code); }) .Join($"{Environment.NewLine}{Environment.NewLine}"); return(handleMessageCode); }
string GenerateCompositedCode(Type messageGroupType, string senderTypeName, IEnumerable <MethodInfo> methods) { var usingCode = TypeUtility.GetUnfriendlyParameterTypeUsingCode(methods, messageGroupType.Namespace, new[] { "Neti.Packets" }); var messageHandlingCode = GenerateMessageHandlingCode(senderTypeName, methods); return(CodeGenerationUtility.BuildMessageGroupCode(usingCode, messageGroupType.Namespace, messageGroupType.Name.TrimStart('I'), "abstract class MessageHandling", messageHandlingCode)); }
string GenerateAbstractMessageMethodCode(string senderTypeName, IEnumerable <MethodInfo> methods) { var code = methods.Select(method => { var paramTypeNamesCode = CodeGenerationUtility.GenerateParameterTypeNameCode(method.GetParameters()); return($@"protected abstract void Handle_{method.Name}({senderTypeName} sender{paramTypeNamesCode});"); }) .JoinWithLine(); return(code); }
string GenerateRpcCode(Type messageGroupType, IEnumerable <MethodInfo> rpcMethods, string senderTypeName) { var usingCode = TypeUtility.GetUnfriendlyParameterTypeUsingCode(rpcMethods, messageGroupType.Namespace); var rpcCode = rpcMethods.Select(method => GenerateRpcMethodCode(method, senderTypeName)) .Join($"{Environment.NewLine}{Environment.NewLine}") .InsertAfterEachLine(CodeConstants.InternalClassCodeIndent); return(CodeGenerationUtility.BuildMessageGroupCode(usingCode, messageGroupType.Namespace, messageGroupType.Name.TrimStart('I'), "static class Rpc", rpcCode)); }
public StateCodeGenerator(ILanguageAbstraction generatorsFactory, string namespaceName, string stateMachineName, string stateName, bool useStateBase, bool isInternal, IGraph graph) : base(generatorsFactory, namespaceName, stateMachineName) { CodeGenerationUtility.CheckValidPartialIdentifierArgument(stateName, nameof(stateName)); if (graph == null) { throw new ArgumentNullException(nameof(graph)); } this.stateName = stateName; this.graph = graph; this.useStateBase = useStateBase; this.isInternal = isInternal; }
string GenerateRpcMethodCode(MethodInfo method, string senderTypeName) { var parameters = method.GetParameters(); var parameterCode = CodeGenerationUtility.GenerateParameterTypeNameCode(parameters); var writeCode = parameters.Select(param => $"{Environment.NewLine} writer.Write({param.Name});").Join(); return ($@"public static void {method.Name}({senderTypeName} sender{parameterCode}) {{ using (var writer = sender.CreatePacketWriter()) {{ writer.Write(MessageId.{method.Name});{writeCode} }} }}"); }
public CodeGeneratorBase(ILanguageAbstraction languageAbstraction, string namespaceName, string stateMachineName) { if (languageAbstraction == null) { throw new ArgumentNullException(nameof(languageAbstraction)); } if (string.IsNullOrWhiteSpace(namespaceName) == false) { this.namespaceName = namespaceName; } CodeGenerationUtility.CheckValidIdentifierArgument(stateMachineName, nameof(stateMachineName)); Language = languageAbstraction; this.stateMachineName = stateMachineName; }
string GenerateHandlerDefinitionCode(string senderTypeName, IEnumerable <MethodInfo> methods) { var delegateCode = methods.Select(method => { var paramCode = CodeGenerationUtility.GenerateParameterTypeNameCode(method.GetParameters()); return($"public delegate void {method.Name}Handler({senderTypeName} sender{paramCode});"); }) .JoinWithLine(); var declaringCode = methods.Select(method => $"{method.Name}Handler on{method.Name};").JoinWithLine(); var eventCode = methods.Select(method => $"public event {method.Name}Handler On{method.Name} {{ add {{ on{method.Name} += value; }} remove {{ on{method.Name} -= value; }} }}").JoinWithLine(); var code = $@"{delegateCode} {declaringCode} {eventCode}"; return(code); }
FileDefinition myCodeRoot = null; ///< Code global definition. // ------------------------------------------------------------------------- /// Builds global scope code definition. /// /// @param iStorage The VS storage to convert to code. /// @return The complete visual script code. /// public void GenerateCodeFor(iCS_IStorage iStorage) { // -- Nothing to do if no or empty Visual Script. -- if (iStorage == null || iStorage.EditorObjects.Count == 0) { return; } // -- Build code global scope. -- var typeName = NameUtility.ToTypeName(iStorage.TypeName); var namespaceName = CodeGenerationUtility.GetNamespace(iStorage); var baseType = CodeGenerationUtility.GetBaseType(iStorage); myCodeRoot = new FileDefinition(typeName, namespaceName, baseType, iStorage); // -- Generate code. -- var result = myCodeRoot.GenerateCode(0); // -- Write final code to file. -- var fileName = typeName; var folder = CodeGenerationUtility.GetCodeGenerationFolder(iStorage); CSharpFileUtils.WriteCSharpFile(folder, fileName, result.ToString()); }
public static void Init() { if (_init) { return; } LogUtils.Verbose("Context.Init"); _init = true; foreach (var source in Sources) { _assets[source.GetAssetPath()] = source; } foreach (var storage in Storages) { _assets[storage.GetAssetPath()] = storage; } var assemblies = Assemblies; if (assemblies.ProxyAssembly == null) { return; } try { var roots = Roots; var wellLocatedRoots = new List <RootDefinition>(); foreach (var r in roots.All) { if (!assemblies.IsAssemblyValidForRoot(r.Assembly)) { LogUtils.Warning($"Config root {r.Root.FullName} is defined in assembly {r.Assembly.FullName}. This is not supported - please put it into separate assembly with AssemblyDefinition or manually."); continue; } wellLocatedRoots.Add(r); } var validGroups = new List <string>(); var validAttributes = new List <AssetDeclarationAttributeBase>(); var attributes = wellLocatedRoots.SelectMany(r => r.Attributes) .ToList(); var groups = attributes.Select(a => a.Group) .ToList(); foreach (var attribute in attributes) { if (groups.Count(g => g == attribute.Group) > 1) { var duplicateRoots = wellLocatedRoots.Where(r => r.Contains(attribute.Group)); var log = new StringBuilder(); log.AppendFormat("Group name \"{0}\" is declared multiple times. This is not supported.", attribute.Group) .AppendLine(); log.AppendLine("Declarations found in these types:"); foreach (var root in duplicateRoots) { log.AppendFormat("{0} ({1})", root.Root.Name, root.Root.AssemblyQualifiedName) .AppendLine(); } log.AppendLine("These group will be ignored until duplication is fixed."); LogUtils.Error(log); continue; } if (!CodeGenerationUtility.IsValidGroupName(attribute.Group)) { LogUtils.Error($"Group {attribute.Group} name is not valid! Group will be ignored."); continue; } validAttributes.Add(attribute); validGroups.Add(attribute.Group); } _groups = validGroups; Attributes = validAttributes; } catch (Exception e) { LogUtils.Verbose(e); } try { var postprocessorType = typeof(IPostProcessAssets); var postprocessorTypes = assemblies.All .SelectMany(a => a.GetTypes()) .Where(t => !t.IsAbstract && !t.IsInterface) .Where(t => postprocessorType.IsAssignableFrom(t)) .ToList(); PostProcessors = new List <IPostProcessAssets>(); var ordered = new Dictionary <int, List <IPostProcessAssets> >(); var orders = new Dictionary <IPostProcessAssets, PostProcessOrderAttribute>(); var defaultOrder = new PostProcessOrderAttribute(); Func <int, List <IPostProcessAssets> > getGroup = i => { List <IPostProcessAssets> g; if (ordered.TryGetValue(i, out g)) { return(g); } g = new List <IPostProcessAssets>(); ordered[i] = g; return(g); }; Func <IPostProcessAssets, PostProcessOrderAttribute> getOrder = a => { PostProcessOrderAttribute o; if (!orders.TryGetValue(a, out o) || o == null) { o = defaultOrder; } return(o); }; foreach (var type in postprocessorTypes) { try { var instance = Activator.CreateInstance(type, type.IsNotPublic) as IPostProcessAssets; PostProcessors.Add(instance); var order = type.GetSingle <PostProcessOrderAttribute>() ?? defaultOrder; orders[instance] = order; getGroup(order.Group).Add(instance); } catch (Exception e) { LogUtils.Verbose(e); } } foreach (var p in ordered) { p.Value.Sort((a1, a2) => getOrder(a1).Order.CompareTo(getOrder(a1).Order)); } OrderedPostProcessors = new IPostProcessAssets[ordered.Count][]; var index = 0; foreach (var groupIndex in ordered.Keys.OrderBy(k => k)) { var g = ordered[groupIndex]; if (g == null || g.Count == 0) { continue; } OrderedPostProcessors[index] = g.ToArray(); index++; } } catch (Exception e) { LogUtils.Verbose(e); } }
private static void BuildAssembly(YamlyProjectAssemblies assemblies, bool debug = false) { var outputAssetsPath = CodeGenerationUtility.GetProxyAssemblyOutputPath(assemblies.ProxyAssembly); if (Settings.VerboseLogs) { Debug.Log($"Build proxy assembly at path {outputAssetsPath}"); } var assetPathsToReimport = new List <string>(2); var outputSystemPath = Application.dataPath.Replace("Assets", outputAssetsPath); var assemblyBuilder = new ProxyAssemblyBuilder { TargetAssemblies = assemblies.TargetAssemblies, IgnoreAssemblies = assemblies.IgnoreAssemblies, OutputAssembly = outputSystemPath, TreatWarningsAsErrors = true, IncludeDebugInformation = debug }.Build(); if (assemblyBuilder.CompilerResults.Errors.Count != 0) { Debug.LogError($"Proxy assembly builder have {assemblyBuilder.CompilerResults.Errors.Count} errors!"); foreach (var error in assemblyBuilder.CompilerResults.Errors) { Debug.LogError(error); } return; } if (Settings.VerboseLogs) { Debug.Log("Proxy assembly builder have no errors."); } assetPathsToReimport.Add(outputAssetsPath); if (assemblies.ProxyAssembly != null) { outputSystemPath = CodeGenerationUtility.GetUtilityAssemblySystemPath(); outputAssetsPath = outputSystemPath.ToAssetsPath(); if (Settings.VerboseLogs) { Debug.Log($"Build utility assembly at path {outputAssetsPath}"); } var groups = _roots.SelectMany(r => r.Attributes).Select(a => a.Group).Distinct().ToArray(); var utilityBuilder = new UtilityAssemblyBuilder(groups) { OutputAssembly = outputSystemPath, TargetNamespace = "Yamly.UnityEditor.Utility" }.Build(); if (utilityBuilder.CompilerResults.Errors.Count != 0) { Debug.LogError($"Utility assembly builder have {utilityBuilder.CompilerResults.Errors.Count} errors!"); foreach (var error in utilityBuilder.CompilerResults.Errors) { Debug.LogError(error); } return; } if (Settings.VerboseLogs) { Debug.Log("Utility assembly builder have no errors."); } assetPathsToReimport.Add(utilityBuilder.OutputAssembly.ToAssetsPath()); } else { if (Settings.VerboseLogs) { Debug.Log("Delay building utility assembly until proxy assembly imported."); } YamlyEditorPrefs.IsAssemblyBuildPending = true; } try { AssetDatabase.StartAssetEditing(); foreach (var assetPath in assetPathsToReimport) { AssetDatabase.ImportAsset(assetPath); } } catch (Exception e) { Debug.LogException(e); } AssetDatabase.StopAssetEditing(); AssetDatabase.Refresh(ImportAssetOptions.Default); }
// Можем импортнуть файл кода или библиотеку, в котором есть конфиг. Надо пересобрать библиотеку. // Можем удалить файл кода или библиотеку, в котором есть конфиг. Надо пересобрать библиотеку. // Можем переместить импортнуть ассет, который попадает в источник. Надо пересобрать все машруты с этим ассетом. // Можем удалить ассет, который попадает в источник. Надо пересобрать все машруты с этим ассетом. // Можем переместить ассет, который попадает в источник. Надо проверить, что исходный и конечный источник тот же. Если тот же - игнорировать. Если изменился - надо пересобрать все маршруты. // Можем импортнуть новый источник. Надо пересобрать все его маршруты. // Можем удалить источник. Надо пересобрать все маршруты, которые он затрагивал. // Можем переместить источни. Надо пересобрать его маршруты. // Можем импортнуть новое хранилище. Надо пересобрать все его маршруты. // Можем переместить файл кода или библиотеку, в котором есть конфиг. Ничего не делать. // Можем удалить хранилище. Ничего не делать. // Можем переместить хранилище. Ничего не делать. private static void ProcessAssets(YamlyPostprocessAssetsContext ctx) { var assemblies = GetAssemblies(); InitRoots(assemblies); if (!_rebuildAssemblyAfterReloadScriptsPending) { if (assemblies.ProxyAssembly == null || assemblies.IsProxyAssemblyInvalid || string.IsNullOrEmpty(assemblies.ProxyAssembly.Location)) { if (_roots.Any()) { BuildAssembly(assemblies); } return; } } var codeAssets = AssetDatabase.FindAssets($"t:{nameof(TextAsset)}") .Select(AssetDatabase.GUIDToAssetPath) .Where(p => p.EndsWith(".cs")) .Select(AssetDatabase.LoadAssetAtPath <TextAsset>) .ToArray(); var codeFilePaths = _roots.SelectMany(r => GetCodeFiles(r, codeAssets)) .Distinct() .ToList(); var exludedAssemblies = new List <string> { CodeGenerationUtility.GetUtilityAssemblySystemPath().ToAssetsPath() }; var proxyAssemblyLocation = assemblies.ProxyAssembly?.Location.ToAssetsPath(); if (!string.IsNullOrEmpty(proxyAssemblyLocation)) { exludedAssemblies.Add(proxyAssemblyLocation); } var rebuildAssembly = false; foreach (var assetPath in ctx.ChangedAndDeletedAssets) { if (assetPath.EndsWith(".cs")) { if (codeFilePaths.Contains(assetPath)) { rebuildAssembly = true; } } if (assetPath.EndsWith(".dll")) { if (!exludedAssemblies.Contains(assetPath)) { rebuildAssembly = true; } } } if (rebuildAssembly || _rebuildAssemblyAfterReloadScriptsPending) { if (!_rebuildAssemblyAfterReloadScriptsPending) { YamlyEditorPrefs.IsAssemblyBuildPending = true; } YamlyEditorPrefs.AssetImportContext = new YamlyPostprocessAssetsContext { ImportedAssets = ctx.ImportedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), DeletedAssets = ctx.DeletedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), MovedAssets = ctx.MovedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), MovedFromAssetPaths = ctx.MovedFromAssetPaths.Where(p => !IsCodeFilePath(p)).ToArray() }; return; } if (_roots.Count == 0) { return; } var sourceDefinitions = AssetUtility.LoadAll <FolderSource>() .Cast <SourceBase>() .Concat(AssetUtility.LoadAll <SingleSource>()) .ToList(); if (sourceDefinitions.Count == 0) { return; } var groups = _roots.SelectMany(r => r.Attributes) .Select(a => a.Group) .Distinct() .ToArray(); var storageDefinitions = AssetUtility.LoadAll <Storage>().ToList(); for (var i = 0; i < storageDefinitions.Count; i++) { var storage = storageDefinitions[i]; storage.ExcludedGroups.RemoveAll(g => !groups.Contains(g)); foreach (var s in storage.Storages) { if (s == null || !storage.Includes(s.Group)) { Object.DestroyImmediate(s, true); EditorUtility.SetDirty(storage); } } storage.Storages.RemoveAll(s => s == null); var assets = AssetDatabase.LoadAllAssetsAtPath(storage.GetAssetPath()); var haveNullAssets = false; foreach (var asset in assets) { if (asset == storage) { continue; } if (storage.Storages.Contains(asset)) { continue; } if (asset == null) { haveNullAssets = true; } Object.DestroyImmediate(asset, true); } if (haveNullAssets) { var assetPath = storage.GetAssetPath(); var storages = storage.Storages.ToArray(); var storageName = storage.name; storage = Object.Instantiate(storage); storage.name = storageName; storage.Storages.Clear(); foreach (var storageBase in storages) { var instance = Object.Instantiate(storageBase); instance.name = storageBase.name; storage.Storages.Add(instance); } if (Settings.VerboseLogs) { Debug.Log($"Storage at path ${assetPath} contains missing storage instances and will be overwritten.", storage); } AssetDatabase.DeleteAsset(assetPath); AssetDatabase.StartAssetEditing(); { AssetDatabase.CreateAsset(storage, assetPath); foreach (var storageBase in storage.Storages) { AssetDatabase.AddObjectToAsset(storageBase, assetPath); } } AssetDatabase.StopAssetEditing(); AssetDatabase.ImportAsset(assetPath); storageDefinitions[i] = storage; } } var routes = new List <DataRoute>(); foreach (var d in _roots) { var codePaths = GetCodeFiles(d, codeAssets); routes.AddRange(d.Attributes.Select(a => CreateRoute(d, a, sourceDefinitions, storageDefinitions, codePaths))); } var routesToRebuild = new List <DataRoute>(); foreach (var assetPath in ctx.All) { foreach (var route in routes) { if (routesToRebuild.Contains(route)) { continue; } if (route.ContainsAsset(assetPath) || route.ContainsSource(assetPath) || route.ContainsStorage(assetPath)) { routesToRebuild.Add(route); } } } var context = new YamlyProjectContext { ProxyAssembly = assemblies.ProxyAssembly, Storages = storageDefinitions, Sources = sourceDefinitions, Roots = _roots }; foreach (var route in routesToRebuild) { Rebuild(route, context); } AssetDatabase.Refresh(); }
private static void ProcessAssets(YamlyPostprocessAssetsContext ctx) { Context.Init(); Context.ClearAssetsCache(); var assemblies = Context.Assemblies; var roots = Context.Roots; if (!_rebuildAssemblyAfterReloadScriptsPending) { if (assemblies.ProxyAssembly == null || assemblies.IsProxyAssemblyInvalid || string.IsNullOrEmpty(assemblies.ProxyAssembly.Location)) { if (roots.Any()) { BuildAssembly(assemblies); } return; } } var exludedAssemblies = new List <string> { CodeGenerationUtility.GetUtilityAssemblySystemPath().ToAssetsPath() }; var proxyAssemblyLocation = assemblies.ProxyAssembly?.Location.ToAssetsPath(); if (!string.IsNullOrEmpty(proxyAssemblyLocation)) { exludedAssemblies.Add(proxyAssemblyLocation); } var rebuildAssembly = false; foreach (var assetPath in ctx.ChangedAndDeletedAssets) { if (roots.Any(r => IsCodeFile(r, assetPath))) { rebuildAssembly = true; break; } } if (rebuildAssembly || _rebuildAssemblyAfterReloadScriptsPending) { if (!_rebuildAssemblyAfterReloadScriptsPending) { YamlyEditorPrefs.IsAssemblyBuildPending = true; } YamlyEditorPrefs.AssetImportContext = new YamlyPostprocessAssetsContext { ImportedAssets = ctx.ImportedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), DeletedAssets = ctx.DeletedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), MovedAssets = ctx.MovedAssets.Where(p => !IsCodeFilePath(p)).ToArray(), MovedFromAssetPaths = ctx.MovedFromAssetPaths.Where(p => !IsCodeFilePath(p)).ToArray() }; return; } if (roots.Count == 0) { LogUtils.Verbose("Stop processing: no roots found."); return; } var sources = Context.Sources; if (sources.Count == 0) { LogUtils.Verbose("Stop processing: no sources found."); return; } var groups = Context.Groups; var storages = Context.Storages; CleanupStorages(storages, groups); var routes = new List <DataRoute>(); foreach (var d in roots) { routes.AddRange(d.ValidAttributes.Select(a => CreateRoute(d, a, sources, storages))); } var routesToRebuild = new List <DataRoute>(); foreach (var assetPath in ctx.All) { foreach (var route in routes) { if (routesToRebuild.Contains(route)) { continue; } if (route.ContainsAsset(assetPath) || route.ContainsSource(assetPath) || route.ContainsStorage(assetPath)) { routesToRebuild.Add(route); } } } foreach (var route in routesToRebuild) { Rebuild(route); } foreach (var route in routesToRebuild) { PostProcess(route); } AssetDatabase.Refresh(); }