public static KontrolRegistry CreateKSP() { KontrolRegistry registry = KontrolRegistry.CreateCore(); registry.RegisterModule(KSPMathModule.Instance.module); KSPVessel.KSPVesselModule.DirectBindings(); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPConsole.KSPConsoleModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPGame.KSPGameModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPGame.KSPGameWarpModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPOrbit.KSPOrbitModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPControl.KSPControlModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPVessel.KSPVesselModule))); registry.RegisterModule(BindingGenerator.BindModule(typeof(KSPUI.KSPUIModule))); registry.RegisterModule( BindingGenerator.BindModule(typeof(KSPDebug.KSPDebugModule))); registry.RegisterModule(BindingGenerator.BindModule(typeof(KSPResource.KSPResourceModule))); registry.RegisterModule(BindingGenerator.BindModule(typeof(KSPAddons.KSPAddonsModule))); registry.RegisterModule(BindingGenerator.BindModule(typeof(Testing.KSPTesting))); return(registry); }
public override bool Execute() { if (String.IsNullOrWhiteSpace(OutputLanguage)) { OutputLanguage = DefaultOutputGenerator.Name; } BindingGenerator generator = GetBindingGenerator(OutputLanguage); if (generator == null) { Log.LogMessage($"Unknown binding output language '{OutputLanguage}', will use {DefaultOutputGenerator.Name} instead"); generator = DefaultOutputGenerator.Creator(); } if (generator == null) { // Should "never" happen Log.LogError($"Cannot find binding generator for language {OutputLanguage} or {DefaultOutputGenerator.Name}"); Complete(); return(false); } Log.LogDebugMessage($"Generating {generator.LanguageName} binding sources"); if (Generate(generator)) { Complete(); } else { base.Execute(); } return(!Log.HasLoggedErrors); }
void GenerateSourceForLayoutGroup (BindingGenerator generator, LayoutGroup group, Action <string> pathAdder) { List<ITaskItem> resourceItems = group?.Items; if (resourceItems == null || resourceItems.Count == 0) return; ITaskItem item = resourceItems.FirstOrDefault (); if (item == null) return; string collectionKey; if (!GetRequiredMetadata (item, CalculateLayoutCodeBehind.WidgetCollectionKeyMetadata, out collectionKey)) return; ICollection<LayoutWidget> widgets; if (!CalculateLayoutCodeBehind.LayoutWidgets.TryGetValue (collectionKey, out widgets) || widgets.Count == 0) { string inputPaths = String.Join ("; ", resourceItems.Select (i => i.ItemSpec)); LogCodedWarning ("XA4222", Properties.Resources.XA4222, inputPaths); return; } string outputFileName; if (!GetRequiredMetadata (item, CalculateLayoutCodeBehind.LayoutBindingFileNameMetadata, out outputFileName)) return; string fullClassName; if (!GetRequiredMetadata (item, CalculateLayoutCodeBehind.ClassNameMetadata, out fullClassName)) return; string outputFilePath = Path.Combine (MonoAndroidCodeBehindDir, outputFileName); string classNamespace; string className; int idx = fullClassName.LastIndexOf ('.'); if (idx < 0) { classNamespace = String.Empty; className = fullClassName; } else { bool fail = false; classNamespace = fullClassName.Substring (0, idx); if (String.IsNullOrEmpty (classNamespace)) { LogCodedError ("XA4223", Properties.Resources.XA4223, fullClassName); fail = true; } className = fullClassName.Substring (idx + 1); if (String.IsNullOrEmpty (className)) { LogCodedError ("XA4224", Properties.Resources.XA4224, fullClassName); fail = true; } if (fail) return; } if (!GenerateSource (generator, outputFilePath, widgets, classNamespace, className, group.Classes)) return; pathAdder (outputFilePath); }
bool GenerateSource (StreamWriter writer, BindingGenerator generator, ICollection <LayoutWidget> widgets, string classNamespace, string className, List<PartialClass> partialClasses) { bool havePartialClasses = partialClasses != null && partialClasses.Count > 0; string ns = AppNamespace == null ? String.Empty : $"{AppNamespace}."; if (havePartialClasses) { string fullBindingClassName = $"{classNamespace}.{className}"; WriteToPartialClasses (pc => pc.State = generator.BeginPartialClassFile (pc.Writer, fullBindingClassName, pc.Namespace, pc.Name, AndroidFragmentType)); } var state = generator.BeginBindingFile (writer, $"global::{ns}Resource.Layout.{className}", classNamespace, className, AndroidFragmentType); foreach (LayoutWidget widget in widgets) { DetermineWidgetType (widget, widget.Type == null); if (widget.Type == null) { widget.TypeFixups = null; // Not needed - we'll use decayed type string decayedType = null; switch (widget.WidgetType) { case LayoutWidgetType.View: decayedType = "global::Android.Views.View"; break; case LayoutWidgetType.Fragment: decayedType = $"global::{AndroidFragmentType}"; break; case LayoutWidgetType.Mixed: decayedType = "object"; break; default: throw new InvalidOperationException ($"Widget {widget.Name} is of unknown type {widget.WidgetType}"); } widget.Type = decayedType; LogCodedWarning ("XA4225", Properties.Resources.XA4225, widget.Name, className, decayedType); } if (String.IsNullOrWhiteSpace (widget.Type)) throw new InvalidOperationException ($"Widget {widget.Name} does not have a type"); generator.WriteBindingProperty (state, widget, ns); WriteToPartialClasses (pc => generator.WritePartialClassProperty (pc.State, widget)); } generator.EndBindingFile (state); WriteToPartialClasses (pc => generator.EndPartialClassFile (pc.State)); return true; void WriteToPartialClasses (Action<PartialClass> code) { if (!havePartialClasses) return; foreach (var pc in partialClasses) { if (pc == null) continue; code (pc); } } }
public static KontrolRegistry CreateCore() { KontrolRegistry registry = new KontrolRegistry(); registry.RegisterModule(BindingGenerator.BindModule(typeof(CoreLogging))); registry.RegisterModule(BindingGenerator.BindModule(typeof(CoreTesting))); registry.RegisterModule(BindingGenerator.BindModule(typeof(CoreBackground))); registry.RegisterModule(DirectBindingMath.Module); return(registry); }
bool GenerateSource (BindingGenerator generator, string outputFilePath, ICollection <LayoutWidget> widgets, string classNamespace, string className, List<PartialClass> partialClasses) { bool result = false; var tempFile = Path.GetTempFileName (); try { if (partialClasses != null && partialClasses.Count > 0) { foreach (var pc in partialClasses) { if (pc == null) continue; pc.Stream = File.Open (pc.OutputFilePath, FileMode.Create); pc.Writer = new StreamWriter (pc.Stream, Encoding.UTF8); } } using (var fs = File.Open (tempFile, FileMode.Create)) { using (var sw = new StreamWriter (fs, Encoding.UTF8)) { result = GenerateSource (sw, generator, widgets, classNamespace, className, partialClasses); } } if (result) Files.CopyIfChanged (tempFile, outputFilePath); } finally { if (File.Exists (tempFile)) File.Delete (tempFile); if (partialClasses != null && partialClasses.Count > 0) { foreach (var pc in partialClasses) { if (pc == null) continue; if (pc.Writer != null) { pc.Writer.Close (); pc.Writer.Dispose (); } if (pc.Stream == null) continue; pc.Stream.Close (); pc.Stream.Dispose (); } } } return result; }
public override bool Execute() { Log.LogDebugMessage("GenerateLayoutBindings Task"); Log.LogDebugMessage($" OutputLanguage: {OutputLanguage}"); Log.LogDebugMessage($" MonoAndroidCodeBehindDir: {MonoAndroidCodeBehindDir}"); Log.LogDebugMessage($" AppNamespace: {AppNamespace}"); Log.LogDebugTaskItems(" ResourceFiles:", ResourceFiles, true); Log.LogDebugTaskItems(" PartialClassFiles:", PartialClassFiles, true); if (String.IsNullOrWhiteSpace(OutputLanguage)) { OutputLanguage = DefaultOutputGenerator.Name; } BindingGenerator generator = GetBindingGenerator(OutputLanguage); if (generator == null) { Log.LogMessage($"Unknown binding output language '{OutputLanguage}', will use {DefaultOutputGenerator.Name} instead"); generator = DefaultOutputGenerator.Creator(); } if (generator == null) { // Should "never" happen Log.LogError($"Cannot find binding generator for language {OutputLanguage} or {DefaultOutputGenerator.Name}"); Complete(); return(false); } Log.LogDebugMessage($"Generating {generator.LanguageName} binding sources"); if (Generate(generator)) { Complete(); } else { base.Execute(); } return(!Log.HasLoggedErrors); }
KSPMathModule() { List <RealizedType> types = new List <RealizedType> { Vector2Binding.Vector2Type, Vector3Binding.Vector3Type, DirectionBinding.DirectionType, Matrix2x2Binding.Matrix2x2Type }; BindingGenerator.RegisterTypeMapping(typeof(Vector2d), Vector2Binding.Vector2Type); BindingGenerator.RegisterTypeMapping(typeof(Vector3d), Vector3Binding.Vector3Type); BindingGenerator.RegisterTypeMapping(typeof(Direction), DirectionBinding.DirectionType); BindingGenerator.RegisterTypeMapping(typeof(Matrix2x2), Matrix2x2Binding.Matrix2x2Type); List <CompiledKontrolConstant> constants = new List <CompiledKontrolConstant>(); List <CompiledKontrolFunction> functions = new List <CompiledKontrolFunction> { Direct.BindFunction(typeof(Vector2Binding), "Vec2", "Create a new 2-dimensional vector", typeof(double), typeof(double)), Direct.BindFunction(typeof(Vector3Binding), "Vec3", "Create a new 3-dimensional vector", typeof(double), typeof(double), typeof(double)), Direct.BindFunction(typeof(DirectionBinding), "Euler", "Create a Direction from euler angles in degree", typeof(double), typeof(double), typeof(double)), Direct.BindFunction(typeof(DirectionBinding), "AngleAxis", "Create a Direction from a given axis with rotation angle in degree", typeof(double), typeof(Vector3d)), Direct.BindFunction(typeof(DirectionBinding), "FromVectorToVector", "Create a Direction to rotate from one vector to another", typeof(Vector3d), typeof(Vector3d)), Direct.BindFunction(typeof(DirectionBinding), "LookDirUp", "Create a Direction from a fore-vector and an up-vector", typeof(Vector3d), typeof(Vector3d)), Direct.BindFunction(typeof(ExtraMath), "AngleDelta", "Calculate the difference between to angles in degree (-180 .. 180)", typeof(double), typeof(double)), Direct.BindFunction(typeof(Matrix2x2Binding), "Matrix2x2", "Create a new 2-dimensional matrix", typeof(double), typeof(double), typeof(double), typeof(double)) }; module = Direct.BindModule(ModuleName, "Collection of KSP/Unity related mathematical functions.", types, constants, functions); }
bool Generate(BindingGenerator generator) { var layoutGroups = new Dictionary <string, LayoutGroup> (StringComparer.Ordinal); string layoutGroupName; LayoutGroup group; foreach (ITaskItem item in ResourceFiles) { if (item == null) { continue; } if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutGroupMetadata, out layoutGroupName)) { return(true); // We need Complete() to be called by Execute above } if (!layoutGroups.TryGetValue(layoutGroupName, out group) || group == null) { group = new LayoutGroup { Items = new List <ITaskItem> () }; layoutGroups [layoutGroupName] = group; } group.Items.Add(item); } if (PartialClassFiles != null && PartialClassFiles.Length > 0) { foreach (ITaskItem item in PartialClassFiles) { if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutGroupMetadata, out layoutGroupName)) { return(true); } if (!layoutGroups.TryGetValue(layoutGroupName, out group) || group == null) { Log.LogError($"Partial class item without associated binding for layout group '{layoutGroupName}'"); return(true); } string partialClassName; if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.PartialCodeBehindClassNameMetadata, out partialClassName)) { return(true); } string outputFileName; if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutPartialClassFileNameMetadata, out outputFileName)) { return(true); } if (group.Classes == null) { group.Classes = new List <PartialClass> (); } if (group.ClassNames == null) { group.ClassNames = new HashSet <string> (); } if (group.ClassNames.Contains(partialClassName)) { continue; } string shortName; string namespaceName; int idx = partialClassName.LastIndexOf('.'); if (idx >= 0) { shortName = partialClassName.Substring(idx + 1); namespaceName = partialClassName.Substring(0, idx); } else { shortName = partialClassName; namespaceName = null; } group.Classes.Add(new PartialClass { Name = shortName, Namespace = namespaceName, OutputFilePath = Path.Combine(MonoAndroidCodeBehindDir, outputFileName) }); group.ClassNames.Add(partialClassName); } } IEnumerable <string> generatedFilePaths = null; bool needComplete = false; if (ResourceFiles.Length >= CalculateLayoutCodeBehind.ParallelGenerationThreshold) { // NOTE: Update the tests in $TOP_DIR/tests/CodeBehind/UnitTests/BuildTests.cs if this message // is changed! Log.LogDebugMessage($"Generating binding code in parallel (threshold of {CalculateLayoutCodeBehind.ParallelGenerationThreshold} layouts met)"); var fileSet = new ConcurrentBag <string> (); TPL.ParallelOptions options = new TPL.ParallelOptions { CancellationToken = Token, TaskScheduler = TPL.TaskScheduler.Default, }; TPL.Task.Factory.StartNew( () => TPL.Parallel.ForEach(layoutGroups, options, kvp => GenerateSourceForLayoutGroup(generator, kvp.Value, rpath => fileSet.Add(rpath))), Token, TPL.TaskCreationOptions.None, TPL.TaskScheduler.Default ).ContinueWith(t => Complete()); generatedFilePaths = fileSet; } else { var fileSet = new List <string> (); foreach (var kvp in layoutGroups) { GenerateSourceForLayoutGroup(generator, kvp.Value, rpath => fileSet.Add(rpath)); } generatedFilePaths = fileSet; needComplete = true; } GeneratedFiles = generatedFilePaths.Where(gfp => !String.IsNullOrEmpty(gfp)).Select(gfp => new TaskItem(gfp)).ToArray(); if (GeneratedFiles.Length == 0) { Log.LogWarning("No layout binding source files generated"); } Log.LogDebugTaskItems(" GeneratedFiles:", GeneratedFiles); return(needComplete); }
public async override System.Threading.Tasks.Task RunTaskAsync() { if (String.IsNullOrWhiteSpace(OutputLanguage)) { OutputLanguage = DefaultOutputGenerator.Name; } BindingGenerator generator = GetBindingGenerator(OutputLanguage); if (generator == null) { LogMessage($"Unknown binding output language '{OutputLanguage}', will use {DefaultOutputGenerator.Name} instead"); generator = DefaultOutputGenerator.Creator(); } if (generator == null) { // Should "never" happen LogCodedError("XA4219", Properties.Resources.XA4219, OutputLanguage, DefaultOutputGenerator.Name); return; } LogDebugMessage($"Generating {generator.LanguageName} binding sources"); var layoutGroups = new Dictionary <string, LayoutGroup> (StringComparer.Ordinal); string layoutGroupName; LayoutGroup group; foreach (ITaskItem item in ResourceFiles) { if (item == null) { continue; } if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutGroupMetadata, out layoutGroupName)) { return; } if (!layoutGroups.TryGetValue(layoutGroupName, out group) || group == null) { group = new LayoutGroup { Items = new List <ITaskItem> () }; layoutGroups [layoutGroupName] = group; } group.Items.Add(item); } if (PartialClassFiles != null && PartialClassFiles.Length > 0) { foreach (ITaskItem item in PartialClassFiles) { if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutGroupMetadata, out layoutGroupName)) { return; } if (!layoutGroups.TryGetValue(layoutGroupName, out group) || group == null) { LogCodedError("XA4220", Properties.Resources.XA4220, item.ItemSpec, layoutGroupName); return; } string partialClassName; if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.PartialCodeBehindClassNameMetadata, out partialClassName)) { return; } string outputFileName; if (!GetRequiredMetadata(item, CalculateLayoutCodeBehind.LayoutPartialClassFileNameMetadata, out outputFileName)) { return; } if (group.Classes == null) { group.Classes = new List <PartialClass> (); } if (group.ClassNames == null) { group.ClassNames = new HashSet <string> (); } if (group.ClassNames.Contains(partialClassName)) { continue; } string shortName; string namespaceName; int idx = partialClassName.LastIndexOf('.'); if (idx >= 0) { shortName = partialClassName.Substring(idx + 1); namespaceName = partialClassName.Substring(0, idx); } else { shortName = partialClassName; namespaceName = null; } group.Classes.Add(new PartialClass { Name = shortName, Namespace = namespaceName, OutputFilePath = Path.Combine(MonoAndroidCodeBehindDir, outputFileName) }); group.ClassNames.Add(partialClassName); } } IEnumerable <string> generatedFilePaths = null; if (ResourceFiles.Length >= CalculateLayoutCodeBehind.ParallelGenerationThreshold) { // NOTE: Update the tests in $TOP_DIR/tests/CodeBehind/UnitTests/BuildTests.cs if this message // is changed! LogDebugMessage($"Generating binding code in parallel (threshold of {CalculateLayoutCodeBehind.ParallelGenerationThreshold} layouts met)"); var fileSet = new ConcurrentBag <string> (); await this.WhenAll(layoutGroups, kvp => GenerateSourceForLayoutGroup(generator, kvp.Value, rpath => fileSet.Add(rpath))); generatedFilePaths = fileSet; } else { var fileSet = new List <string> (); foreach (var kvp in layoutGroups) { GenerateSourceForLayoutGroup(generator, kvp.Value, rpath => fileSet.Add(rpath)); } generatedFilePaths = fileSet; } GeneratedFiles = generatedFilePaths.Where(gfp => !String.IsNullOrEmpty(gfp)).Select(gfp => new TaskItem(gfp)).ToArray(); if (GeneratedFiles.Length == 0) { LogCodedWarning("XA4221", Properties.Resources.XA4221); } LogDebugTaskItems(" GeneratedFiles:", GeneratedFiles); }
public static void DirectBindings() { BindingGenerator.RegisterTypeMapping(typeof(FlightCtrlState), FlightCtrlStateBinding.FlightCtrlStateType); }