diff --git a/.editorconfig b/.editorconfig index 1592dd774..229463f20 100644 --- a/.editorconfig +++ b/.editorconfig @@ -29,9 +29,9 @@ dotnet_style_predefined_type_for_locals_parameters_members=true:hint dotnet_style_predefined_type_for_member_access=true:hint # Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators=always_for_clarity:silent -dotnet_style_parentheses_in_relational_binary_operators=always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators=always_for_clarity:silent +dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:silent +dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:silent dotnet_style_parentheses_in_other_operators=never_if_unnecessary:silent # Modifier preferences diff --git a/.gitignore b/.gitignore index 8675d7757..dc7f17eeb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ obj /Ships /GameData/FerramAerospaceResearch/Custom*.cfg /GameData/FerramAerospaceResearch/FARForceDataUpdate.cfg +GameData/FerramAerospaceResearch/Plugins/FARLogger_* *.suo *.DotSettings *.user @@ -20,9 +21,6 @@ releases .pytest_cache *.pyc -// unignore Debug build DLLs -!bin/[Dd]ebug/[Ff]erram*.dll - // Rider .idea @@ -35,6 +33,7 @@ Unity/FerramAerospaceResearch*/[Oo]bj/ Unity/FerramAerospaceResearch*/[Bb]uild/ Unity/FerramAerospaceResearch*/[Bb]uilds/ Unity/FerramAerospaceResearch*/[Ll]ogs/ +Unity/[Bb]uild/ # Never ignore Asset meta data !Unity/FerramAerospaceResearch*/[Aa]ssets/**/*.meta @@ -91,10 +90,14 @@ Unity/FerramAerospaceResearch*/[Aa]ssets/PartTools Unity/FerramAerospaceResearch*/[Aa]ssets/SquadCore # External editor scripts -Unity/FerramAerospaceResearch*/[Aa]ssets/Editor/**/* +Unity/FerramAerospaceResearch*/[Aa]ssets/Editor/* !Unity/FerramAerospaceResearch*/[Aa]ssets/Editor/Bundle.cs !Unity/FerramAerospaceResearch*/[Aa]ssets/Editor/Assets.cs +!Unity/FerramAerospaceResearch*/[Aa]ssets/Editor/Tests/ # Rider generated files in Unity directory Unity/FerramAerospaceResearch*/[Aa]ssets/Plugins/Editor* Unity/FerramAerospaceResearch*/.idea + +# burst compiler +Logs/* diff --git a/Directory.Build.props b/Directory.Build.props index 8f72270cc..14ad2bc20 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,8 +1,8 @@ - - C:\Zaidimai\KSP 1.9.0\ - + + C:\Zaidimai\KSP 1.10\ + cd "$(SolutionDir)"" python -m buildtools postbuild -f "$(SolutionDir)config.json" -c "$(Configuration)" -t - + diff --git a/FerramAerospaceResearch.Base/Config/DebugConfig.cs b/FerramAerospaceResearch.Base/Config/DebugConfig.cs new file mode 100644 index 000000000..94b232855 --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/DebugConfig.cs @@ -0,0 +1,19 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Config +{ + [ConfigNode("Debug")] + public class DebugConfig + { + [ConfigValue("logLevel")] + public static LogLevel Level + { + get { return FARLogger.Level; } + set { FARLogger.Level = value; } + } + + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global - reflection + [ConfigValue("dumpOnLoad")] + public bool DumpOnLoad { get; set; } = false; + } +} diff --git a/FerramAerospaceResearch.Base/Config/FlightLogConfig.cs b/FerramAerospaceResearch.Base/Config/FlightLogConfig.cs new file mode 100644 index 000000000..64b32fd37 --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/FlightLogConfig.cs @@ -0,0 +1,29 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Config +{ + [ConfigNode("FlightLog")] + public class FlightLogConfig + { + private string directory = PathUtil.Combine(PathUtil.PParentDir, "Logs", PathUtil.ModDirectoryName); + + [ConfigValue("directory")] + public string Directory + { + get { return directory; } + set { directory = PathUtil.Combine(PathUtil.PParentDir, value); } + } + + [ConfigValue("nameFormat")] + public StringFormatter NameFormat { get; } = new StringFormatter("<<>>_<<>>.csv"); + + [ConfigValue("datetimeFormat")] + public string DatetimeFormat { get; set; } = "yyyy_MM_dd_HH_mm_ss"; + + [ConfigValue("period")] + public Observable LogPeriod { get; } = new Observable(50); + + [ConfigValue("flushPeriod")] + public Observable FlushPeriod { get; } = new Observable(10); + } +} diff --git a/FerramAerospaceResearch.Base/Config/GUIColors.cs b/FerramAerospaceResearch.Base/Config/GUIColors.cs new file mode 100644 index 000000000..26141a23e --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/GUIColors.cs @@ -0,0 +1,44 @@ +using FerramAerospaceResearch.Reflection; +using UnityEngine; + +namespace FerramAerospaceResearch.Config +{ + [ConfigNode("GuiColors")] + public class GUIColors + { + private readonly Color[] colors = {Color.cyan, Color.red, Color.yellow, Color.green}; + + [ConfigValue] + public Color ClColor + { + get { return colors[0]; } + set { colors[0] = value; } + } + + [ConfigValue] + public Color CdColor + { + get { return colors[1]; } + set { colors[1] = value; } + } + + [ConfigValue] + public Color CmColor + { + get { return colors[2]; } + set { colors[2] = value; } + } + + [ConfigValue("L_DColor")] + public Color LdColor + { + get { return colors[3]; } + set { colors[3] = value; } + } + + public Color GetColor(int index) + { + return colors[index]; + } + } +} diff --git a/FerramAerospaceResearch.Base/Config/ResourceNode.cs b/FerramAerospaceResearch.Base/Config/ResourceNode.cs new file mode 100644 index 000000000..5faf0f95c --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/ResourceNode.cs @@ -0,0 +1,52 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Config +{ + public class ResourceNode + { + public ResourceNode(string url = "", string loader = "default") + { + Url.Value = url; + Loader.Value = loader; + } + + [ConfigValue("url")] + public Observable Url { get; } = new Observable(); + + [ConfigValue("loader")] + public Observable Loader { get; } = new Observable("default"); + + public static implicit operator string(ResourceNode node) + { + return node.Url; + } + } + + [ConfigNode("TEXTURE")] + public class TextureNode : ResourceNode + { + public TextureNode(string url = "", string loader = "default") : base(url, loader) + { + } + } + + [ConfigNode("SHADER")] + public class ShaderNode : ResourceNode + { + public ShaderNode(string url = "", string loader = "default") : base(url, loader) + { + } + } + + [ConfigNode("SHADER")] + public class DebugVoxelNode : ShaderNode + { + public DebugVoxelNode(string url = "", string loader = "default") : base(url, loader) + { + } + + [ConfigValue("_Cutoff")] + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global - reflection + public float Cutoff { get; set; } = 0.45f; + } +} diff --git a/FerramAerospaceResearch.Base/Config/ShaderConfig.cs b/FerramAerospaceResearch.Base/Config/ShaderConfig.cs new file mode 100644 index 000000000..cbaec9681 --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/ShaderConfig.cs @@ -0,0 +1,32 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Config +{ + [ConfigNode("Shaders")] + public class ShaderConfig + { + [ConfigValue("bundleLinux")] + public Observable BundleLinux { get; } = + new Observable("FerramAerospaceResearch/Assets/farshaders_linux.far", + PathUtil.CombineDelegate(PathUtil.ParentDir)); + + [ConfigValue("bundleWindows")] + public Observable BundleWindows { get; } = + new Observable("FerramAerospaceResearch/Assets/farshaders_windows.far", + PathUtil.CombineDelegate(PathUtil.ParentDir)); + + [ConfigValue("bundleMac")] + public Observable BundleMac { get; } = + new Observable("FerramAerospaceResearch/Assets/farshaders_macosx.far", + PathUtil.CombineDelegate(PathUtil.ParentDir)); + + [ConfigValue("debugVoxel")] + public DebugVoxelNode DebugVoxel { get; } = new DebugVoxelNode("FerramAerospaceResearch/Debug Voxel Mesh"); + + [ConfigValue("lineRenderer")] + public ShaderNode LineRenderer { get; } = new ShaderNode("Hidden/Internal-Colored"); + + [ConfigValue("debugVoxelFallback")] + public ShaderNode DebugVoxelFallback { get; } = new ShaderNode("Sprites/Default"); + } +} diff --git a/FerramAerospaceResearch.Base/Config/TextureConfig.cs b/FerramAerospaceResearch.Base/Config/TextureConfig.cs new file mode 100644 index 000000000..b7b60e862 --- /dev/null +++ b/FerramAerospaceResearch.Base/Config/TextureConfig.cs @@ -0,0 +1,20 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Config +{ + [ConfigNode("Textures")] + public class TextureConfig + { + [ConfigValue("iconButtonBlizzy")] + public TextureNode IconButtonBlizzy { get; } = + new TextureNode("FerramAerospaceResearch/Textures/icon_button_blizzy"); + + [ConfigValue("iconButtonStock")] + public TextureNode IconButtonStock { get; } = + new TextureNode("FerramAerospaceResearch/Textures/icon_button_stock"); + + [ConfigValue("spriteDebugVoxel")] + public TextureNode SpriteDebugVoxel { get; } = + new TextureNode("FerramAerospaceResearch/Textures/sprite_debug_voxel"); + } +} diff --git a/FerramAerospaceResearch.Base/FARAddonAttribute.cs b/FerramAerospaceResearch.Base/FARAddonAttribute.cs new file mode 100644 index 000000000..c67683270 --- /dev/null +++ b/FerramAerospaceResearch.Base/FARAddonAttribute.cs @@ -0,0 +1,24 @@ +using System; + +namespace FerramAerospaceResearch +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class FARAddonAttribute : Attribute + { + /// + /// Whether this addon should have its reference kept after instantiation + /// + public readonly bool Persistant; + + /// + /// Priority of instantiation, higher values get instantiated earlier + /// + public readonly int Priority; + + public FARAddonAttribute(int priority = 0, bool persistant = false) + { + Priority = priority; + Persistant = persistant; + } + } +} diff --git a/FerramAerospaceResearch.Base/FARAddonLoader.cs b/FerramAerospaceResearch.Base/FARAddonLoader.cs new file mode 100644 index 000000000..e38d8df22 --- /dev/null +++ b/FerramAerospaceResearch.Base/FARAddonLoader.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using FerramAerospaceResearch.Interfaces; +using FerramAerospaceResearch.Reflection; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + /// + /// Class to handle instantiation of marked addons, specific implementation needs some entry point to start this + /// + public class FARAddonLoader : MonoSingleton + { + /// + /// Dictionary of all instantiated (addons, reloadable) objects + /// + private readonly Dictionary instantiatedTypes = new Dictionary(); + + /// + /// Dictionary of found addons and their corresponding types + /// + public List> AddonTypes { get; } = new List>(); + + /// + /// Dictionary of types found that implement interface/> + /// + public List ReloadableTypes { get; } = new List(); + + /// + /// List of persistant addons + /// + public List AddonObjects { get; } = new List(); + + /// + /// List of all instantiated objects that implement interface/> + /// + public List ReloadableObjects { get; } = new List(); + + /// + /// Start the loading + /// + /// callback function after loading has successfully finished + public void Load(Action callback = null) + { + StartCoroutine(DoLoad(callback)); + } + + private void InitTask() + { + Assembly[] assemblies = ReflectionUtils.LoadedAssemblies; + var types = new List(ReflectionUtils.GetTypes(assemblies)); + + AddonTypes.AddRange(ReflectionUtils.FindAttribute(types)); + ReloadableTypes.AddRange(ReflectionUtils.FindTypes(types, true)); + + if (AddonTypes.Count == 0) + FARLogger.Trace("No FARAddon types found"); + if (ReloadableTypes.Count == 0) + FARLogger.Trace("No IReloadable types found"); + + // sort by descending priority order + AddonTypes.Sort((x, y) => y.First.Priority.CompareTo(x.First.Priority)); + + // output some debug information + FARLogger.TraceFormat(TraceMessage()); + } + + private string TraceMessage() + { + var sb = new StringBuilder("FARAddonLoader found addons: \n"); + foreach (Pair pair in AddonTypes) + // ReSharper disable once UseFormatSpecifierInInterpolation + sb.AppendLine($" {pair.First.Priority.ToString("D4")}: {pair.Second.Name}"); + sb.AppendLine("IReloadable types found:"); + foreach (Type type in ReloadableTypes) + sb.AppendLine($" {type.Name}"); + return sb.ToString(); + } + + private IEnumerator DoLoad(Action callback) + { + // offload to another thread and wait for it to complete + Task task = Task.Factory.StartNew(InitTask); + yield return new WaitUntil(() => task.IsCompleted); + + if (task.Exception != null) + { + FARLogger.Exception(task.Exception, "Exception while loading FAR addons:"); + yield break; + } + + // do instantiation in the main thread in case any of the types are Unity objects + FARLogger.Debug("Instantiating FAR addons"); + foreach (Pair pair in AddonTypes) + { + yield return SetupType(pair.Second, pair.First.Persistant, AddonObjects); + yield return null; + } + + FARLogger.Debug("Instantiating Reloadable types"); + foreach (Type type in ReloadableTypes) + { + yield return SetupType(type, true, ReloadableObjects); + yield return null; + } + + callback?.Invoke(); + } + + private IEnumerator SetupType(Type type, bool persistant, List objects) where T : class + { + // skip invalid types + if (type.IsAbstract || type.IsInterface) + yield break; + + FARLogger.DebugFormat("FARAddonLoader: instantiating {0}", type); + + bool contains = true; + + // if not yet instantiated, try to find singleton instance or create a new one + if (!instantiatedTypes.TryGetValue(type, out object o)) + { + o = ReflectionUtils.FindInstance(type); + if (o == null) + o = typeof(Component).IsBaseOf(type) + ? ReflectionUtils.Create(type, transform, persistant) + : Activator.CreateInstance(type, true); + else + FARLogger.DebugFormat("Found an instance of {0}", type); + contains = false; + } + + // enable behaviour so that their Awake methods run + if (o is Behaviour behaviour && behaviour != null) + behaviour.enabled = true; + + // wait for the addon to finish its setup + if (o is IWaitForAddon waitForAddon) + yield return new WaitUntil(() => waitForAddon.Completed); + + // store persistant objects + if (persistant) + { + objects.Add(o as T); + if (!contains) + instantiatedTypes.Add(type, o); + } + else if (o is Component component) + { + Destroy(component); + } + + FARLogger.DebugFormat("FARAddonLoader: {0} finished", type); + } + + public IEnumerator Reload() + { + FARLogger.Debug("Reloading IReloadable objects"); + + // sort again in case priorities have changed + ReloadableObjects.Sort((x, y) => y.Priority.CompareTo(x.Priority)); + + foreach (IReloadable reloadable in ReloadableObjects) + { + reloadable.Completed = false; + reloadable.DoReload(); + yield return new WaitUntil(() => reloadable.Completed); + } + } + } +} diff --git a/FerramAerospaceResearch.Base/FARConfig.cs b/FerramAerospaceResearch.Base/FARConfig.cs new file mode 100644 index 000000000..4ae0d0084 --- /dev/null +++ b/FerramAerospaceResearch.Base/FARConfig.cs @@ -0,0 +1,30 @@ +using FerramAerospaceResearch.Config; +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch +{ + [ConfigNode("FARConfig", true)] + public static class FARConfig + { + /// + /// Whether the config is being loaded + /// + private static volatile bool isLoading; + + public static readonly ShaderConfig Shaders = new ShaderConfig(); + + public static readonly TextureConfig Textures = new TextureConfig(); + + public static readonly FlightLogConfig FlightLog = new FlightLogConfig(); + + public static readonly GUIColors GUIColors = new GUIColors(); + + public static readonly DebugConfig Debug = new DebugConfig(); + + public static bool IsLoading + { + get { return isLoading; } + set { isLoading = value; } + } + } +} diff --git a/FerramAerospaceResearch.Base/FerramAerospaceResearch.Base.csproj b/FerramAerospaceResearch.Base/FerramAerospaceResearch.Base.csproj new file mode 100644 index 000000000..1c16bb9b9 --- /dev/null +++ b/FerramAerospaceResearch.Base/FerramAerospaceResearch.Base.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {8E4E9138-A949-4DED-A08C-4CE3442887B4} + Library + Properties + FerramAerospaceResearch + FerramAerospaceResearch.Base + v4.8 + 512 + 8 + + + AnyCPU + true + portable + false + $(SolutionDir)bin\Debug\ + DEBUG;TRACE;ASSERT;LOG_TRACE + prompt + 4 + true + + + AnyCPU + portable + true + $(SolutionDir)bin\Release\ + TRACE;INFO + prompt + 4 + true + + + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.AnimationModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.AssetBundleModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.CoreModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.IMGUIModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.InputLegacyModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.PhysicsModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.TextRenderingModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.UI.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.UnityWebRequestModule.dll + + + $(KSP_DIR_BUILD)KSP_x64_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(PostBuildCommand) "$(TargetPath)" + + + + diff --git a/FerramAerospaceResearch.Base/Geometry/DebugVoxel.cs b/FerramAerospaceResearch.Base/Geometry/DebugVoxel.cs new file mode 100644 index 000000000..7a53522d5 --- /dev/null +++ b/FerramAerospaceResearch.Base/Geometry/DebugVoxel.cs @@ -0,0 +1,122 @@ +using FerramAerospaceResearch.Resources; +using UnityEngine; + +namespace FerramAerospaceResearch.Geometry +{ + public struct DebugVoxel + { + public float Scale; + public Vector3 Position; + public Color Color; + + public DebugVoxel(Vector3 pos, float elementScale, Color color) + { + Scale = elementScale; + Position = pos; + Color = color; + } + + public Vector3 BottomLeft + { + get { return new Vector3(Position.x - Scale, Position.y - Scale, Position.z); } + } + + public Vector3 BottomRight + { + get { return new Vector3(Position.x + Scale, Position.y - Scale, Position.z); } + } + + public Vector3 TopRight + { + get { return new Vector3(Position.x + Scale, Position.y + Scale, Position.z); } + } + + public Vector3 TopLeft + { + get { return new Vector3(Position.x - Scale, Position.y + Scale, Position.z); } + } + + public struct Builder : IDebugVoxelMeshBuilder + { + /// + public int VerticesPerVoxel + { + get { return 4; } + } + + /// + public bool HasColor + { + get { return true; } + } + + /// + public int UVChannels + { + get { return 1; } + } + + /// + public MeshTopology Topology + { + // using triangles since they have better performance than quads + get { return MeshTopology.Triangles; } + } + + /// + public int PrimitivesPerVoxel + { + get { return 2; } + } + + /// + public Material MeshMaterial + { + get + { + Material mat = FARAssets.Instance.Shaders.DebugVoxel; + + if (mat == null || mat.shader == null) + mat = FARAssets.Instance.Shaders.DebugVoxelFallback; + else if (mat.HasProperty(ShaderPropertyIds.Cutoff)) + mat.SetFloat(ShaderPropertyIds.Cutoff, FARConfig.Shaders.DebugVoxel.Cutoff); + + mat.mainTexture = FARAssets.Instance.Textures.DebugVoxel; + + return mat; + } + } + + /// + public void Build(DebugVoxel voxel, MeshBuildData buildData, int offset) + { + int counter = buildData.Vertices.Count - offset; + + buildData.Vertices.Add(voxel.BottomLeft); + buildData.Colors.Add(voxel.Color); + buildData.Uvs[0].Add(new Vector2(0, 0)); + + buildData.Vertices.Add(voxel.TopLeft); + buildData.Colors.Add(voxel.Color); + buildData.Uvs[0].Add(new Vector2(0, 1)); + + buildData.Vertices.Add(voxel.TopRight); + buildData.Colors.Add(voxel.Color); + buildData.Uvs[0].Add(new Vector2(1, 1)); + + buildData.Vertices.Add(voxel.BottomRight); + buildData.Colors.Add(voxel.Color); + buildData.Uvs[0].Add(new Vector2(1, 0)); + + // left-handed triangles + buildData.Indices.Add(counter); + buildData.Indices.Add(counter + 1); + buildData.Indices.Add(counter + 2); + + buildData.Indices.Add(counter); + buildData.Indices.Add(counter + 2); + buildData.Indices.Add(counter + 3); + } + } + } +} diff --git a/FerramAerospaceResearch/FARPartGeometry/DebugVoxelMesh.cs b/FerramAerospaceResearch.Base/Geometry/DebugVoxelMesh.cs similarity index 72% rename from FerramAerospaceResearch/FARPartGeometry/DebugVoxelMesh.cs rename to FerramAerospaceResearch.Base/Geometry/DebugVoxelMesh.cs index b4b1a6bc9..ebf1c4afb 100644 --- a/FerramAerospaceResearch/FARPartGeometry/DebugVoxelMesh.cs +++ b/FerramAerospaceResearch.Base/Geometry/DebugVoxelMesh.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using FerramAerospaceResearch.FARUtils; using UnityEngine; using UnityEngine.Rendering; -namespace FerramAerospaceResearch.FARPartGeometry +namespace FerramAerospaceResearch.Geometry { [RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))] public class DebugVoxelMesh : MonoBehaviour @@ -13,7 +12,8 @@ public class DebugVoxelMesh : MonoBehaviour // limit of vertices in each mesh imposed by Unity if using 16 bit indices public const int MaxVerticesPerSubmesh = 65535; - private int currentSubmesh; + public static bool Use32BitIndices = false; + private int currentOffset; private int indicesPerSubmesh; private int verticesPerSubmesh; @@ -22,14 +22,18 @@ public class DebugVoxelMesh : MonoBehaviour public Mesh Mesh { get; private set; } public MeshRenderer Renderer { get; private set; } public MeshFilter Filter { get; private set; } - public List Vertices { get; } = new List(); - public List> Uvs { get; } = new List>(); - public List> Indices { get; } = new List>(); + public MeshBuildData Data { get; } = new MeshBuildData(); + + private bool uInt32BitIndices; - public bool Use32BitIndices + private bool UInt32BitIndices { - get { return Mesh.indexFormat == IndexFormat.UInt32; } - set { Mesh.indexFormat = value ? IndexFormat.UInt32 : IndexFormat.UInt16; } + get { return uInt32BitIndices; } + set + { + uInt32BitIndices = value; + Mesh.indexFormat = value ? IndexFormat.UInt32 : IndexFormat.UInt16; + } } public static DebugVoxelMesh Create(Transform parent = null) @@ -48,7 +52,7 @@ private void Awake() { FARLogger.Debug("Setting up debug voxel mesh"); Mesh = new Mesh(); - Use32BitIndices = FARSettingsScenarioModule.VoxelSettings.use32BitIndices; + UInt32BitIndices = Use32BitIndices; Filter = GetComponent(); Renderer = GetComponent(); @@ -90,13 +94,14 @@ public void Clear(bool clearMesh = true) { if (clearMesh) Mesh.Clear(); - Use32BitIndices = FARSettingsScenarioModule.VoxelSettings.use32BitIndices; - Uvs.Clear(); - Vertices.Clear(); - foreach (List sublist in Indices) + UInt32BitIndices = Use32BitIndices; + Data.Uvs.Clear(); + Data.Vertices.Clear(); + Data.Colors.Clear(); + foreach (List sublist in Data.SubmeshIndices) sublist.Clear(); - currentSubmesh = 0; + Data.CurrentSubmesh = 0; nextVertexCount = 0; currentOffset = 0; } @@ -112,7 +117,7 @@ public void Reserve(Builder builder, int count) where Builder : IDebugV { int meshes; int voxelsPerSubmesh; - if (Use32BitIndices) + if (uInt32BitIndices) { voxelsPerSubmesh = count; meshes = 1; @@ -129,67 +134,71 @@ public void Reserve(Builder builder, int count) where Builder : IDebugV verticesPerVoxel = builder.VerticesPerVoxel; int nVertices = count * builder.VerticesPerVoxel; - if (Vertices.Capacity < nVertices) - Vertices.Capacity = nVertices; + if (Data.Vertices.Capacity < nVertices) + Data.Vertices.Capacity = nVertices; + + if (builder.HasColor && Data.Colors.Capacity < nVertices) + Data.Colors.Capacity = nVertices; - SetupNestedList(Indices, meshes, indicesPerSubmesh); - SetupNestedList(Uvs, builder.UVChannels, nVertices); + SetupNestedList(Data.SubmeshIndices, meshes, indicesPerSubmesh); + SetupNestedList(Data.Uvs, builder.UVChannels, nVertices); FARLogger.InfoFormat("Reserved {0} voxels in {1} submeshes", count.ToString(), meshes.ToString()); } public void Add(Builder builder, T voxel) where Builder : IDebugVoxelMeshBuilder { - builder.Build(voxel, Vertices, Uvs, Indices[currentSubmesh], currentOffset); + builder.Build(voxel, Data, currentOffset); // check if submesh is filled, 32 bit indices can store 4B vertices so there should be no need to check - if (Use32BitIndices || Vertices.Count < nextVertexCount) + if (uInt32BitIndices || Data.Vertices.Count < nextVertexCount) return; - currentOffset = Vertices.Count; - currentSubmesh++; - nextVertexCount = Vertices.Count + verticesPerSubmesh; + currentOffset = Data.Vertices.Count; + Data.CurrentSubmesh++; + nextVertexCount = Data.Vertices.Count + verticesPerSubmesh; // make sure the next list for indices is valid and reserve memory to for performance - if (Indices.Count > currentSubmesh) + if (Data.Indices.Count > Data.CurrentSubmesh) return; - Indices.Add(new List()); - Indices.Capacity = indicesPerSubmesh; + Data.SubmeshIndices.Add(new List()); + Data.Indices.Capacity = indicesPerSubmesh; } public void Apply(Builder builder) where Builder : IDebugVoxelMeshBuilder { Mesh.Clear(); FARLogger.InfoFormat("Built voxel mesh with {0} voxels in {1} submeshes", - (Vertices.Count / verticesPerVoxel).ToString(), - Indices.Count.ToString()); + (Data.Vertices.Count / verticesPerVoxel).ToString(), + Data.SubmeshIndices.Count.ToString()); - Mesh.SetVertices(Vertices); - for (int i = 0; i < Uvs.Count; i++) + Mesh.SetVertices(Data.Vertices); + Mesh.SetColors(Data.Colors); + for (int i = 0; i < Data.Uvs.Count; i++) { - if (Uvs[i].Count == 0) + if (Data.Uvs[i].Count == 0) continue; - Mesh.SetUVs(i, Uvs[i]); + Mesh.SetUVs(i, Data.Uvs[i]); } //TODO: replace with Mesh.SetIndices(List, ...) when using Unity 2019.3+ - if (Use32BitIndices) + if (uInt32BitIndices) { // only 1 submesh Renderer.material = builder.MeshMaterial; - Mesh.SetIndices(Indices[0].ToArray(), builder.Topology, 0); + Mesh.SetIndices(Data.SubmeshIndices[0].ToArray(), builder.Topology, 0); } else { // ignore empty index lists - int count = Indices.Sum(list => list.Count == 0 ? 0 : 1); + int count = Data.SubmeshIndices.Sum(list => list.Count == 0 ? 0 : 1); Mesh.subMeshCount = count; var materials = new Material[count]; int offset = 0; int j = 0; - foreach (List t in Indices) + foreach (List t in Data.SubmeshIndices) { if (t.Count == 0) continue; @@ -218,8 +227,8 @@ public static int IndicesPerPrimitive(MeshTopology topology) MeshTopology.Triangles => 3, MeshTopology.Quads => 4, MeshTopology.Lines => 2, - MeshTopology.LineStrip => 10, // variable number so use some value, list will still grow as needed MeshTopology.Points => 1, + MeshTopology.LineStrip => throw new NotImplementedException("LineStrip is not supported"), _ => throw new ArgumentOutOfRangeException(nameof(topology), topology, null) }; } diff --git a/FerramAerospaceResearch/FARPartGeometry/IDebugVoxelMeshBuilder.cs b/FerramAerospaceResearch.Base/Geometry/IDebugVoxelMeshBuilder.cs similarity index 74% rename from FerramAerospaceResearch/FARPartGeometry/IDebugVoxelMeshBuilder.cs rename to FerramAerospaceResearch.Base/Geometry/IDebugVoxelMeshBuilder.cs index d3528fc8a..0d1adbe5d 100644 --- a/FerramAerospaceResearch/FARPartGeometry/IDebugVoxelMeshBuilder.cs +++ b/FerramAerospaceResearch.Base/Geometry/IDebugVoxelMeshBuilder.cs @@ -1,7 +1,6 @@ -using System.Collections.Generic; using UnityEngine; -namespace FerramAerospaceResearch.FARPartGeometry +namespace FerramAerospaceResearch.Geometry { public interface IDebugVoxelMeshBuilder { @@ -10,6 +9,11 @@ public interface IDebugVoxelMeshBuilder /// int VerticesPerVoxel { get; } + /// + /// Whether each vertex has color component + /// + bool HasColor { get; } + /// /// Number of UV channels /// @@ -37,10 +41,8 @@ public interface IDebugVoxelMeshBuilder : IDebugVoxelMeshBuilder /// Build a single voxel by appending the corresponding lists /// /// Voxel to build mesh for - /// List of mesh vertices - /// Nested list of mesh uvs, should have a list for each UV channel - /// List of indices + /// Build data /// Offset to remove from indices before adding them to the list, for use with Unity submeshes - void Build(T voxel, List vertices, List> uvs, List indices, int offset); + void Build(T voxel, MeshBuildData buildData, int offset); } } diff --git a/FerramAerospaceResearch.Base/Geometry/MeshBuildData.cs b/FerramAerospaceResearch.Base/Geometry/MeshBuildData.cs new file mode 100644 index 000000000..2b42cd244 --- /dev/null +++ b/FerramAerospaceResearch.Base/Geometry/MeshBuildData.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace FerramAerospaceResearch.Geometry +{ + public class MeshBuildData + { + public readonly List Colors = new List(); + public readonly List Vertices = new List(); + public readonly List> Uvs = new List>(); + public readonly List> SubmeshIndices = new List>(); + + public int CurrentSubmesh; + + public List Indices + { + get { return SubmeshIndices[CurrentSubmesh]; } + set { SubmeshIndices[CurrentSubmesh] = value; } + } + } +} diff --git a/FerramAerospaceResearch.Base/Interfaces/IConfigNode.cs b/FerramAerospaceResearch.Base/Interfaces/IConfigNode.cs new file mode 100644 index 000000000..30570b4d0 --- /dev/null +++ b/FerramAerospaceResearch.Base/Interfaces/IConfigNode.cs @@ -0,0 +1,28 @@ +namespace FerramAerospaceResearch.Interfaces +{ + /// + /// Interface for config nodes that need to do setup before/after loading/saving them + /// + public interface IConfigNode + { + /// + /// Called before loading this config node + /// + void BeforeLoaded(); + + /// + /// Called after loading this config node + /// + void AfterLoaded(); + + /// + /// Called before saving this config node + /// + void BeforeSaved(); + + /// + /// Called after saving this config node + /// + void AfterSaved(); + } +} diff --git a/FerramAerospaceResearch.Base/Interfaces/IConfigValue.cs b/FerramAerospaceResearch.Base/Interfaces/IConfigValue.cs new file mode 100644 index 000000000..cb2162f71 --- /dev/null +++ b/FerramAerospaceResearch.Base/Interfaces/IConfigValue.cs @@ -0,0 +1,23 @@ +// ReSharper disable UnusedMemberInSuper.Global + +namespace FerramAerospaceResearch.Interfaces +{ + /// + /// Interface for config values that are not supported types + /// + public interface IConfigValue + { + void Set(object value); + object Get(); + } + + /// + /// Generic version of IConfigValue + /// + /// type of the config value + public interface IConfigValue : IConfigValue + { + void Set(T value); + new T Get(); + } +} diff --git a/FerramAerospaceResearch.Base/Interfaces/IObservable.cs b/FerramAerospaceResearch.Base/Interfaces/IObservable.cs new file mode 100644 index 000000000..acef62b36 --- /dev/null +++ b/FerramAerospaceResearch.Base/Interfaces/IObservable.cs @@ -0,0 +1,26 @@ +using System; +// ReSharper disable UnusedMemberInSuper.Global + +namespace FerramAerospaceResearch.Interfaces +{ + /// + /// Interface for objects that should notify subscribers if the stored value changes + /// + public interface IObservable + { + object Value { get; set; } + // event Action OnValueChanged; + } + + /// + /// Generic version of IObservable + /// + /// type of the stored value + public interface IObservable : IObservable + { + new T Value { get; set; } + + // ReSharper disable once EventNeverSubscribedTo.Global + /* new */ event Action OnValueChanged; + } +} diff --git a/FerramAerospaceResearch.Base/Interfaces/IReloadable.cs b/FerramAerospaceResearch.Base/Interfaces/IReloadable.cs new file mode 100644 index 000000000..f33979c2b --- /dev/null +++ b/FerramAerospaceResearch.Base/Interfaces/IReloadable.cs @@ -0,0 +1,23 @@ +namespace FerramAerospaceResearch.Interfaces +{ + /// + /// Interface for objects that can be reloaded such as by ModuleManager + /// + public interface IReloadable + { + /// + /// Priority of when this object should be reloaded, higher values are reloaded first + /// + int Priority { get; } + + /// + /// Whether the reload has finished in case DoReload simply starts a coroutine. Is set to false before calling + /// + bool Completed { get; set; } + + /// + /// Start or do the reload + /// + void DoReload(); + } +} diff --git a/FerramAerospaceResearch.Base/Interfaces/IWaitForAddon.cs b/FerramAerospaceResearch.Base/Interfaces/IWaitForAddon.cs new file mode 100644 index 000000000..e0040cb97 --- /dev/null +++ b/FerramAerospaceResearch.Base/Interfaces/IWaitForAddon.cs @@ -0,0 +1,13 @@ +namespace FerramAerospaceResearch.Interfaces +{ + /// + /// Interface for addons that should be waited for instantiation + /// + public interface IWaitForAddon + { + /// + /// Whether this addon has completed its instantiation + /// + bool Completed { get; } + } +} diff --git a/FerramAerospaceResearch.Base/Properties/AssemblyInfo.cs b/FerramAerospaceResearch.Base/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..3bdc84e87 --- /dev/null +++ b/FerramAerospaceResearch.Base/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FerramAerospaceResearch.Base")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FerramAerospaceResearch.Base")] +[assembly: AssemblyCopyright("Copyright © dkavolis 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8E4E9138-A949-4DED-A08C-4CE3442887B4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.16.0.0")] +[assembly: AssemblyFileVersion("0.16.0.0")] diff --git a/FerramAerospaceResearch.Base/Reflection/ConfigNodeAttribute.cs b/FerramAerospaceResearch.Base/Reflection/ConfigNodeAttribute.cs new file mode 100644 index 000000000..3d94cdf51 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ConfigNodeAttribute.cs @@ -0,0 +1,42 @@ +using System; + +namespace FerramAerospaceResearch.Reflection +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + public class ConfigNodeAttribute : Attribute + { + /// + /// Whether there can be multiple nodes of this, should only be used if IsRoot is true + /// + public readonly bool AllowMultiple; + + /// + /// Whether this node should be saved + /// + public readonly bool ShouldSave; + + /// + /// Node name + /// + public readonly string Id; + + /// + /// Whether this node is root in config files + /// + public readonly bool IsRoot; + + /// + /// If not null attaches this config node as a child to Parent + /// + public readonly Type Parent; + + public ConfigNodeAttribute(string id, bool isRoot = false, bool allowMultiple = false, bool shouldSave = true, Type parent = null) + { + Id = id; + IsRoot = isRoot; + AllowMultiple = allowMultiple; + ShouldSave = shouldSave; + Parent = parent; + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ConfigReflection.cs b/FerramAerospaceResearch.Base/Reflection/ConfigReflection.cs new file mode 100644 index 000000000..0c5b2805c --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ConfigReflection.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace FerramAerospaceResearch.Reflection +{ + public class ReflectedConfig + { + public object Instance { get; set; } + public NodeReflection Reflection { get; set; } + } + + // ReSharper disable once ClassNeverInstantiated.Global + public class ConfigReflection : Singleton + { + /// + /// Dictionary of name - config pairs + /// + private readonly Dictionary nodes = new Dictionary(); + + private bool initialized; + + public Dictionary Configs + { + get + { + if (!initialized) + Initialize(); + return nodes; + } + } + + public void Initialize(bool force = false) + { + if (initialized && !force) + return; + + try + { + var allNodes = + new List>(ReflectionUtils + .FindAttribute(false)); + + foreach (Pair pair in allNodes) + { + if (!pair.First.IsRoot) + continue; + var node = NodeReflection.GetReflection(pair.Second); + nodes.Add(node.Id, + new ReflectedConfig + { + Instance = ReflectionUtils.FindInstance(pair.Second), + Reflection = node + }); + } + + FARLogger.TraceFormat("Config nodes found: {0}", string.Join(", ", nodes.Select(p => p.Key))); + } + finally + { + initialized = true; + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ConfigValueAttribute.cs b/FerramAerospaceResearch.Base/Reflection/ConfigValueAttribute.cs new file mode 100644 index 000000000..3faefea5d --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ConfigValueAttribute.cs @@ -0,0 +1,24 @@ +using System; + +namespace FerramAerospaceResearch.Reflection +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ConfigValueAttribute : Attribute + { + /// + /// Override name of this config value + /// + public readonly string Name; + + /// + /// Override type of this config value + /// + public readonly Type Type; + + public ConfigValueAttribute(string name = null, Type type = null) + { + Type = type; + Name = name; + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ConfigValueIgnoreAttribute.cs b/FerramAerospaceResearch.Base/Reflection/ConfigValueIgnoreAttribute.cs new file mode 100644 index 000000000..ce909f9f0 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ConfigValueIgnoreAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace FerramAerospaceResearch.Reflection +{ + /// + /// Attribute to ignore a member in reflection + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ConfigValueIgnoreAttribute : Attribute + { + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/INodeLoader.cs b/FerramAerospaceResearch.Base/Reflection/INodeLoader.cs new file mode 100644 index 000000000..074c6b621 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/INodeLoader.cs @@ -0,0 +1,41 @@ +using System.Collections; + +namespace FerramAerospaceResearch.Reflection +{ + public interface INodeLoader + { + /// + /// Plain value callback + /// + /// Value reflection + /// New value to set in the owner object + /// Whether the the owner object should be updated with + bool OnValue(ValueReflection reflection, out object newValue); + + /// + /// List plain value callback + /// + /// List value reflection associated with currently iterated list + /// New value to set in the owner object + /// Whether the the owner object should be updated with + bool OnValueList(ListValueReflection reflection, out IList newValue); + + /// + /// Nested node callback + /// + /// + /// Node reflection + /// New value to set in the owner object + /// Whether the the owner object should be updated with + bool OnNode(object nodeObject, NodeReflection reflection, out object newValue); + + /// + /// List nested node callback + /// + /// List reflection + /// Node reflection + /// New value to set in the owner object + /// Whether the the owner object should be updated with + bool OnNodeList(ListValueReflection reflection, NodeReflection nodeReflection, out IList newValue); + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/INodeSaver.cs b/FerramAerospaceResearch.Base/Reflection/INodeSaver.cs new file mode 100644 index 000000000..15488e07c --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/INodeSaver.cs @@ -0,0 +1,50 @@ +namespace FerramAerospaceResearch.Reflection +{ + public interface INodeSaver + { + /// + /// Plain value callback + /// + /// Current value + /// Value reflection associated with + /// New value to set in the owner object + /// Whether the owner object should be updated with + bool OnValue(object value, ValueReflection reflection, out object newValue); + + /// + /// List plain value callback + /// + /// Index of the current value + /// Current value + /// List value reflection associated with currently iterated list + /// New value to set in the owner object + /// Whether the the owner object should be updated with at index + bool OnListValue(int index, object value, ListValueReflection reflection, out object newValue); + + /// + /// Nested node callback + /// + /// Current value + /// Node reflection associated with + /// New value to set in the owner object + /// Whether the the owner object should be updated with + bool OnNode(object value, NodeReflection reflection, out object newValue); + + /// + /// List nested node callback + /// + /// Index of the current value + /// Current value + /// List reflection associated with the current member + /// Node reflection associated with + /// New value to set in the owner object + /// Whether the the owner object should be updated with at index + bool OnListNode( + int index, + object value, + ListValueReflection reflection, + NodeReflection nodeReflection, + out object newValue + ); + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ListValueReflection.cs b/FerramAerospaceResearch.Base/Reflection/ListValueReflection.cs new file mode 100644 index 000000000..0f4260bf0 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ListValueReflection.cs @@ -0,0 +1,51 @@ +using System; +using System.Reflection; + +namespace FerramAerospaceResearch.Reflection +{ + /// + /// A reflection for a list of values + /// + public class ListValueReflection : ValueReflection + { + /// + /// Id of the config node if this is a reflection of a list of config nodes + /// + public string NodeId { get; set; } + + /// + /// Whether this reflection is a list of config nodes + /// + public bool IsNodeValue + { + get { return !string.IsNullOrEmpty(NodeId); } + } + + protected ListValueReflection() + { + } + + public static ListValueReflection Create( + MemberInfo mi, + ConfigValueAttribute attribute = null, + Type valueType = null + ) + { + var reflection = new ListValueReflection(); + if (valueType != null) + reflection.ValueType = valueType; + return Factory(reflection, mi, attribute); + } + + protected override void OnSetup(Type type, ConfigValueAttribute attribute) + { + ValueType = ReflectionUtils.ListType(ValueType) ?? ValueType; + + if (attribute != null) + Name = attribute.Name; + + ConfigNodeAttribute node = ValueType.GetCustomAttribute(); + NodeId ??= node?.Id; + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/NodeReflection.cs b/FerramAerospaceResearch.Base/Reflection/NodeReflection.cs new file mode 100644 index 000000000..d90b871af --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/NodeReflection.cs @@ -0,0 +1,480 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using FerramAerospaceResearch.Interfaces; + +namespace FerramAerospaceResearch.Reflection +{ + public class NodeReflection : ValueReflection + { + private const BindingFlags PublicFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; + private const BindingFlags PrivateFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic; + private const BindingFlags AllFlags = PublicFlags | PrivateFlags; + + private static Dictionary> children; + + public static Dictionary> Children + { + get + { + if (children != null) + return children; + + children = new Dictionary>(); + + foreach (Pair pair in ReflectionUtils.FindAttribute()) + { + // FARLogger.TraceFormat("{0} parent: {1}", pair.Second.Name, pair.First.Parent?.Name); + if (pair.First.Parent is null) + continue; + + if (!children.TryGetValue(pair.First.Parent, out List list)) + { + list = new List(); + children.Add(pair.First.Parent, list); + } + + FARLogger.Assert(pair.Second.IsStatic() || ReflectionUtils.FindInstance(pair.Second) != null, + "Can only attach static types and singletons"); + list.Add(pair.Second); + } + + return children; + } + } + + /// + /// All the created for each type + /// + private static readonly Dictionary nodes = new Dictionary(); + + /// + /// Reflected lists in this config node + /// + public readonly List ListValues = new List(); + + /// + /// Reflected subnodes in this config node + /// + public readonly List Nodes = new List(); + + /// + /// Reflected values in this node + /// + public readonly List Values = new List(); + + private NodeReflection(Type type, string name) + { + ValueType = type; + Name = name; + } + + public NodeReflection(NodeReflection other, string name = null, MemberInfo mi = null) : base(other, mi) + { + Name = name; + Id = other.Id; + AllowMultiple = other.AllowMultiple; + + // copy reflected values + Values.Capacity = other.Values.Count; + foreach (ValueReflection reflection in other.Values) + Values.Add(reflection); + + // copy reflected list values + ListValues.Capacity = other.ListValues.Count; + foreach (ListValueReflection list in other.ListValues) + ListValues.Add(list); + + // copy reflected nodes + Nodes.Capacity = other.Nodes.Count; + foreach (NodeReflection node in other.Nodes) + Nodes.Add(node); + } + + /// + /// Id of this config node + /// + public string Id { get; private set; } + + /// + /// Whether this node can be declared multiple times at the top level scope + /// + public bool AllowMultiple { get; private set; } + + /// + /// Whether this node is root + /// + public bool IsRootNode { get; private set; } + + /// + /// Whether this node should be saved + /// + public bool ShouldSave { get; private set; } + + private object FindOrMakeInstance() + { + // handle static classes + if (ValueType.IsStatic()) + return null; + object instance = ReflectionUtils.FindInstance(ValueType); + if (instance != null) + return instance; + FARLogger.TraceFormat("Instance of {0} was not provided and could not find one. Creating one", ValueType); + instance = ReflectionUtils.CreateInstance(ValueType); + + FARLogger.Assert(instance != null, "Could not create instance"); + + return instance; + } + + /// + protected override void OnSetup(Type type, ConfigValueAttribute attribute) + { + ConfigNodeAttribute node = type.GetCustomAttribute(); + Id = node?.Id ?? type.Name; + + // there should only be 1 root node for one type + if (node != null) + { + IsRootNode = node.IsRoot; + ShouldSave = node.ShouldSave; + if (node.IsRoot) + AllowMultiple = node.AllowMultiple; + } + + // if this is a member of some type + if (attribute != null) + { + FARLogger.AssertFormat(!string.IsNullOrEmpty(attribute.Name), + "Nested nodes required ConfigValue.Name to be set"); + Name = attribute.Name; + } + + // get all public fields + var fields = new HashSet(type.GetFields(PublicFlags)); + + // and add all the other fields that declare ConfigValueAttribute + fields.UnionWith(type.GetFieldsWithAttribute(flags: AllFlags) + .Select(pair => pair.Second)); + + // only get properties that declare ConfigValueAttribute + var properties = new List(type.GetPropertiesWithAttribute(AllFlags) + .Select(pair => pair.Second)); + + FARLogger.TraceFormat("Found {0} fields and {1} properties in {2}", + fields.Count.ToString(), + properties.Count.ToString(), + type); + + foreach (FieldInfo fi in fields) + SetupType(fi, fi.FieldType); + + foreach (PropertyInfo pi in properties) + SetupType(pi, pi.PropertyType); + + if (!Children.TryGetValue(type, out List list)) + return; + foreach (Type subnode in list) + SetupType(null, subnode); + } + + private void SetupType(MemberInfo mi, Type memberType) + { + // if ignored, nothing to do + if (mi?.GetCustomAttribute() != null) + return; + + // check if the type is a node and contains ConfigValueAttribute + ConfigNodeAttribute node = memberType.GetCustomAttribute(); + ConfigValueAttribute value = mi?.GetCustomAttribute(); + + // try to get the list value type + Type listValueType = ReflectionUtils.ListType(ReflectionUtils.ConfigValueType(memberType) ?? memberType); + + if (listValueType != null) + { + // is a list + var reflection = ListValueReflection.Create(mi, value, listValueType); + + ListValues.Add(reflection); + FARLogger.TraceFormat("Added list value '{1} -> <{0}, {2}>'", + reflection.Name ?? "{null}", + reflection.NodeId ?? "{null}", + reflection.ValueType); + } + else if (node == null) + { + // not a node or a list -> simple value + ValueReflection reflection = Create(mi, value); + Values.Add(reflection); + FARLogger.TraceFormat("Added value '{0} -> {1}'", reflection.Name, reflection.ValueType); + } + else + { + // ConfigValue name + string name = value?.Name; + + // get clone or create new reflection for the type + NodeReflection nodeReflection = GetReflection(memberType, true, name, mi); + Nodes.Add(nodeReflection); + FARLogger.TraceFormat("Added node '{1} -> <{0}, {2}>'", + name ?? "{null}", + nodeReflection.Id, + nodeReflection.ValueType); + } + } + + public static NodeReflection GetReflection( + Type type, + bool clone = false, + string cloneName = null, + MemberInfo mi = null + ) + { + // get or create NodeReflection and cache it + if (nodes.TryGetValue(type, out NodeReflection original)) + return !clone ? original : new NodeReflection(original, cloneName, mi); + original = Factory(new NodeReflection(type, cloneName), mi); + nodes.Add(type, original); + + return !clone ? original : new NodeReflection(original, cloneName, mi); + } + + private int Apply(ref object owner, NodeVisitor visitor) + { + int count = 0; + FARLogger.TraceFormat("Applying visitor to config node {0}[{1}]", Id, Name ?? "{null}"); + foreach (ValueReflection value in Values) + { + FARLogger.TraceFormat("Visiting value {0}[{1}].{2}", Id, Name, value.Name); + try + { + visitor.VisitValue(owner, value); + } + catch (Exception e) + { + FARLogger.ExceptionFormat(e, "Exception loading value {0} in {1}", value.Name, value.DeclaringType); + count++; + } + } + + foreach (ListValueReflection reflection in ListValues) + { + if (reflection.IsNodeValue) + { + NodeReflection nodeReflection = GetReflection(reflection.ValueType); + + FARLogger.TraceFormat("Visiting list nodes {0}[{1}].{2}[{3}]", + Id, + Name ?? "{null}", + reflection.NodeId, + reflection.Name ?? "{null}"); + try + { + visitor.VisitNodeList(owner, reflection, nodeReflection); + } + catch (Exception e) + { + FARLogger.ExceptionFormat(e, + "Exception loading node ({2}) list {0} in {1}", + reflection.Name, + reflection.DeclaringType, + reflection.NodeId); + count++; + } + } + else + { + FARLogger.TraceFormat("Visiting list values {0}[{1}].{2}", Id, Name ?? "{null}", reflection.Name); + try + { + visitor.VisitValueList(owner, reflection); + } + catch (Exception e) + { + FARLogger.ExceptionFormat(e, + "Exception loading value list {0} in {1}", + reflection.Name, + reflection.DeclaringType); + count++; + } + } + } + + foreach (NodeReflection node in Nodes) + { + FARLogger.TraceFormat("Visiting subnode {0}[{1}].{2}[{3}]", + Id, + Name ?? "{null}", + node.Id, + node.Name ?? "{null}"); + try + { + visitor.VisitNode(owner, node); + } + catch (Exception e) + { + FARLogger.ExceptionFormat(e, + "Exception loading node {2}[{0}] in {1}", + node.Name, + node.DeclaringType, + node.Id); + count++; + } + } + + return count; + } + + public int Save(INodeSaver saver, object instance) + { + var save = new NodeReader {Saver = saver}; + var node = instance as IConfigNode; + node?.BeforeSaved(); + int count = Apply(ref instance, save); + node?.AfterSaved(); + return count; + } + + public int Load(INodeLoader loader, ref object instance) + { + var load = new NodeLoader {Loader = loader}; + var node = instance as IConfigNode; + node?.BeforeLoaded(); + int count = Apply(ref instance, load); + node?.AfterLoaded(); + return count; + } + + public object Load(INodeLoader loader, out int errors) + { + object instance = FindOrMakeInstance(); + errors = Load(loader, ref instance); + return instance; + } + + private abstract class NodeVisitor + { + public abstract void VisitValue(object owner, ValueReflection reflection); + public abstract void VisitValueList(object owner, ListValueReflection reflection); + + public abstract void VisitNodeList( + object owner, + ListValueReflection reflection, + NodeReflection nodeReflection + ); + + public abstract void VisitNode(object owner, NodeReflection reflection); + + protected static void CopyList(IList from, IList to, Type valueType) + { + if (from is null || to is null) + return; + + object def = valueType.IsValueType ? Activator.CreateInstance(valueType) : null; + + int count = from.Count; + if (to.IsFixedSize) + { + count = Math.Min(count, to.Count); + for (int i = 0; i < count; i++) + to[i] = from[i] ?? def; + } + else + { + to.Clear(); + for (int i = 0; i < count; i++) + to.Add(from[i] ?? def); + } + } + } + + private sealed class NodeLoader : NodeVisitor + { + public INodeLoader Loader { get; set; } + + /// + public override void VisitValue(object owner, ValueReflection reflection) + { + if (Loader.OnValue(reflection, out object value)) + reflection.SetMember(owner, value, true); + } + + /// + public override void VisitValueList(object owner, ListValueReflection reflection) + { + if (Loader.OnValueList(reflection, out IList list)) + CopyList(list, reflection.GetMember(owner) as IList, reflection.ValueType); + } + + /// + public override void VisitNodeList( + object owner, + ListValueReflection reflection, + NodeReflection nodeReflection + ) + { + if (Loader.OnNodeList(reflection, nodeReflection, out IList list)) + CopyList(list, reflection.GetMember(owner) as IList, reflection.ValueType); + } + + /// + public override void VisitNode(object owner, NodeReflection reflection) + { + if (Loader.OnNode(reflection.GetMember(owner), reflection, out object value) && value != null) + reflection.SetMember(owner, value, true); + } + } + + private sealed class NodeReader : NodeVisitor + { + public INodeSaver Saver { get; set; } + + /// + public override void VisitValue(object owner, ValueReflection reflection) + { + if (Saver.OnValue(reflection.GetMember(owner), reflection, out object newValue)) + reflection.SetMember(owner, newValue, true); + } + + /// + public override void VisitValueList(object owner, ListValueReflection reflection) + { + if (!(reflection.GetMember(owner) is IList member)) + return; + + for (int i = 0; i < member.Count; i++) + { + if (Saver.OnListValue(i, member[i], reflection, out object newValue)) + member[i] = newValue; + } + } + + /// + public override void VisitNodeList( + object owner, + ListValueReflection reflection, + NodeReflection nodeReflection + ) + { + if (!(reflection.GetMember(owner) is IList member)) + return; + + for (int i = 0; i < member.Count; i++) + { + if (Saver.OnListNode(i, member[i], reflection, nodeReflection, out object newValue)) + member[i] = newValue; + } + } + + /// + public override void VisitNode(object owner, NodeReflection reflection) + { + if (Saver.OnNode(reflection.GetMember(owner), reflection, out object newValue)) + reflection.SetMember(owner, newValue, true); + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ReflectionUtils.cs b/FerramAerospaceResearch.Base/Reflection/ReflectionUtils.cs new file mode 100644 index 000000000..781b62243 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ReflectionUtils.cs @@ -0,0 +1,429 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using FerramAerospaceResearch.Interfaces; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace FerramAerospaceResearch.Reflection +{ + public static class ReflectionUtils + { + /// + /// Cache for the loaded assemblies + /// + private static Assembly[] loadedAssemblies; + + /// + /// Cache for singletons + /// + private static readonly ConcurrentDictionary instances = new ConcurrentDictionary(); + + public static Assembly ExecutingAssembly { get; } = Assembly.GetExecutingAssembly(); + + /// + /// Cache for loaded types per assembly + /// + public static Dictionary LoadedTypes { get; } = new Dictionary(); + + /// + /// Lazy getter for loaded assemblies + /// + public static Assembly[] LoadedAssemblies + { + get { return loadedAssemblies ??= ReloadAssemblies(); } + } + + /// + /// Reload the assembly cache in case anything has changed + /// + /// Array of loaded assemblies + public static Assembly[] ReloadAssemblies() + { + loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + return loadedAssemblies; + } + + /// + /// Find types in the specified assembly that derive from T + /// + /// + /// + /// + /// enumerable of Type + public static IEnumerable FindTypesInAssembly(Assembly assembly, bool inherit = true) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (Type type in GetTypes(assembly)) + if (type.IsDefined(typeof(T), inherit)) + yield return type; + } + + public static IEnumerable FindTypesInAssembly(bool inherit = true) + { + return FindTypesInAssembly(ExecutingAssembly, inherit); + } + + public static IEnumerable FindTypes(IEnumerable types, bool inherit) + { + if (inherit) + { + foreach (Type type in types) + if (typeof(T).IsBaseOf(type)) + yield return type; + } + else + { + foreach (Type type in types) + if (type == typeof(T)) + yield return type; + } + } + + public static IEnumerable FindTypes(IEnumerable assemblies, bool inherit) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (Assembly assembly in assemblies) + foreach (Type type in FindTypes(GetTypes(assembly), inherit)) + yield return type; + } + + public static IEnumerable FindTypes(bool inherit) + { + return FindTypes(LoadedAssemblies, inherit); + } + + public static IEnumerable> FindAttributeInAssembly(Assembly assembly, bool inherit = true) + where T : Attribute + { + foreach (Type type in GetTypes(assembly)) + if (type.GetCustomAttribute(typeof(T), inherit) is T attribute) + yield return Pair.Create(attribute, type); + } + + public static IEnumerable> FindAttributeInAssembly(bool inherit = true) where T : Attribute + { + return FindAttributeInAssembly(ExecutingAssembly, inherit); + } + + public static IEnumerable> FindAttribute(IEnumerable assemblies, bool inherit = true) + where T : Attribute + { + // AssemblyLoader.loadedTypes don't have all the types from all the assemblies + foreach (Assembly assembly in assemblies) + foreach (Type type in GetTypes(assembly)) + if (type.GetCustomAttribute(typeof(T), inherit) is T attribute) + yield return Pair.Create(attribute, type); + } + + public static IEnumerable> FindAttribute(IEnumerable types, bool inherit = true) + where T : Attribute + { + foreach (Type type in types) + if (type.GetCustomAttribute(typeof(T), inherit) is T attribute) + yield return Pair.Create(attribute, type); + } + + public static IEnumerable> FindAttribute(bool inherit = true) where T : Attribute + { + return FindAttribute(LoadedAssemblies, inherit); + } + + /// + /// Add a component to a GameObject. Note that this function must be run from the main thread since it accesses Unity methods + /// + /// type of the component + /// optional parent gameobject, if not provided will create new one + /// whether this component should not be destroyed on load + /// the created component + public static Component Create(Type type, Transform parent = null, bool persistant = false) + { + FARLogger.Assert(typeof(Component).IsBaseOf(type), + $"Invalid type given: {type.ToString()}, expected Component"); + + GameObject go = parent == null ? new GameObject() : parent.gameObject; + Component component = go.AddComponent(type); + + if (persistant) + Object.DontDestroyOnLoad(component); + + return component; + } + + /// + /// Create an instance of an object from type + /// + /// type of the object + /// optional parent gameobject, only used if type is a child of Component + /// whether the component should not be destroyed on load + /// the created object instance + public static object CreateInstance(Type type, Transform parent = null, bool persistant = false) + { + return typeof(Component).IsBaseOf(type) ? Create(type, parent, persistant) : Activator.CreateInstance(type); + } + + public static bool IsBaseOf(this Type type, Type derived) + { + return type.IsAssignableFrom(derived); + } + + public static IEnumerable GetTypes(IEnumerable assemblies) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (Assembly assembly in assemblies) + foreach (Type type in GetTypes(assembly)) + yield return type; + } + + public static IEnumerable GetTypes() + { + return GetTypes(LoadedAssemblies); + } + + public static Type[] GetTypes(Assembly assembly) + { + if (LoadedTypes.TryGetValue(assembly, out Type[] types)) + return types; + + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException e) + { + FARLogger.Exception(e, $"While loading {assembly}"); + foreach (Exception exception in e.LoaderExceptions) + { + FARLogger.Exception(exception); + } + + types = e.Types.Where(t => t != null).ToArray(); + } + catch (Exception e) + { + FARLogger.Exception(e); + types = Type.EmptyTypes; + } + + LoadedTypes.Add(assembly, types); + + return types; + } + + public static Type[] ReloadTypes(Assembly assembly) + { + LoadedTypes.Remove(assembly); + return GetTypes(assembly); + } + + public static IEnumerable> GetFieldsWithAttribute( + this Type type, + bool compilerGenerated = false, + BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic + ) where T : Attribute + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (FieldInfo fi in type.GetFields(flags)) + { + if (!compilerGenerated && fi.GetCustomAttribute() != null) + continue; + + T attribute = fi.GetCustomAttribute(); + if (attribute != null) + yield return Pair.Create(attribute, fi); + } + } + + public static IEnumerable> GetPropertiesWithAttribute( + this Type type, + BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic + ) where T : Attribute + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (PropertyInfo fi in type.GetProperties(flags)) + { + T attribute = fi.GetCustomAttribute(); + if (attribute != null) + yield return Pair.Create(attribute, fi); + } + } + + public static IEnumerable GetParentTypes(this Type type) + { + // is there any base type? + if (type == null) + yield break; + + // return all implemented or inherited interfaces + foreach (Type i in type.GetInterfaces()) + yield return i; + + // return all inherited types + Type currentBaseType = type.BaseType; + while (currentBaseType != null) + { + yield return currentBaseType; + currentBaseType = currentBaseType.BaseType; + } + } + + /// + /// Cache a singleton instance + /// + /// type of the instance + /// + /// instance + public static object RegisterInstance(Type type, object instance) + { + if (!instances.TryAdd(type, instance)) + FARLogger.ErrorFormat("Could not register instance <{0}> of type {1}", instance, type.Name); + else if (instance != null && type != instance.GetType() && !instances.ContainsKey(instance.GetType())) + if (!instances.TryAdd(instance.GetType(), instance)) + FARLogger.ErrorFormat("Could not register instance <{0}> of type {1}", + instance, + instance.GetType().Name); + return instance; + } + + /// + /// Try to get a singleton instance. The resolution order is: + /// 1. Type is a static class + /// 2. An instance has been already cached with the provided type + /// 3. An instance has been already cached with a different derived type + /// 4. Type contains static field 'instance' (case insensitive) + /// 5. Type contains static property 'instance' (case insensitive) + /// 6. Type contains static method 'instance' (case insensitive) + /// New found instances are cached + /// + /// type of the singleton + /// instance if found and not static class, null otherwise + public static object FindInstance(Type type) + { + const BindingFlags flags = BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.FlattenHierarchy | + BindingFlags.IgnoreCase; + + // short circuit for static types + if (type.IsStatic()) + return null; + + // first try checking if an instance has already been found + if (instances.TryGetValue(type, out object instance)) + return instance; + + // otherwise do a slow check with inheritance + foreach (KeyValuePair pair in instances) + { + if (type.IsBaseOf(pair.Key)) + return pair.Value; + } + + // not found so check for fields/properties/methods 'Instance' + FieldInfo field = type.GetField("Instance", flags); + if (field != null) + { + instance = field.GetValue(null); + if (type.IsBaseOf(instance?.GetType())) + return RegisterInstance(type, instance); + FARLogger.TraceFormat("Found static field Instance in {0} but it returns a different type {1}", + type, + instance?.GetType()); + } + + PropertyInfo info = type.GetProperty("Instance", flags); + if (info != null) + { + instance = info.GetValue(null, flags, null, null, null); + if (type.IsBaseOf(instance?.GetType())) + return RegisterInstance(type, instance); + FARLogger.TraceFormat("Found static property Instance in {0} but it returns a different type {1}", + type, + instance?.GetType()); + } + + MethodInfo method = type.GetMethod("Instance", flags, null, new Type[0], null); + if (method == null) + return RegisterInstance(type, null); + + // ReSharper disable once AssignNullToNotNullAttribute - false positive + instance = method.Invoke(null, flags, null, new object[0], null); + if (instance != null && type.IsBaseOf(instance.GetType())) + return RegisterInstance(type, instance); + + FARLogger.TraceFormat("Found static method Instance in {0} but it returns a different type {1}", + type, + instance?.GetType()); + return RegisterInstance(type, null); + } + + public static bool IsStatic(this Type type) + { + return type.IsAbstract && type.IsSealed; + } + + /// + /// Get generic interface type parameters + /// + /// type implementing the interface + /// generic interface type + /// array of generic arguments of interfaceType if it is found in type, otherwise null + public static Type[] GetGenericInterfaceArguments(Type type, Type interfaceType) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == interfaceType) + return type.GetGenericArguments(); + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (Type i in type.GetInterfaces()) + if (i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType) + return i.GetGenericArguments(); + + return null; + } + + /// + /// See for description of parameters + /// + /// Returns the first generic interface argument + public static Type InterfaceParameter(Type type, Type interfaceType) + { + Type[] args = GetGenericInterfaceArguments(type, interfaceType); + + return args?.Single(); + } + + /// + /// Get the IConfigValue generic type parameter + /// + /// type to check for IConfigValue interface + /// Generic parameter if found, null otherwise + public static Type ConfigValueType(Type type) + { + return InterfaceParameter(type, typeof(IConfigValue<>)); + } + + /// + /// Get the IList generic type parameter + /// + /// type to check for List interface + /// Generic parameter if found, null otherwise + public static Type ListType(Type type) + { + return InterfaceParameter(type, typeof(IList<>)); + } + + /// + /// Check if type implements generic IList interface + /// + /// type to check + /// + public static bool IsListValue(Type type) + { + return ListType(type) != null; + } + } +} diff --git a/FerramAerospaceResearch.Base/Reflection/ValueReflection.cs b/FerramAerospaceResearch.Base/Reflection/ValueReflection.cs new file mode 100644 index 000000000..82cb1d0e2 --- /dev/null +++ b/FerramAerospaceResearch.Base/Reflection/ValueReflection.cs @@ -0,0 +1,318 @@ +using System; +using System.Reflection; +using FerramAerospaceResearch.Interfaces; + +namespace FerramAerospaceResearch.Reflection +{ + /// + /// Base class for config value reflection + /// + public class ValueReflection + { + /// + /// Copy constructor that will rebind to a provided MemberInfo if not null + /// + /// Value to copy from + /// If provided, bind getter and setter to it + protected ValueReflection(ValueReflection other, MemberInfo mi = null) + { + // simple copy is enough + Name = other.Name; + ValueType = other.ValueType; + DeclaringType = mi?.DeclaringType ?? other.DeclaringType; + + // if MemberInfo is provided use it to setup the correct getter and setter, otherwise just copy + // this is useful for when the same type is reused with different declaring types + Info = mi == null ? other.Info : SetupInfo(mi); + } + + protected ValueReflection() + { + } + + /// + /// Name of the reflected value in the config + /// + public string Name { get; protected set; } + + /// + /// Type of the config value + /// + public Type ValueType { get; protected set; } + + /// + /// Type of declaring type + /// + public Type DeclaringType { get; protected set; } + + /// + /// Whether this value is contained in static class + /// + protected bool StaticParser + { + get { return DeclaringType == null || DeclaringType.IsStatic(); } + } + + private GetterSetter Info { get; set; } + + private static GetterSetter SetupInfo(MemberInfo mi) + { + switch (mi) + { + case FieldInfo fi: + if (typeof(IConfigValue).IsBaseOf(fi.FieldType)) + return new CVFieldMember(fi); + return new FieldMember(fi); + + case PropertyInfo fi: + if (typeof(IConfigValue).IsBaseOf(fi.PropertyType)) + return new CVPropertyMember(fi); + return new PropertyMember(fi); + + default: + throw new + ArgumentException($"Invalid argument, expected either FieldInfo or PropertyInfo but got {mi.GetType().Name}", + nameof(mi)); + } + } + + /// + /// Set the value of property/field this reflection points to + /// + /// Instance of the object to set the value to, null for static classes + /// New value + /// If true will silently fail for readonly members + public void SetMember(object instance, object value, bool suppressReadOnly = false) + { + CheckInstanceType(instance, SourceInfo.Current()); + CheckValueType(value, SourceInfo.Current()); + if (suppressReadOnly && !Info.CanWrite) + return; + Info.Set(instance, value); + } + + /// + /// Get the value of property/field this reflection points to + /// + /// Instance of the object to retrieve the value from + /// The retrieved value + public object GetMember(object instance) + { + CheckInstanceType(instance, SourceInfo.Current()); + return Info.Get(instance); + } + + /// + /// A factory method for value reflections since virtual methods cannot be called in constructors + /// + /// the reflection to setup + /// member info this reflection will use + /// optional attribute of the field/property, if null will try to get it automatically + /// child class of ValueReflection + /// reflection ready to use + protected static T Factory(T reflection, MemberInfo mi, ConfigValueAttribute attribute = null) + where T : ValueReflection + { + // mi may be null when reflected value is not a member of a type + if (mi is null) + reflection.Info = reflection.ValueType is null ? null : new SingletonMember(reflection.ValueType); + else + reflection.Info = SetupInfo(mi); + + // this involves a virtual call so cannot be used in constructors + // if mi is null, use existing value type + reflection.Setup(mi, reflection.Info?.ValueType ?? reflection.ValueType, attribute); + + return reflection; + } + + public static ValueReflection Create(MemberInfo mi, ConfigValueAttribute attribute = null) + { + return Factory(new ValueReflection(), mi, attribute); + } + + private void Setup(MemberInfo mi, Type type, ConfigValueAttribute attribute = null) + { + // try and get the attribute since it will override some of the options + attribute ??= type?.GetCustomAttribute(); + + DeclaringType = mi?.DeclaringType; + + // if name has not been yet setup, use the name from the attribute if it was specified, otherwise default to the member name + Name ??= attribute?.Name ?? mi?.Name; + + // if value type has not been setup, try to deduce it from the member type, then try to use type from the attribute or fallback to the provided type + ValueType ??= ReflectionUtils.ConfigValueType(type) ?? attribute?.Type ?? type; + + // delegate the remaining setup to children + OnSetup(type, attribute); + } + + /// + /// Finalize this reflection setup + /// + /// Type of this reflection + /// ConfigValueAttribute for this reflection, null if not found + protected virtual void OnSetup(Type type, ConfigValueAttribute attribute) + { + } + + protected void CheckInstanceType(object instance, SourceInfo current) + { + FARLogger.AssertFormat(StaticParser && instance == null || + instance != null && (DeclaringType?.IsBaseOf(instance.GetType()) ?? true), + "Invalid instance type {0}, expected {1}", + current, + instance?.GetType(), + DeclaringType); + } + + protected void CheckValueType(object value, SourceInfo current) + { + FARLogger.AssertFormat(ValueType.IsBaseOf(value.GetType()), + "Invalid value type {0}, expected {1}", + current, + value.GetType(), + ValueType); + } + + // Virtual classes for FieldInfo/PropertyInfo type erasure + + private abstract class GetterSetter + { + public abstract Type ValueType { get; } + public bool CanWrite { get; protected set; } = true; + public abstract void Set(object instance, object value); + public abstract object Get(object instance); + } + + private class FieldMember : GetterSetter + { + public readonly FieldInfo Info; + + public FieldMember(FieldInfo info) + { + Info = info; + CanWrite = !info.IsInitOnly; + } + + public override Type ValueType + { + get { return Info.FieldType; } + } + + public override void Set(object instance, object value) + { + Info.SetValue(instance, value, BindingFlags.NonPublic, null, null); + } + + public override object Get(object instance) + { + return Info.GetValue(instance); + } + } + + private class PropertyMember : GetterSetter + { + public readonly PropertyInfo Info; + + public PropertyMember(PropertyInfo info) + { + Info = info; + CanWrite = info.CanWrite; + } + + public override Type ValueType + { + get { return Info.PropertyType; } + } + + public override void Set(object instance, object value) + { + Info.SetValue(instance, value, BindingFlags.NonPublic, null, null, null); + } + + public override object Get(object instance) + { + return Info.GetValue(instance); + } + } + + private class CVFieldMember : GetterSetter + { + public readonly FieldInfo Info; + + public CVFieldMember(FieldInfo info) + { + Info = info; + } + + public override Type ValueType + { + get { return Info.FieldType; } + } + + public override void Set(object instance, object value) + { + object v = Info.GetValue(instance); + ((IConfigValue)v).Set(value); + } + + public override object Get(object instance) + { + object v = Info.GetValue(instance); + return ((IConfigValue)v).Get(); + } + } + + private class CVPropertyMember : GetterSetter + { + public readonly PropertyInfo Info; + + public CVPropertyMember(PropertyInfo info) + { + Info = info; + } + + public override Type ValueType + { + get { return Info.PropertyType; } + } + + public override void Set(object instance, object value) + { + object v = Info.GetValue(instance); + ((IConfigValue)v).Set(value); + } + + public override object Get(object instance) + { + object v = Info.GetValue(instance); + return ((IConfigValue)v).Get(); + } + } + + private class SingletonMember : GetterSetter + { + public readonly object Singleton; + + public SingletonMember(Type type) + { + ValueType = type; + Singleton = type.IsStatic() ? null : ReflectionUtils.FindInstance(type); + } + + public override Type ValueType { get; } + + public override void Set(object instance, object value) + { + throw new NotImplementedException(); + } + + public override object Get(object instance) + { + return Singleton; + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/FARAssetDictionary.cs b/FerramAerospaceResearch.Base/Resources/FARAssetDictionary.cs new file mode 100644 index 000000000..0223f22b1 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/FARAssetDictionary.cs @@ -0,0 +1,64 @@ +using System.Collections; +using System.Collections.Generic; +using FerramAerospaceResearch.Resources.Loading; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + public class FARAssetDictionary : Dictionary + { + private readonly List> requests = new List>(); + + public bool Contains(string name) + { + return ContainsKey(name); + } + + public void Unsubscribe() + { + foreach (LoadableAsset request in requests) + { + request.OnAssetLoaded -= OnAssetLoaded; + request.OnAssetLoadError -= OnAssetError; + } + } + + public IEnumerator Load() + { + foreach (LoadableAsset request in requests) + { + request.Load(); + } + + foreach (LoadableAsset request in requests) + { + if (FinishedLoading(request)) + continue; + yield return new WaitUntil(() => FinishedLoading(request)); + } + } + + private static bool FinishedLoading(IAssetRequest request) + { + return request.State == Progress.Completed || request.State == Progress.Error; + } + + protected void SetupAsset(LoadableAsset asset) + { + Add(asset.Key, asset.Asset); + requests.Add(asset); + + asset.OnAssetLoaded += OnAssetLoaded; + asset.OnAssetLoadError += OnAssetError; + } + + private void OnAssetLoaded(string key, AssetRequest request) + { + this[key] = request.Asset; + } + + private static void OnAssetError(string key, AssetRequest request) + { + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/FARAssets.cs b/FerramAerospaceResearch.Base/Resources/FARAssets.cs new file mode 100644 index 000000000..85e664bd7 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/FARAssets.cs @@ -0,0 +1,79 @@ +using System.Collections; +using FerramAerospaceResearch.Interfaces; +using FerramAerospaceResearch.Resources.Loading; +using FerramAerospaceResearch.Threading; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + [FARAddon(0, true)] + public class FARAssets : MonoSingleton, IReloadable + { + private bool loaded; + public FARShaderCache Shaders { get; private set; } + public FARTextureCache Textures { get; private set; } + public LoaderCache Loaders { get; private set; } + + public ShaderBundleLoader ShaderLoader { get; private set; } + + public int Priority { get; set; } + public bool Completed { get; set; } + + public void DoReload() + { + if (!loaded) + StartCoroutine(LoadAssets()); + else + Completed = true; + } + + protected override void OnAwake() + { + // first setup bundle loaders + ShaderLoader = new ShaderBundleLoader(); + + // then setup loader caches and add loaders + Loaders = new LoaderCache(); + Loaders.Shaders.Add(new AssetBundleAssetLoader {BundleLoader = ShaderLoader}); + Loaders.Textures.Add(new TextureLoader()); + Loaders.Shaders.Add(new ShaderLoader()); + + // finally, setup asset caches + Shaders = new FARShaderCache(); + Textures = new FARTextureCache(); + } + + protected override void OnDestruct() + { + Textures.Unsubscribe(); + Shaders.Unsubscribe(); + ShaderLoader.Unsubscribe(); + } + + public void ReloadAssets() + { + MainThread.StartCoroutine(DoReloadAssets); + } + + private IEnumerator LoadAssets() + { + FARLogger.Debug("Loading all assets"); + if (ShaderLoader.NeedsReload) + yield return ShaderLoader.Load(); + + while (ShaderLoader.State == Progress.InProgress) + yield return null; + + yield return DoReloadAssets(); + + Completed = true; + loaded = true; + } + + private IEnumerator DoReloadAssets() + { + yield return Shaders.Load(); + yield return Textures.Load(); + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/FARShaderCache.cs b/FerramAerospaceResearch.Base/Resources/FARShaderCache.cs new file mode 100644 index 000000000..c46077df4 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/FARShaderCache.cs @@ -0,0 +1,96 @@ +using FerramAerospaceResearch.Config; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + public class FARShaderCache : FARAssetDictionary + { + public FARShaderCache() + { + LineRenderer = MakeAsset(FARConfig.Shaders.LineRenderer, "line_renderer"); + DebugVoxel = MakeAsset(FARConfig.Shaders.DebugVoxel, "debug_voxel"); + DebugVoxelFallback = MakeAsset(FARConfig.Shaders.DebugVoxelFallback, "debug_voxel_fallback"); + } + + public ShaderAssetRequest LineRenderer { get; } + public ShaderAssetRequest DebugVoxel { get; } + public ShaderAssetRequest DebugVoxelFallback { get; } + + private ShaderAssetRequest MakeAsset(ResourceNode node, string name) + { + var asset = new ShaderAssetRequest + { + AssetLoaders = FARAssets.Instance.Loaders.Shaders, + Key = name, + Node = node + }; + SetupAsset(asset); + return asset; + } + + public class ShaderAssetRequest : LoadableAsset + { + private ShaderMaterialPair Items { get; } = new ShaderMaterialPair(); + + public Material Material + { + get { return Items.Material; } + } + + /// + protected override void AssetLoaded() + { + base.AssetLoaded(); + Items.Shader = Asset; + } + + + public static implicit operator ShaderMaterialPair(ShaderAssetRequest rb) + { + return rb.Items; + } + + public static implicit operator Shader(ShaderAssetRequest rb) + { + return rb.Items.Shader; + } + + public static implicit operator Material(ShaderAssetRequest rb) + { + return rb.Items.Material; + } + } + + public class ShaderMaterialPair + { + private Shader shader; + + public Shader Shader + { + get { return shader; } + set + { + shader = value; + if (value == null) + return; + if (Material == null) + Material = new Material(value); + else + Material.shader = value; + } + } + + public Material Material { get; private set; } + + public static implicit operator Material(ShaderMaterialPair sm) + { + return sm.Material; + } + + public static implicit operator Shader(ShaderMaterialPair sm) + { + return sm.shader; + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/FARTextureCache.cs b/FerramAerospaceResearch.Base/Resources/FARTextureCache.cs new file mode 100644 index 000000000..1e271760d --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/FARTextureCache.cs @@ -0,0 +1,31 @@ +using FerramAerospaceResearch.Config; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + public class FARTextureCache : FARAssetDictionary + { + public readonly LoadableAsset DebugVoxel; + public readonly LoadableAsset IconLarge; + public readonly LoadableAsset IconSmall; + + public FARTextureCache() + { + IconLarge = MakeAsset(FARConfig.Textures.IconButtonStock, "stock_button"); + IconSmall = MakeAsset(FARConfig.Textures.IconButtonBlizzy, "blizzy_button"); + DebugVoxel = MakeAsset(FARConfig.Textures.SpriteDebugVoxel, "debug_voxel"); + } + + private LoadableAsset MakeAsset(ResourceNode node, string name) + { + var asset = new LoadableAsset + { + AssetLoaders = FARAssets.Instance.Loaders.Textures, + Key = name, + Node = node + }; + SetupAsset(asset); + return asset; + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/LoadableAsset.cs b/FerramAerospaceResearch.Base/Resources/LoadableAsset.cs new file mode 100644 index 000000000..a714e8f48 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/LoadableAsset.cs @@ -0,0 +1,89 @@ +using System; +using FerramAerospaceResearch.Config; +using FerramAerospaceResearch.Resources.Loading; +using FerramAerospaceResearch.Threading; + +namespace FerramAerospaceResearch.Resources +{ + public class LoadableAsset : AssetRequest + { + public Loaders AssetLoaders { get; set; } + public IAssetLoader Loader { get; private set; } + + public string Key { get; set; } + + public event Action> OnAssetLoaded; + public event Action> OnAssetLoadError; + + private ResourceNode node; + + public ResourceNode Node + { + get { return node; } + set + { + Unsubscribe(); + node = value; + Subscribe(); + + Url = node.Url; + Loader = AssetLoaders.Get(node.Loader); + } + } + + private void OnUrlChanged(string url) + { + FARLogger.TraceFormat("Asset '{0}' url has changed: '{1}' -> {2}", Key, Url, url); + Url = url; + Load(); + } + + private void OnLoaderChanged(string name) + { + FARLogger.TraceFormat("Asset '{0}' loader has changed: '{1}' -> {2}", Key, Loader.Name, name); + Loader = AssetLoaders.Get(name); + Load(); + } + + public void Load() + { + if (Loader is null) + { + FARLogger.WarningFormat("Could not load resource from {0} because loader is not set", Url); + return; + } + + MainThread.StartCoroutine(() => Loader.Load(this)); + } + + private void Subscribe() + { + if (node is null) + return; + + node.Url.OnValueChanged += OnUrlChanged; + node.Loader.OnValueChanged += OnLoaderChanged; + } + + public void Unsubscribe() + { + if (node is null) + return; + + node.Url.OnValueChanged -= OnUrlChanged; + node.Loader.OnValueChanged -= OnLoaderChanged; + } + + /// + protected override void AssetLoaded() + { + OnAssetLoaded?.Invoke(Key, this); + } + + /// + protected override void AssetError() + { + OnAssetLoadError?.Invoke(Key, this); + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/LoaderCache.cs b/FerramAerospaceResearch.Base/Resources/LoaderCache.cs new file mode 100644 index 000000000..2d72718b0 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/LoaderCache.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using FerramAerospaceResearch.Resources.Loading; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + public class LoaderCache + { + public Loaders Shaders { get; } = new Loaders(); + public Loaders Textures { get; } = new Loaders(); + } + + public class Loaders : Dictionary> + { + private IAssetLoader defaultLoader; + + public Loaders() + { + Add("default", null); + } + + public IAssetLoader Default + { + get { return defaultLoader; } + set + { + defaultLoader = value; + this["default"] = value; + } + } + + public IAssetLoader Get(string name) + { + if (string.IsNullOrEmpty(name)) + return Default; + return TryGetValue(name, out IAssetLoader loader) ? loader : Default; + } + + public void Add(IAssetLoader loader) + { + if (string.IsNullOrEmpty(loader.Name) || loader.Name == "default") + Default = loader; + else + base.Add(loader.Name, loader); + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleAssetLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleAssetLoader.cs new file mode 100644 index 000000000..47f3fce0b --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleAssetLoader.cs @@ -0,0 +1,46 @@ +using System.Collections; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public class AssetBundleAssetLoader : IAssetLoader where T : Object + { + public IAssetBundleLoader BundleLoader { get; set; } + + /// + public IEnumerator Load(IAssetRequest assetRequest) + { + FARLogger.Assert(assetRequest.Url != null, "Request url cannot be null"); + assetRequest.State = Progress.InProgress; + + // make sure bundle is loaded + if (BundleLoader.NeedsReload) + yield return BundleLoader.Load(); + + // check for errors + if (BundleLoader.State == Progress.Error) + { + FARLogger.ErrorFormat("Could not load asset bundle {0} for request {1}", + BundleLoader.Url, + assetRequest.Url); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + yield break; + } + + if (!BundleLoader.TryGetAsset(assetRequest.Url, out T asset)) + { + FARLogger.ErrorFormat("Could not find asset {0} in bundle {1}", assetRequest.Url, BundleLoader.Url); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + yield break; + } + + assetRequest.State = Progress.Completed; + assetRequest.OnLoad(asset); + } + + /// + public string Name { get; } = "bundle"; + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleLoader.cs new file mode 100644 index 000000000..841e138ec --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/AssetBundleLoader.cs @@ -0,0 +1,90 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public class AssetBundleLoader : IAssetBundleLoader where T : Object + { + private string url; + + public AssetBundleLoader(string path = "") + { + url = path; + } + + public Dictionary LoadedAssets { get; } = new Dictionary(); + + public bool TryGetAsset(string name, out T asset) + { + return LoadedAssets.TryGetValue(name, out asset); + } + + public string Url + { + get { return url; } + set + { + if (url == value) + return; + NeedsReload = true; + url = value; + } + } + + public Progress State { get; set; } + + public IEnumerator Load() + { + // wait for the other loading to be done + if (State == Progress.InProgress) + { + yield return new WaitWhile(() => State == Progress.InProgress); + yield break; + } + + State = Progress.InProgress; + + // wait for config to be loaded fully + while (FARConfig.IsLoading) + yield return null; + + NeedsReload = false; + + string path = Url; + FARLogger.DebugFormat("Loading asset bundle from {0}", path); + AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(path); + yield return createRequest; + + AssetBundle assetBundle = createRequest.assetBundle; + if (assetBundle == null) + { + FARLogger.Error($"Could not load asset bundle from {path}"); + State = Progress.Error; + yield break; + } + + AssetBundleRequest loadRequest = assetBundle.LoadAllAssetsAsync(); + yield return loadRequest; + + LoadedAssets.Clear(); + foreach (Object asset in loadRequest.allAssets) + { + if (!LoadedAssets.ContainsKey(asset.name)) + if (asset is T t) + LoadedAssets.Add(asset.name, t); + else + FARLogger + .Warning($"Invalid asset type {asset.GetType().ToString()}, expected {typeof(T).ToString()}"); + else + FARLogger.DebugFormat("Asset {0} is duplicated", asset); + } + + FARLogger.DebugFormat("Completed loading assets from {0}", path); + + State = Progress.Completed; + } + + public bool NeedsReload { get; protected set; } = true; + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/AssetRequest.cs b/FerramAerospaceResearch.Base/Resources/Loading/AssetRequest.cs new file mode 100644 index 000000000..025700142 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/AssetRequest.cs @@ -0,0 +1,41 @@ +namespace FerramAerospaceResearch.Resources.Loading +{ + public class AssetRequest : IAssetRequest + { + /// + public void OnLoad(T resource) + { + FARLogger.DebugFormat("Loaded {0} from {1}", resource, Url); + Asset = resource; + AssetLoaded(); + } + + public T Asset { get; private set; } + + /// + public Progress State { get; set; } + + /// + public string Url { get; set; } + + /// + public void OnError() + { + FARLogger.ErrorFormat("Failed to load asset from {0}", Url); + AssetError(); + } + + protected virtual void AssetLoaded() + { + } + + protected virtual void AssetError() + { + } + + public static implicit operator T(AssetRequest request) + { + return request.Asset; + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/IAssetBundleLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/IAssetBundleLoader.cs new file mode 100644 index 000000000..1b59712cd --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/IAssetBundleLoader.cs @@ -0,0 +1,18 @@ +using System.Collections; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public interface IAssetBundleLoader + { + string Url { get; set; } + Progress State { get; } + bool NeedsReload { get; } + IEnumerator Load(); + } + + public interface IAssetBundleLoader : IAssetBundleLoader where T : Object + { + bool TryGetAsset(string name, out T asset); + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/IAssetLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/IAssetLoader.cs new file mode 100644 index 000000000..8ca84e16d --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/IAssetLoader.cs @@ -0,0 +1,15 @@ +using System.Collections; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public interface IAssetLoader + { + // using interface property instead of attribute for possibly stateful loaders + string Name { get; } + } + + public interface IAssetLoader : IAssetLoader + { + IEnumerator Load(IAssetRequest assetRequest); + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/IAssetRequest.cs b/FerramAerospaceResearch.Base/Resources/Loading/IAssetRequest.cs new file mode 100644 index 000000000..4f2bf5659 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/IAssetRequest.cs @@ -0,0 +1,14 @@ +namespace FerramAerospaceResearch.Resources.Loading +{ + public interface IAssetRequest + { + Progress State { get; set; } + string Url { get; } + void OnError(); + } + + public interface IAssetRequest : IAssetRequest + { + void OnLoad(T resource); + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/Progress.cs b/FerramAerospaceResearch.Base/Resources/Loading/Progress.cs new file mode 100644 index 000000000..945cba2df --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/Progress.cs @@ -0,0 +1,10 @@ +namespace FerramAerospaceResearch.Resources.Loading +{ + public enum Progress + { + NotStarted, + InProgress, + Completed, + Error + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/ShaderBundleLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/ShaderBundleLoader.cs new file mode 100644 index 000000000..b655d1496 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/ShaderBundleLoader.cs @@ -0,0 +1,58 @@ +using System; +using FerramAerospaceResearch.Threading; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public class ShaderBundleLoader : AssetBundleLoader + { + private readonly Observable pathValue; + + public ShaderBundleLoader() + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (Application.platform) + { + case RuntimePlatform.LinuxPlayer: + case RuntimePlatform.WindowsPlayer + when SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL", StringComparison.Ordinal): + FARLogger.Info("Shaders will be loaded from Linux bundle"); + //For OpenGL users on Windows we load the Linux shaders to fix OpenGL issues + pathValue = FARConfig.Shaders.BundleLinux; + break; + case RuntimePlatform.WindowsPlayer: + FARLogger.Info("Shaders will be loaded from Windows bundle"); + pathValue = FARConfig.Shaders.BundleWindows; + break; + case RuntimePlatform.OSXPlayer: + FARLogger.Info("Shaders will be loaded from MacOSX bundle"); + pathValue = FARConfig.Shaders.BundleMac; + break; + default: + // Should never reach this + FARLogger.Error($"Invalid runtime platform {Application.platform}"); + break; + } + + Url = pathValue.Value; + pathValue.OnValueChanged += UpdateUrl; + } + + private void UpdateUrl(string url) + { + Url = url; + LoadAssets(); + } + + public void LoadAssets() + { + FARLogger.Info("Loading shader bundle"); + MainThread.StartCoroutine(Load); + } + + public void Unsubscribe() + { + pathValue.OnValueChanged -= UpdateUrl; + } + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/ShaderLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/ShaderLoader.cs new file mode 100644 index 000000000..b7b4905bc --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/ShaderLoader.cs @@ -0,0 +1,32 @@ +using System.Collections; +using UnityEngine; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public class ShaderLoader : IAssetLoader + { + public IEnumerator Load(IAssetRequest assetRequest) + { + assetRequest.State = Progress.InProgress; + + var shader = Shader.Find(assetRequest.Url); + + if (shader == null) + { + FARLogger.DebugFormat("Could not find shader {0}", assetRequest.Url); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + } + else + { + FARLogger.DebugFormat("Found shader {0}", assetRequest.Url); + assetRequest.State = Progress.Completed; + assetRequest.OnLoad(shader); + } + + yield break; + } + + public string Name { get; } = "default"; + } +} diff --git a/FerramAerospaceResearch.Base/Resources/Loading/TextureLoader.cs b/FerramAerospaceResearch.Base/Resources/Loading/TextureLoader.cs new file mode 100644 index 000000000..22127a5c5 --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/Loading/TextureLoader.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Networking; + +namespace FerramAerospaceResearch.Resources.Loading +{ + public class TextureLoader : IAssetLoader + { + // cache loaded textures + private readonly Dictionary loadedTextures = new Dictionary(); + + public IEnumerator Load(IAssetRequest assetRequest) + { + assetRequest.State = Progress.InProgress; + + if (loadedTextures.TryGetValue(assetRequest.Url, out Texture2D texture)) + { + FARLogger.DebugFormat("Using already loaded texture {0}", assetRequest.Url); + assetRequest.State = Progress.Completed; + assetRequest.OnLoad(texture); + yield break; + } + + string path = $@"file:///{PathUtil.Combine(PathUtil.ParentDir, assetRequest.Url)}"; + FARLogger.DebugFormat("Loading texture from {0}", path); + using UnityWebRequest request = UnityWebRequestTexture.GetTexture(path); + yield return request.SendWebRequest(); + + if (!string.IsNullOrEmpty(request.error)) + { + FARLogger.Error($"Error loading texture from {request.url}: {request.error}"); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + } + else + { + FARLogger.DebugFormat("Texture loaded from from {0}", request.url); + Texture2D content = DownloadHandlerTexture.GetContent(request); + loadedTextures.Add(assetRequest.Url, content); + assetRequest.State = Progress.Completed; + assetRequest.OnLoad(content); + } + } + + public string Name { get; } = "default"; + } +} diff --git a/FerramAerospaceResearch.Base/Resources/ShaderPropertyIds.cs b/FerramAerospaceResearch.Base/Resources/ShaderPropertyIds.cs new file mode 100644 index 000000000..b18300caa --- /dev/null +++ b/FerramAerospaceResearch.Base/Resources/ShaderPropertyIds.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace FerramAerospaceResearch.Resources +{ + public static class ShaderPropertyIds + { + public static readonly int Color = Shader.PropertyToID("_Color"); + public static readonly int Cutoff = Shader.PropertyToID("_Cutoff"); + } +} diff --git a/FerramAerospaceResearch.Base/Threading/MainThread.cs b/FerramAerospaceResearch.Base/Threading/MainThread.cs new file mode 100644 index 000000000..dc7619813 --- /dev/null +++ b/FerramAerospaceResearch.Base/Threading/MainThread.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Threading; +using UnityEngine; + +namespace FerramAerospaceResearch.Threading +{ + /// + /// MonoBehaviour object that can be used to run tasks or start coroutines from threads different to the main. + /// + [FARAddon(0, true)] + public class MainThread : MonoSingleton + { + private static readonly ConcurrentQueue routines = new ConcurrentQueue(); + private static readonly ConcurrentQueue tasks = new ConcurrentQueue(); + + public static bool IsMainThread + { + get { return Thread == Thread.CurrentThread; } + } + + public static Thread Thread { get; private set; } + + protected override void OnAwake() + { + // Awake is always called in main thread + Thread = Thread.CurrentThread; + } + + private static void CheckStatus() + { + FARLogger.Assert(Thread != null, "Calling main thread task before initialization"); + } + + /// + /// Run action on the main thread and wait for its execution. + /// + /// Action to run on the main thread + public static Task StartTaskWait(Action action) + { + CheckStatus(); + Task task = StartTask(action); + Wait(task); + return task; + } + + public static CoroutineTask StartCoroutine(Func routine) + { + CheckStatus(); + var task = new CoroutineTask {Action = routine}; + if (IsMainThread) + Instance.ExecuteTask(task); + else + routines.Enqueue(task); + return task; + } + + /// + /// Run action on the main thread. If current thread is main, action is executed immediately, otherwise it is only + /// queued and the method returns. + /// + /// Action to run on the main thread + /// The queued task + public static Task StartTask(Action action) + { + CheckStatus(); + var task = new Task {Action = action}; + + if (IsMainThread) + { + ExecuteTask(task); + return task; + } + + tasks.Enqueue(task); + return task; + } + + public static void Wait(TaskBase task) + { + CheckStatus(); + if (task is null) + return; + + lock (task) + { + while (!task.Executed) + Monitor.Wait(task); + } + } + + public static void ExecuteTask(Task task) + { + try + { + task.Action(); + } + catch (Exception e) + { + FARLogger.Exception(e, "Caught exception while executing task"); + } + + CompleteTask(task); + } + + public void ExecuteTask(CoroutineTask task) + { + try + { + task.Result = StartCoroutine(task.Action()); + } + catch (Exception e) + { + FARLogger.Exception(e, "Caught exception while starting coroutine"); + } + + CompleteTask(task); + } + + private static void CompleteTask(TaskBase task) + { + lock (task) + { + task.Executed = true; + Monitor.PulseAll(task); + } + } + + private void Update() + { + while (tasks.TryDequeue(out Task task)) + ExecuteTask(task); + while (routines.TryDequeue(out CoroutineTask task)) + ExecuteTask(task); + } + + public class TaskBase + { + public volatile bool Executed; + } + + public class Task : TaskBase + { + public Action Action; + } + + public class CoroutineTask : TaskBase + { + public Func Action; + public Coroutine Result; + + public void Cancel() + { + if (Result is null) + return; + + Instance.StopCoroutine(Result); + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Threading/ReaderWriteLockExtensions.cs b/FerramAerospaceResearch.Base/Threading/ReaderWriteLockExtensions.cs new file mode 100644 index 000000000..3da277c22 --- /dev/null +++ b/FerramAerospaceResearch.Base/Threading/ReaderWriteLockExtensions.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading; + +namespace FerramAerospaceResearch.Threading +{ + public static class ReaderWriteLockExtensions + { + /// + /// A simple struct to generate disposable objects for using statements, saves writing try/finally statements everywhere + /// + /// + public readonly struct Disposable : IDisposable + { + private readonly T obj; + private readonly Action exit; + + public Disposable(T obj, Action exit) + { + this.obj = obj; + this.exit = exit; + } + + /// + public void Dispose() + { + exit(obj); + } + } + + public static Disposable DisposableWriteLock(this ReaderWriterLockSlim ls) + { + ls.EnterWriteLock(); + return new Disposable(ls, slim => slim.ExitWriteLock()); + } + + public static Disposable DisposableReadLock(this ReaderWriterLockSlim ls) + { + ls.EnterReadLock(); + return new Disposable(ls, slim => slim.ExitReadLock()); + } + + public static Disposable DisposableUpgradeableReadLock(this ReaderWriterLockSlim ls) + { + ls.EnterUpgradeableReadLock(); + return new Disposable(ls, slim => slim.ExitUpgradeableReadLock()); + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/CsvWriter.cs b/FerramAerospaceResearch.Base/Utils/CsvWriter.cs new file mode 100644 index 000000000..7dc67e14b --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/CsvWriter.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; + +namespace FerramAerospaceResearch +{ + public class CsvWriter : IDisposable + { + private const string Separator = ", "; + + public CsvWriter(string filename) + { + Filename = filename; + } + + public string Filename { get; private set; } + + protected StreamWriter Writer { get; private set; } + public bool Appending { get; private set; } + + public bool IsOpen + { + get { return Writer != null; } + } + + public void Dispose() + { + Writer?.Dispose(); + } + + public void Open() + { + Open(Filename); + } + + public void Open(string filename) + { + Filename = filename; + Appending = File.Exists(filename); + Writer = File.AppendText(filename); + Writer.AutoFlush = false; + } + + public void Close() + { + Writer?.Close(); + Writer?.Dispose(); + Writer = null; + } + + public void Write(T[] values) + { + foreach (T value in values) + Write(value); + } + + public void Write(T value) + { + Writer.Write(value.ToString()); + Writer.Write(Separator); + } + + public void WriteLine(T[] values) + { + Write(values); + Writer.WriteLine(); + } + + public void WriteLine(T value) + { + Write(value); + Writer.WriteLine(); + } + + public void WriteLine() + { + Writer.WriteLine(); + } + + public void Flush() + { + Writer.Flush(); + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/FARLogHandler.cs b/FerramAerospaceResearch.Base/Utils/FARLogHandler.cs new file mode 100644 index 000000000..6b7a4c15b --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/FARLogHandler.cs @@ -0,0 +1,170 @@ +using System; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.Assertions; +using Debug = UnityEngine.Debug; + +namespace FerramAerospaceResearch +{ + // UnityEngine.LogType is weird, Exception is at the wrong end and doesn't have runtime debug level... + public enum LogLevel + { + Trace = 10, + Debug = 20, + Info = 30, + Warning = 40, + Assert = 50, + Error = 60, + Exception = 70 + } + + public class FARLogHandler + { +#if DEBUG + private const LogLevel DefaultLevel = LogLevel.Debug; +#else + private const LogLevel DefaultLevel = LogLevel.Info; +#endif + + public FARLogHandler(LogLevel level = DefaultLevel) + { + Level = level; + } + + public ILogHandler LogHandler { get; } = Debug.unityLogger.logHandler; + public LogLevel Level { get; set; } + + public void Log(LogLevel logLevel, string tag, object message) + { + if (EnabledFor(logLevel)) + LogHandler.LogFormat(Convert(logLevel), null, "{0}: {1}", tag, message); + } + + public void LogTrace(string tag, object message) + { + if (EnabledFor(LogLevel.Trace)) + LogHandler.LogFormat(LogType.Log, null, "{0} trace: {1}", tag, message); + } + + public void LogInfo(string tag, object message) + { + if (EnabledFor(LogLevel.Info)) + LogHandler.LogFormat(LogType.Log, null, "{0}: {1}", tag, message); + } + + public void LogDebug(string tag, object message) + { + if (EnabledFor(LogLevel.Debug)) + LogHandler.LogFormat(LogType.Log, null, "{0} debug: {1}", tag, message); + } + + public void LogWarning(string tag, object message) + { + if (EnabledFor(LogLevel.Warning)) + LogHandler.LogFormat(LogType.Warning, null, "{0}: {1}", tag, message); + } + + public void LogError(string tag, object message) + { + if (EnabledFor(LogLevel.Error)) + LogHandler.LogFormat(LogType.Error, null, "{0}: {1}", tag, message); + } + + public void LogException(Exception exception, string tag, object message) + { + if (!EnabledFor(LogLevel.Exception)) + return; + LogHandler.LogFormat(LogType.Exception, null, "{0}: {1}", tag, message); + LogHandler.LogException(exception, null); + } + + public void LogAssert(bool condition, string tag, object message) + { + if (condition) + return; + + if (EnabledFor(LogLevel.Assert)) + LogHandler.LogFormat(LogType.Assert, null, "{0}: {1}", tag, message); + + // throw an assertion error to match behaviour with assert in other languages + throw new AssertionException("Assertion condition failed", ""); + } + + public void LogFormat(LogLevel logLevel, string tag, string format, params object[] args) + { + if (EnabledFor(logLevel)) + LogHandler.LogFormat(Convert(logLevel), null, "{0}: {1}", tag, string.Format(format, args)); + } + + public void LogTraceFormat(string tag, string format, params object[] args) + { + if (EnabledFor(LogLevel.Trace)) + LogHandler.LogFormat(LogType.Log, null, "{0} trace: {1}", tag, string.Format(format, args)); + } + + public void LogInfoFormat(string tag, string format, params object[] args) + { + if (EnabledFor(LogLevel.Info)) + LogHandler.LogFormat(LogType.Log, null, "{0}: {1}", tag, string.Format(format, args)); + } + + public void LogDebugFormat(string tag, string format, params object[] args) + { + if (EnabledFor(LogLevel.Debug)) + LogHandler.LogFormat(LogType.Log, null, "{0} debug: {1}", tag, string.Format(format, args)); + } + + public void LogWarningFormat(string tag, string format, params object[] args) + { + if (EnabledFor(LogLevel.Warning)) + LogHandler.LogFormat(LogType.Warning, null, "{0}: {1}", tag, string.Format(format, args)); + } + + public void LogErrorFormat(string tag, string format, params object[] args) + { + if (EnabledFor(LogLevel.Error)) + LogHandler.LogFormat(LogType.Error, null, "{0}: {1}", tag, string.Format(format, args)); + } + + public void LogExceptionFormat(Exception exception, string tag, string format, params object[] args) + { + if (!EnabledFor(LogLevel.Exception)) + return; + LogHandler.LogFormat(LogType.Exception, null, "{0}: {1}", tag, string.Format(format, args)); + LogHandler.LogException(exception, null); + } + + public void LogAssertFormat(bool condition, string tag, string format, params object[] args) + { + if (condition) + return; + + if (EnabledFor(LogLevel.Assert)) + LogHandler.LogFormat(LogType.Assert, null, "{0}: {1}", tag, string.Format(format, args)); + + // throw an assertion error to match behaviour with assert in other languages + throw new AssertionException("Assertion condition failed", ""); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool EnabledFor(LogLevel logLevel) + { + return Level <= logLevel; + } + + private static LogType Convert(LogLevel logLevel) + { + return logLevel switch + { + LogLevel.Assert => LogType.Assert, + LogLevel.Debug => LogType.Log, + LogLevel.Error => LogType.Error, + LogLevel.Exception => LogType.Exception, + LogLevel.Info => LogType.Log, + LogLevel.Warning => LogType.Warning, + LogLevel.Trace => LogType.Log, + _ => throw new ArgumentException("Should never reach here") + }; + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/FARLogger.cs b/FerramAerospaceResearch.Base/Utils/FARLogger.cs new file mode 100644 index 000000000..b2acce265 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/FARLogger.cs @@ -0,0 +1,191 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + public static class FARLogger + { + public const string DefaultExceptionMessage = "Logged exception:"; + public static readonly FARLogHandler LogHandler = new FARLogHandler(); + public static readonly string Tag = $"[FAR {Version.ShortString}]"; + + // force set log level on initialization by looking at files next to plugins + private static readonly Regex logLevelRegex = + new Regex(@"FARLogger_(\w+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + static FARLogger() + { + SetupLevel(); + LogHandler.LogHandler.LogFormat(LogType.Log, null, "{0}: Using {1} log level", Tag, Level); + } + + public static LogLevel Level + { + get { return LogHandler.Level; } + set { LogHandler.Level = value; } + } + + public static bool IsEnabledFor(LogLevel level) + { + return LogHandler.EnabledFor(level); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Info(object message) + { + LogHandler.LogInfo(Tag, message); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Debug(object message) + { + LogHandler.LogDebug(Tag, message); + } + + [Conditional("LOG_TRACE"), MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Trace(object message) + { + LogHandler.LogTrace(Tag, message); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Warning(object message) + { + LogHandler.LogWarning(Tag, message); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Error(object message) + { + LogHandler.LogError(Tag, message); + } + + [Conditional("ASSERT")] + public static void Assert( + bool condition, + object message, + [CallerMemberName] + string memberName = "", + [CallerFilePath] + string filePath = "", + [CallerLineNumber] + int lineNumber = 0 + ) + { + LogHandler.LogAssertFormat(condition, + Tag, + "{2}({3}): {1}: {0}", + message, + memberName, + filePath, + lineNumber.ToString()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Exception(Exception exception, object message = null) + { + LogHandler.LogException(exception, Tag, message ?? DefaultExceptionMessage); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void InfoFormat(string format, params object[] args) + { + LogHandler.LogInfoFormat(Tag, format, args); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void DebugFormat(string format, params object[] args) + { + LogHandler.LogDebugFormat(Tag, format, args); + } + + [Conditional("LOG_TRACE"), MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void TraceFormat(string format, params object[] args) + { + LogHandler.LogTraceFormat(Tag, format, args); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WarningFormat(string format, params object[] args) + { + LogHandler.LogWarningFormat(Tag, format, args); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ErrorFormat(string format, params object[] args) + { + LogHandler.LogErrorFormat(Tag, format, args); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining), Conditional("ASSERT")] + public static void AssertFormat( + bool condition, + string format, + [CallerMemberName] + string memberName = "", + [CallerFilePath] + string filePath = "", + [CallerLineNumber] + int lineNumber = 0, + params object[] args + ) + { + // ReSharper disable ExplicitCallerInfoArgument + Assert(condition, string.Format(format, args), memberName, filePath, lineNumber); + // ReSharper restore ExplicitCallerInfoArgument + } + + [MethodImpl(MethodImplOptions.AggressiveInlining), Conditional("ASSERT")] + public static void AssertFormat(bool condition, string format, SourceInfo source, params object[] args) + { + // ReSharper disable ExplicitCallerInfoArgument + Assert(condition, string.Format(format, args), source.MemberName, source.FilePath, source.LineNumber); + // ReSharper restore ExplicitCallerInfoArgument + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ExceptionFormat(Exception exception, string format, params object[] args) + { + LogHandler.LogExceptionFormat(exception, Tag, format, args); + } + + private static void SetupLevel() + { + LogLevel level = LogLevel.Assert; + + bool exists = false; + string[] files = Directory.GetFiles(PathUtil.PluginsDir); + + foreach (string file in files) + { + Match match = logLevelRegex.Match(Path.GetFileNameWithoutExtension(file)); + if (!match.Success) + { + DebugFormat("{0} did not match the regex pattern {1}", file, logLevelRegex); + continue; + } + + if (Enum.TryParse(match.Groups[1].Value, true, out LogLevel l)) + { + exists = true; + if (l < level) + level = l; + DebugFormat("Matched {0} to {1}", file, level); + } + else + { + Warning($"Unknown level name {match.Value}"); + } + } + + if (!exists) + return; + + Level = level; + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/FARUtils.cs b/FerramAerospaceResearch.Base/Utils/FARUtils.cs new file mode 100644 index 000000000..f786ca3cf --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/FARUtils.cs @@ -0,0 +1,48 @@ +using System; + +namespace FerramAerospaceResearch +{ + public static class FARUtils + { + public static bool ValuesEqual(T a, T b) + { + return a switch + { + IComparable comparable => (comparable.CompareTo(b) == 0), + IEquatable equatable => equatable.Equals(b), + null => b is null, + IComparable comparable => (comparable.CompareTo(b) == 0), + _ => a.Equals(b) + }; + } + + public static bool ValuesEqual(object a, T b) + { + return a switch + { + IComparable comparable => (comparable.CompareTo(b) == 0), + IEquatable equatable => equatable.Equals(b), + null => b is null, + IComparable comparable => (comparable.CompareTo(b) == 0), + _ => a.Equals(b) + }; + } + + public static bool ValuesEqual(object a, object b) + { + return a switch + { + IComparable comparable => (comparable.CompareTo(b) == 0), + null => b is null, + _ => a.Equals(b) + }; + } + + public static void Swap(ref T a, ref T b) + { + T c = b; + b = a; + a = c; + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/MonoSingleton.cs b/FerramAerospaceResearch.Base/Utils/MonoSingleton.cs new file mode 100644 index 000000000..617be2022 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/MonoSingleton.cs @@ -0,0 +1,90 @@ +using UnityEngine; + +// ReSharper disable StaticMemberInGenericType - + +namespace FerramAerospaceResearch +{ + /// + /// Inherit from this base class to create a singleton. + /// e.g. public class MyClassName : MonoSingleton<MyClassName> {} + /// + public class MonoSingleton : MonoBehaviour where T : MonoBehaviour + { + // Check to see if we're about to be destroyed. + private static bool shuttingDown; + + private static bool created; + private static T instance; + private bool destroyingDuplicate; + + /// + /// Access singleton instance through this propriety. + /// + public static T Instance + { + get + { + if (shuttingDown) + { + FARLogger.Warning($"[MonoSingleton] Instance '{typeof(T)}' already destroyed. Returning null."); + return null; + } + + if (created) + return instance; + + // Need to create a new GameObject to attach the singleton to. + var singletonObject = new GameObject($"{typeof(T).ToString()} (MonoSingleton)"); + singletonObject.AddComponent(); + + // Make instance persistent. + DontDestroyOnLoad(singletonObject); + created = true; + + return instance; + } + } + + private void Awake() + { + if (instance == null) + { + FARLogger.Debug($"MonoSingleton {this} is awake"); + instance = this as T; + OnAwake(); + } + + else + { + FARLogger.Trace($"{this} is a MonoSingleton but an instance already exists, destroying self"); + destroyingDuplicate = true; + Destroy(this); + } + } + + protected virtual void OnAwake() + { + } + + protected virtual void OnApplicationQuit() + { + shuttingDown = true; + } + + protected void OnDestroy() + { + if (!destroyingDuplicate) + { + shuttingDown = true; + OnDestruct(); + instance = null; + } + + destroyingDuplicate = false; + } + + protected virtual void OnDestruct() + { + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/Observable.cs b/FerramAerospaceResearch.Base/Utils/Observable.cs new file mode 100644 index 000000000..cc16ad6a5 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/Observable.cs @@ -0,0 +1,73 @@ +using System; +using FerramAerospaceResearch.Interfaces; + +namespace FerramAerospaceResearch +{ + public class Observable : Interfaces.IObservable, IConfigValue + { + private T value; + + public Observable(T v = default, Func transform = null) + { + Transform = transform; + value = transform == null ? v : transform(v); + } + + public Func Transform { get; } + + public void Set(object v) + { + if (v is T val) + Set(val); + } + + public T Get() + { + return Value; + } + + public void Set(T v) + { + Value = v; + } + + object IConfigValue.Get() + { + return Get(); + } + + public T Value + { + get { return value; } + set + { + value = Transform == null ? value : Transform(value); + + if (FARUtils.ValuesEqual(this.value, value)) + return; + + this.value = value; + OnValueChanged?.Invoke(value); + } + } + + object IObservable.Value + { + get { return Value; } + set + { + if (value is T val) + Value = val; + else + FARLogger.Assert(false, $"Value {value.ToString()} is not of type {typeof(T).ToString()}"); + } + } + + public event Action OnValueChanged; + + public static implicit operator T(Observable o) + { + return o.Value; + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/Pair.cs b/FerramAerospaceResearch.Base/Utils/Pair.cs new file mode 100644 index 000000000..7da3983af --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/Pair.cs @@ -0,0 +1,23 @@ +namespace FerramAerospaceResearch +{ + public readonly struct Pair + { + public readonly Ta First; + public readonly Tb Second; + + public Pair(Ta first, Tb second) + { + First = first; + Second = second; + } + } + + public static class Pair + { + // use type deduction to save on writing parameters every time + public static Pair Create(Tx first, Ty second) + { + return new Pair(first, second); + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/PathUtil.cs b/FerramAerospaceResearch.Base/Utils/PathUtil.cs new file mode 100644 index 000000000..3ad2131c6 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/PathUtil.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch +{ + public static class PathUtil + { + public const string ModDirectoryName = "FerramAerospaceResearch"; + + public static string PluginsDir { get; } = + AbsPath(Path.Combine(ReflectionUtils.ExecutingAssembly.Location, "..")); + + public static string RootDir { get; } = AbsPath(Path.Combine(PluginsDir, "..")); + public static string AssetsDir { get; } = AbsPath(Path.Combine(RootDir, "Assets")); + public static string TexturesDir { get; } = AbsPath(Path.Combine(RootDir, "Textures")); + public static string ParentDir { get; } = AbsPath(Path.Combine(RootDir, "..")); + public static string PParentDir { get; } = AbsPath(Path.Combine(ParentDir, "..")); + + public static string AbsPath(string path) + { + // C# works with either '/' or '\' but KSP will serialise '\\' as '\' and parsing will fail + return Path.GetFullPath(path).Replace("\\", "/"); + } + + public static string Combine(string path, string filename) + { + return IsAbsolute(filename) ? filename : Path.Combine(path, filename); + } + + public static string Combine(string path, string dir1, string filename) + { + return IsAbsolute(filename) ? filename : Path.Combine(path, dir1, filename); + } + + public static string Combine(string path, string dir1, string dir2, string filename) + { + return IsAbsolute(filename) ? filename : Path.Combine(path, dir1, dir2, filename); + } + + public static string Combine(params string[] paths) + { + return IsAbsolute(paths[paths.Length - 1]) ? paths[paths.Length - 1] : Path.Combine(paths); + } + + public static Func CombineDelegate(string root) + { + return s => AbsPath(Combine(root, s)); + } + + public static Func CombineDelegate2(string root) + { + return (d, s) => AbsPath(Combine(root, d, s)); + } + + public static Func CombineDelegate3(string root) + { + return (d1, d2, s) => AbsPath(Combine(root, d1, d2, s)); + } + + public static bool IsAbsolute(string path, bool retry = true) + { + try + { + return Path.IsPathRooted(path); + } + catch (ArgumentException e) + { + if (retry) + { + FARLogger.Warning($"Invalid path: {path}, retrying"); + return IsAbsolute(path.Replace("\\", "/"), false); + } + + FARLogger.Exception(e, $"Exception in path: {path}"); + throw; + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/Singleton.cs b/FerramAerospaceResearch.Base/Utils/Singleton.cs new file mode 100644 index 000000000..8760b79b4 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/Singleton.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading; + +namespace FerramAerospaceResearch +{ + /// + /// Inherit from this base class to create a singleton. + /// e.g. public class MyClassName : Singleton<MyClassName> {} + /// + public class Singleton where T : class + { + // ReSharper disable once StaticMemberInGenericType + private static readonly object locker = new object(); + private static volatile T instance; + + protected Singleton() + { + if (instance == null) + { + FARLogger.DebugFormat("Singleton {0} is created", this); + } + else + { + FARLogger.TraceFormat("{0} is a Singleton but an instance already exists", this); + } + } + + /// + /// Access singleton instance through this property. + /// + public static T Instance + { + get + { + if (instance != null) + return instance; + + lock (locker) + { + return instance ??= Activator.CreateInstance(typeof(T), true) as T; + } + } + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/SourceInfo.cs b/FerramAerospaceResearch.Base/Utils/SourceInfo.cs new file mode 100644 index 000000000..d0c56d56b --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/SourceInfo.cs @@ -0,0 +1,57 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace FerramAerospaceResearch +{ + public readonly struct SourceInfo + { + public readonly string MemberName; + public readonly string FilePath; + public readonly int LineNumber; + + private SourceInfo(string memberName, string filePath, int lineNumber) + { + MemberName = memberName; + FilePath = filePath; + LineNumber = lineNumber; + } + + public static SourceInfo Current( + [CallerMemberName] + string memberName = "", + [CallerFilePath] + string filePath = "", + [CallerLineNumber] + int lineNumber = 0 + ) + { + return new SourceInfo(memberName, filePath, lineNumber); + } + + public static SourceInfo Current(int depth) + { + // frame 0 - Current + // frame 1 - caller method + var frame = new StackFrame(depth + 1, true); + string method = frame.GetMethod().Name; + // release mode doesn't have debug symbols +#if DEBUG + string fileName = frame.GetFileName(); + int lineNumber = frame.GetFileLineNumber(); + + return new SourceInfo(method, fileName, lineNumber); +#else + return new SourceInfo(method, "", -1); +#endif + } + + public override string ToString() + { +#if DEBUG + return $"{FilePath}:{LineNumber.ToString()} - {MemberName}"; +#else + return MemberName; +#endif + } + } +} diff --git a/FerramAerospaceResearch.Base/Utils/StringFormatter.cs b/FerramAerospaceResearch.Base/Utils/StringFormatter.cs new file mode 100644 index 000000000..a0742aa27 --- /dev/null +++ b/FerramAerospaceResearch.Base/Utils/StringFormatter.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Text; +using FerramAerospaceResearch.Interfaces; + +namespace FerramAerospaceResearch +{ + public class StringFormatter : IConfigValue + { + private const string LeftBrace = "<<<"; + private const string RightBrace = ">>>"; + + private readonly List fields = new List(); + private readonly StringBuilder stringBuilder = new StringBuilder(); + private string formatString; + + public StringFormatter(string formatString) + { + Parse(formatString); + } + + public string FormatString + { + get { return formatString; } + set { Parse(value); } + } + + public void Set(object value) + { + if (value is string str) + Set(str); + } + + public string Get() + { + return FormatString; + } + + public void Set(string value) + { + FormatString = value; + } + + object IConfigValue.Get() + { + return Get(); + } + + public void Parse(string str) + { + fields.Clear(); + formatString = str; + + int begin = 0; + while (begin < str.Length) + { + int replaceBegin = str.IndexOf(LeftBrace, begin, StringComparison.Ordinal); + + // no replacements found + if (replaceBegin < 0) + { + fields.Add(new Field + { + Type = FieldType.Text, + Str = str.Substring(begin, str.Length - begin) + }); + break; + } + + int paramBegin = replaceBegin + LeftBrace.Length; + int paramEnd = str.IndexOf(RightBrace, paramBegin, StringComparison.Ordinal); + // no closing brace found + if (paramEnd < 0) + { + fields.Add(new Field + { + Type = FieldType.Text, + Str = str.Substring(begin, str.Length - begin) + }); + break; + } + + // found braced parameter + fields.Add(new Field + { + Type = FieldType.Text, + Str = str.Substring(begin, replaceBegin - begin) + }); + + fields.Add(new Field + { + Type = FieldType.Replacement, + Str = str.Substring(paramBegin, paramEnd - paramBegin) + }); + + begin = paramEnd + RightBrace.Length; + } + } + + public string ToString(StringBuilder sb, Dictionary replacements) + { + sb.Clear(); + foreach (Field field in fields) + { + if (field.Type == FieldType.Text) + sb.Append(field.Str); + else if (replacements.TryGetValue(field.Str, out object o)) + sb.Append(o.ToString()); + else + { + sb.Append(LeftBrace); + sb.Append(field.Str); + sb.Append(RightBrace); + } + } + + return sb.ToString(); + } + + public string ToString(Dictionary replacements) + { + return ToString(stringBuilder, replacements); + } + + public override string ToString() + { + return FormatString; + } + + private enum FieldType + { + Text, + Replacement + } + + private struct Field + { + public FieldType Type; + public string Str; + } + } +} diff --git a/FerramAerospaceResearch.Base/Version.cs b/FerramAerospaceResearch.Base/Version.cs new file mode 100644 index 000000000..766a91ddd --- /dev/null +++ b/FerramAerospaceResearch.Base/Version.cs @@ -0,0 +1,22 @@ +namespace FerramAerospaceResearch +{ + public class Version + { + // using byte here because 0-255 should be enough for any version number + public const byte Major = 0; + public const byte Minor = 16; + public const byte Build = 0; + public const byte Revision = 0; + public const string Name = "Mader"; + + /// + /// String of the numerical version + /// + public static readonly string ShortString = $"v{Major}.{Minor}.{Build}.{Revision}"; + + /// + /// String of the numerical version with name + /// + public static readonly string LongString = $"{ShortString} '{Name}'"; + } +} diff --git a/FerramAerospaceResearch.sln b/FerramAerospaceResearch.sln index 4a99fc2d6..4a3c8e81e 100644 --- a/FerramAerospaceResearch.sln +++ b/FerramAerospaceResearch.sln @@ -15,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FerramAerospaceResearch.Base", "FerramAerospaceResearch.Base\FerramAerospaceResearch.Base.csproj", "{8E4E9138-A949-4DED-A08C-4CE3442887B4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,6 +31,10 @@ Global {0CE2D15F-3EC2-4DC0-B35F-D9F7B18169BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {0CE2D15F-3EC2-4DC0-B35F-D9F7B18169BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {0CE2D15F-3EC2-4DC0-B35F-D9F7B18169BE}.Release|Any CPU.Build.0 = Release|Any CPU + {8E4E9138-A949-4DED-A08C-4CE3442887B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E4E9138-A949-4DED-A08C-4CE3442887B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E4E9138-A949-4DED-A08C-4CE3442887B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E4E9138-A949-4DED-A08C-4CE3442887B4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FerramAerospaceResearch/FARAPI.cs b/FerramAerospaceResearch/FARAPI.cs index ac3c0e7cf..93ae19406 100644 --- a/FerramAerospaceResearch/FARAPI.cs +++ b/FerramAerospaceResearch/FARAPI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using ferram4; using FerramAerospaceResearch.FARAeroComponents; using FerramAerospaceResearch.FARGUI.FARFlightGUI; -using FerramAerospaceResearch.FARUtils; using UnityEngine; // ReSharper disable UnusedMember.Global @@ -54,7 +53,7 @@ namespace FerramAerospaceResearch { public static class FARAPI { - public static FARVersion Version { get; } = new FARVersion(); + public static Version Version { get; } = new Version(); /// /// Toggle or enable/disable FAR speed display. @@ -224,7 +223,7 @@ public static void VesselIncreaseFlapDeflection(Vessel v) { if (!p.Modules.Contains()) continue; - var surface = p.Modules.GetModule(); + FARControllableSurface surface = p.Modules.GetModule(); surface.SetDeflection(surface.flapDeflectionLevel + 1); } } @@ -238,7 +237,7 @@ public static void VesselDecreaseFlapDeflection(Vessel v) { if (!p.Modules.Contains()) continue; - var surface = p.Modules.GetModule(); + FARControllableSurface surface = p.Modules.GetModule(); surface.SetDeflection(surface.flapDeflectionLevel - 1); } } @@ -254,7 +253,7 @@ public static int VesselFlapSetting(Vessel v) { if (!p.Modules.Contains()) continue; - var surface = p.Modules.GetModule(); + FARControllableSurface surface = p.Modules.GetModule(); if (surface.isFlap) return surface.flapDeflectionLevel; } @@ -271,7 +270,7 @@ public static void VesselSetSpoilers(Vessel v, bool spoilerActive) { if (!p.Modules.Contains()) continue; - var surface = p.Modules.GetModule(); + FARControllableSurface surface = p.Modules.GetModule(); surface.brake = spoilerActive; } } @@ -287,7 +286,7 @@ public static bool VesselSpoilerSetting(Vessel v) { if (!p.Modules.Contains()) continue; - var surface = p.Modules.GetModule(); + FARControllableSurface surface = p.Modules.GetModule(); if (surface.isSpoiler) return surface.brake; } @@ -359,7 +358,7 @@ double altitude return; } - var vesselAero = vessel.GetComponent(); + FARVesselAero vesselAero = vessel.GetComponent(); if (vesselAero == null) { diff --git a/FerramAerospaceResearch/FARAeroComponents/DummyAirstreamShield.cs b/FerramAerospaceResearch/FARAeroComponents/DummyAirstreamShield.cs new file mode 100644 index 000000000..a73ae56b1 --- /dev/null +++ b/FerramAerospaceResearch/FARAeroComponents/DummyAirstreamShield.cs @@ -0,0 +1,25 @@ +namespace FerramAerospaceResearch.FARAeroComponents +{ + public sealed class DummyAirstreamShield : IAirstreamShield + { + /// + public bool ClosedAndLocked() + { + return true; + } + + public Part part; + + /// + public Vessel GetVessel() + { + return part.vessel; + } + + /// + public Part GetPart() + { + return part; + } + } +} diff --git a/FerramAerospaceResearch/FARAeroComponents/FARAeroPartModule.cs b/FerramAerospaceResearch/FARAeroComponents/FARAeroPartModule.cs index 3b0f9b5d0..4bcbf6dee 100644 --- a/FerramAerospaceResearch/FARAeroComponents/FARAeroPartModule.cs +++ b/FerramAerospaceResearch/FARAeroComponents/FARAeroPartModule.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,11 +45,11 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using ferram4; -using FerramAerospaceResearch.FARGUI; using FerramAerospaceResearch.FARGUI.FAREditorGUI; using FerramAerospaceResearch.FARGUI.FARFlightGUI; using FerramAerospaceResearch.FARPartGeometry; using FerramAerospaceResearch.RealChuteLite; +using FerramAerospaceResearch.Settings; using KSP.Localization; using UnityEngine; @@ -88,22 +88,24 @@ public class FARAeroPartModule : PartModule, ILiftProvider private ArrowPointer dragArrow; private ArrowPointer momentArrow; + private DummyAirstreamShield shield; + private bool fieldsVisible; // ReSharper disable once NotAccessedField.Global -> unity [KSPField(isPersistant = false, - guiActive = false, - guiActiveEditor = false, - guiFormat = "F3", - guiUnits = "FARUnitKN")] + guiActive = false, + guiActiveEditor = false, + guiFormat = "F3", + guiUnits = "FARUnitKN")] public float dragForce; // ReSharper disable once NotAccessedField.Global -> unity [KSPField(isPersistant = false, - guiActive = false, - guiActiveEditor = false, - guiFormat = "F3", - guiUnits = "FARUnitKN")] + guiActive = false, + guiActiveEditor = false, + guiFormat = "F3", + guiUnits = "FARUnitKN")] public float liftForce; private Transform partTransform; @@ -144,7 +146,12 @@ public void SetShielded(bool value) { part.ShieldedFromAirstream = value; if (!value) + { + part.RemoveShield(shield); return; + } + + part.AddShield(shield); worldSpaceAeroForce = Vector3.zero; worldSpaceTorque = Vector3.zero; @@ -180,12 +187,8 @@ public void SetProjectedArea(ProjectedArea areas, Matrix4x4 vesselToWorldMatrix) Matrix4x4 transformMatrix = part.partTransform.worldToLocalMatrix * vesselToWorldMatrix; - IncrementAreas(ref transformedArea, (float)areas.iP * Vector3.right, transformMatrix); - IncrementAreas(ref transformedArea, (float)areas.iN * -Vector3.right, transformMatrix); - IncrementAreas(ref transformedArea, (float)areas.jP * Vector3.up, transformMatrix); - IncrementAreas(ref transformedArea, (float)areas.jN * -Vector3.up, transformMatrix); - IncrementAreas(ref transformedArea, (float)areas.kP * Vector3.forward, transformMatrix); - IncrementAreas(ref transformedArea, (float)areas.kN * -Vector3.forward, transformMatrix); + for (int i = 0; i < 6; i++) + IncrementAreas(ref transformedArea, (float)areas[i] * ProjectedArea.FaceDirections[i], transformMatrix); projectedArea = transformedArea; projectedArea.totalArea = projectedArea.iN + @@ -198,6 +201,7 @@ public void SetProjectedArea(ProjectedArea areas, Matrix4x4 vesselToWorldMatrix) if (projectedArea.totalArea <= 0) { part.ShieldedFromAirstream = true; + part.AddShield(shield); if (fieldsVisible) { Fields["dragForce"].guiActive = false; @@ -226,6 +230,7 @@ public void SetProjectedArea(ProjectedArea areas, Matrix4x4 vesselToWorldMatrix) else { part.ShieldedFromAirstream = false; + part.RemoveShield(shield); } double areaForStress = projectedArea.totalArea / 6; @@ -265,6 +270,8 @@ private static void IncrementAreas(ref ProjectedArea data, Vector3 vector, Matri private void Start() { + shield = new DummyAirstreamShield {part = part}; + if (waterSlowDragNew < 0) { waterSlowDragNew = PhysicsGlobals.BuoyancyWaterDragSlow; @@ -287,8 +294,8 @@ private void Start() if (FARDebugValues.allowStructuralFailures && !partStressOverride) { FARPartStressTemplate template = FARAeroStress.DetermineStressTemplate(part); - partStressMaxY = template.YmaxStress; - partStressMaxXZ = template.XZmaxStress; + partStressMaxY = template.YMaxStress; + partStressMaxXZ = template.XZMaxStress; } partTransform = part.partTransform; @@ -574,7 +581,7 @@ private void ApplyAeroStressFailure() bool failureOccured = false; if (part.Modules.Contains()) { - var fairing = part.Modules.GetModule(); + ModuleProceduralFairing fairing = part.Modules.GetModule(); fairing.ejectionForce = 0.5f; fairing.DeployFairing(); @@ -629,7 +636,7 @@ private void UpdateAeroDisplay() worldLiftArrow, worldLiftArrow.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale, - GUIColors.GetColor(0), + FARConfig.GUIColors.ClColor, true); } else @@ -645,7 +652,7 @@ private void UpdateAeroDisplay() worldDragArrow, worldDragArrow.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale, - GUIColors.GetColor(1), + FARConfig.GUIColors.CdColor, true); } else @@ -663,7 +670,7 @@ private void UpdateAeroDisplay() worldSpaceTorque, worldSpaceTorque.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale, - GUIColors.GetColor(2), + FARConfig.GUIColors.CmColor, true); } else @@ -725,11 +732,11 @@ public override void OnLoad(ConfigNode node) FARPartStressTemplate defaultTemplate = FARAeroStress.DetermineStressTemplate(part); if (stressTemplate.HasValue("YmaxStress")) if (!double.TryParse(stressTemplate.GetValue("YmaxStress"), out partStressMaxY)) - partStressMaxY = defaultTemplate.YmaxStress; + partStressMaxY = defaultTemplate.YMaxStress; // ReSharper disable once InvertIf if (stressTemplate.HasValue("XZmaxStress")) if (!double.TryParse(stressTemplate.GetValue("XZmaxStress"), out partStressMaxXZ)) - partStressMaxXZ = defaultTemplate.XZmaxStress; + partStressMaxXZ = defaultTemplate.XZMaxStress; } private void OnDestroy() @@ -758,11 +765,47 @@ private void OnDestroy() public struct ProjectedArea { - public double iN, iP; //area in x direction - public double jN, jP; //area in y direction - public double kN, kP; //area in z direction + public double iP, iN; //area in x direction + public double jP, jN; //area in y direction + public double kP, kN; //area in z direction public double totalArea; + public static readonly Vector3d[] FaceDirections = + { + Vector3d.right, Vector3d.left, Vector3d.up, Vector3d.down, Vector3d.forward, Vector3d.back + }; + + // a map onto stock cube faces, adds a bit of robustness when mapping from ProjectedAreas to drag cubes faces arrays + public static readonly int[] FaceMap = + { + (int)DragCube.DragFace.XP, + (int)DragCube.DragFace.XN, + (int)DragCube.DragFace.YP, + (int)DragCube.DragFace.YN, + (int)DragCube.DragFace.ZP, + (int)DragCube.DragFace.ZN + }; + + // since this is POD struct, use pointer casting for quick indexed access + public unsafe double this[int index] + { + get + { + FARLogger.Assert(index < 7, "Index out of bounds"); + fixed (ProjectedArea* areas = &this) + { + return ((double*)areas)[index]; + } + } + set + { + FARLogger.Assert(index < 7, "Index out of bounds"); + fixed (ProjectedArea* areas = &this) + { + ((double*)areas)[index] = value; + } + } + } public static ProjectedArea operator +(ProjectedArea a, ProjectedArea b) { diff --git a/FerramAerospaceResearch/FARAeroComponents/FARAeroSection.cs b/FerramAerospaceResearch/FARAeroComponents/FARAeroSection.cs index 03e4cd8aa..593ab28de 100644 --- a/FerramAerospaceResearch/FARAeroComponents/FARAeroSection.cs +++ b/FerramAerospaceResearch/FARAeroComponents/FARAeroSection.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARAeroComponents/FARVesselAero.cs b/FerramAerospaceResearch/FARAeroComponents/FARVesselAero.cs index 72d4baec7..00923e357 100644 --- a/FerramAerospaceResearch/FARAeroComponents/FARVesselAero.cs +++ b/FerramAerospaceResearch/FARAeroComponents/FARVesselAero.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -47,7 +47,6 @@ You should have received a copy of the GNU General Public License using FerramAerospaceResearch.FARGUI.FARFlightGUI; using FerramAerospaceResearch.FARPartGeometry; using FerramAerospaceResearch.FARThreading; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARAeroComponents @@ -111,7 +110,7 @@ protected override void OnStart() p.minimum_drag = 0; p.angularDrag = 0; - var g = p.GetComponent(); + GeometryPartModule g = p.GetComponent(); if (!(g is null)) { _currentGeoModules.Add(g); @@ -135,7 +134,7 @@ protected override void OnStart() private PartModule.StartState StartState() { - var startState = PartModule.StartState.None; + PartModule.StartState startState = PartModule.StartState.None; if (HighLogic.LoadedSceneIsEditor) startState |= PartModule.StartState.Editor; else if (HighLogic.LoadedSceneIsFlight) @@ -227,8 +226,8 @@ private void CalculateAndApplyVesselAeroProperties() vessel.srfSpeed, MachNumber, FlightGlobals.getExternalTemperature((float)vessel - .altitude, - vessel.mainBody), + .altitude, + vessel.mainBody), vessel.mainBody.atmosphereAdiabaticIndex); float skinFrictionDragCoefficient = (float)FARAeroUtil.SkinFrictionDrag(ReynoldsNumber, MachNumber); @@ -308,7 +307,7 @@ double altitude center); foreach (FARWingAerodynamicModel curWing in _legacyWingModels) - if (!(curWing is null)) + if (curWing != null) center.AddForce(curWing.transform.position, curWing.PrecomputeCenterOfLift(velocityWorldVector, machNumber, @@ -409,7 +408,7 @@ public void VesselUpdate(bool recalcGeoModules) geoModulesReady = 0; foreach (Part p in vessel.Parts) { - var g = p.Modules.GetModule(); + GeometryPartModule g = p.Modules.GetModule(); if (g is null) continue; _currentGeoModules.Add(g); diff --git a/FerramAerospaceResearch/FARAeroComponents/FlightForceContext.cs b/FerramAerospaceResearch/FARAeroComponents/FlightForceContext.cs index eef2ed560..37328e156 100644 --- a/FerramAerospaceResearch/FARAeroComponents/FlightForceContext.cs +++ b/FerramAerospaceResearch/FARAeroComponents/FlightForceContext.cs @@ -1,7 +1,7 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= -Copyright 2019, Benjamin Chung, aka BenChung +Copyright 2020, Benjamin Chung, aka BenChung This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARAeroComponents/ModularFlightIntegratorRegisterer.cs b/FerramAerospaceResearch/FARAeroComponents/ModularFlightIntegratorRegisterer.cs index 93eed88ff..955f3ee2b 100644 --- a/FerramAerospaceResearch/FARAeroComponents/ModularFlightIntegratorRegisterer.cs +++ b/FerramAerospaceResearch/FARAeroComponents/ModularFlightIntegratorRegisterer.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,7 +43,7 @@ You should have received a copy of the GNU General Public License */ using System; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Settings; using ModularFI; using UnityEngine; @@ -57,7 +57,7 @@ private void Start() FARLogger.Info("Modular Flight Integrator function registration started"); ModularFlightIntegrator.RegisterUpdateAerodynamicsOverride(UpdateAerodynamics); ModularFlightIntegrator.RegisterUpdateThermodynamicsPre(UpdateThermodynamicsPre); - ModularFlightIntegrator.RegisterCalculateAreaExposedOverride(CalculateAreaRadiative); + ModularFlightIntegrator.RegisterCalculateAreaExposedOverride(CalculateAreaExposed); ModularFlightIntegrator.RegisterCalculateAreaRadiativeOverride(CalculateAreaRadiative); ModularFlightIntegrator.RegisterGetSunAreaOverride(CalculateSunArea); ModularFlightIntegrator.RegisterGetBodyAreaOverride(CalculateBodyArea); @@ -74,13 +74,19 @@ private static void UpdateThermodynamicsPre(ModularFlightIntegrator fi) if (!part.Modules.Contains()) continue; - var aeroModule = part.Modules.GetModule(); + FARAeroPartModule aeroModule = part.Modules.GetModule(); + + // make sure drag cube areas are correct based on voxelization + if (!part.DragCubes.None && aeroModule) + for (int j = 0; j < 6; j++) + part.DragCubes.AreaOccluded[FARAeroPartModule.ProjectedArea.FaceMap[j]] = + (float)aeroModule.ProjectedAreas[j]; part.radiativeArea = CalculateAreaRadiative(fi, part, aeroModule); part.exposedArea = part.machNumber > 0 ? CalculateAreaExposed(fi, part, aeroModule) : part.radiativeArea; - if (part.exposedArea > part.radiativeArea) + if (FARSettings.ExposedAreaLimited && part.exposedArea > part.radiativeArea) part.exposedArea = part.radiativeArea; //sanity check just in case } } @@ -117,8 +123,10 @@ private static void UpdateAerodynamics(ModularFlightIntegrator fi, Part part) CalculateLocalDynPresAndAngularDrag(fi, part); } - if (!part.DragCubes.None) - part.DragCubes.SetDrag(part.dragVectorDirLocal, (float)fi.mach); + if (part.DragCubes.None) + return; + + part.DragCubes.SetDrag(part.dragVectorDirLocal, (float)fi.mach); } } @@ -179,8 +187,7 @@ FARAeroPartModule aeroModule return radArea > 0 ? radArea : fi.BaseFICalculateAreaRadiative(part); } - // ReSharper disable once UnusedMember.Local - private double CalculateAreaExposed(ModularFlightIntegrator fi, Part part) + private static double CalculateAreaExposed(ModularFlightIntegrator fi, Part part) { FARAeroPartModule module = null; if (part.Modules.Contains()) @@ -193,7 +200,12 @@ private static double CalculateAreaExposed(ModularFlightIntegrator fi, Part part { if (aeroModule is null) return fi.BaseFICalculateAreaExposed(part); - double exposedArea = aeroModule.ProjectedAreaLocal(-part.dragVectorDirLocal); + + // Apparently stock exposed area is actually weighted by some function of mach number... + // otherwise heating is much lower + double exposedArea = FARSettings.ExposedAreaUsesKSPHack + ? part.DragCubes.ExposedArea + : aeroModule.ProjectedAreaLocal(-part.dragVectorDirLocal); return exposedArea > 0 ? exposedArea : fi.BaseFICalculateAreaExposed(part); } diff --git a/FerramAerospaceResearch/FARAeroComponents/SimulatedForceContext.cs b/FerramAerospaceResearch/FARAeroComponents/SimulatedForceContext.cs index a01e8fe14..24c1207b4 100644 --- a/FerramAerospaceResearch/FARAeroComponents/SimulatedForceContext.cs +++ b/FerramAerospaceResearch/FARAeroComponents/SimulatedForceContext.cs @@ -1,7 +1,7 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= -Copyright 2019, Benjamin Chung, aka BenChung +Copyright 2020, Benjamin Chung, aka BenChung This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARAeroComponents/VehicleAerodynamics.cs b/FerramAerospaceResearch/FARAeroComponents/VehicleAerodynamics.cs index 646a2b938..2916ab562 100644 --- a/FerramAerospaceResearch/FARAeroComponents/VehicleAerodynamics.cs +++ b/FerramAerospaceResearch/FARAeroComponents/VehicleAerodynamics.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARAeroComponents/VesselIntakeRamDrag.cs b/FerramAerospaceResearch/FARAeroComponents/VesselIntakeRamDrag.cs index 60374cde8..b1b58a76d 100644 --- a/FerramAerospaceResearch/FARAeroComponents/VesselIntakeRamDrag.cs +++ b/FerramAerospaceResearch/FARAeroComponents/VesselIntakeRamDrag.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARAeroUtil.cs b/FerramAerospaceResearch/FARAeroUtil.cs index eef250013..ab6b037a8 100644 --- a/FerramAerospaceResearch/FARAeroUtil.cs +++ b/FerramAerospaceResearch/FARAeroUtil.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -46,7 +46,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.IO; using ferram4; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Settings; using UnityEngine; namespace FerramAerospaceResearch @@ -69,9 +69,8 @@ public static class FARAeroUtil public static double massStressPower; public static bool AJELoaded; - public static Dictionary bodyAtmosphereConfiguration; public static int prevBodyIndex = -1; - public static double[] currentBodyVisc = new double[2]; + public static BodySettings currentBodyData; private static CelestialBody currentBody; public static bool loaded; @@ -239,7 +238,7 @@ public static int RaycastMask // When parts are being dragged in the editor, they are put into this // layer; however we have to raycast them, or the visible CoL will be // different from the one after the parts are attached. - RaycastMaskEdit = RaycastMaskVal | (1 << LayerMask.NameToLayer("Ignore Raycast")); + RaycastMaskEdit = RaycastMaskVal | 1 << LayerMask.NameToLayer("Ignore Raycast"); FARLogger.Info("Raycast mask: " + RaycastMaskVal + " " + RaycastMaskEdit); @@ -247,115 +246,11 @@ public static int RaycastMask } } - public static void SaveCustomAeroDataToConfig() - { - var node = new ConfigNode("@FARAeroData[default]:FOR[FerramAerospaceResearch]"); - node.AddValue("%massPerWingAreaSupported", massPerWingAreaSupported); - node.AddValue("%massStressPower", massStressPower); - node.AddValue("%ctrlSurfTimeConstant", FARControllableSurface.timeConstant); - node.AddValue("%ctrlSurfTimeConstantFlap", FARControllableSurface.timeConstantFlap); - node.AddValue("%ctrlSurfTimeConstantSpoiler", FARControllableSurface.timeConstantSpoiler); - - node.AddNode(new ConfigNode("!BodyAtmosphericData,*")); - - foreach (KeyValuePair pair in bodyAtmosphereConfiguration) - node.AddNode(CreateAtmConfigurationConfigNode(pair.Key, pair.Value)); - - var saveNode = new ConfigNode(); - saveNode.AddNode(node); - saveNode.Save(KSPUtil.ApplicationRootPath.Replace("\\", "/") + - "GameData/FerramAerospaceResearch/CustomFARAeroData.cfg"); - } - - private static ConfigNode CreateAtmConfigurationConfigNode(int bodyIndex, double[] atmProperties) - { - var node = new ConfigNode("BodyAtmosphericData"); - node.AddValue("index", bodyIndex); - - node.AddValue("viscosityAtReferenceTemp", atmProperties[0]); - node.AddValue("referenceTemp", atmProperties[1]); - - return node; - } - public static void LoadAeroDataFromConfig() { if (loaded) return; - foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("FARAeroData")) - { - if (node == null) - continue; - - if (node.HasValue("massPerWingAreaSupported")) - double.TryParse(node.GetValue("massPerWingAreaSupported"), out massPerWingAreaSupported); - - if (node.HasValue("massStressPower")) - double.TryParse(node.GetValue("massStressPower"), out massStressPower); - - if (node.HasValue("ctrlSurfTimeConstant")) - double.TryParse(node.GetValue("ctrlSurfTimeConstant"), out FARControllableSurface.timeConstant); - - if (node.HasValue("ctrlSurfTimeConstantFlap")) - double.TryParse(node.GetValue("ctrlSurfTimeConstantFlap"), - out FARControllableSurface.timeConstantFlap); - - if (node.HasValue("ctrlSurfTimeConstantSpoiler")) - double.TryParse(node.GetValue("ctrlSurfTimeConstantSpoiler"), - out FARControllableSurface.timeConstantSpoiler); - - bodyAtmosphereConfiguration = new Dictionary(); - foreach (ConfigNode bodyProperties in node.GetNodes("BodyAtmosphericData")) - { - if (bodyProperties == null || - !(bodyProperties.HasValue("index") || bodyProperties.HasValue("name")) || - !bodyProperties.HasValue("viscosityAtReferenceTemp") || - !bodyProperties.HasValue("referenceTemp")) - continue; - - var Rgamma_and_gamma = new double[2]; - double.TryParse(bodyProperties.GetValue("viscosityAtReferenceTemp"), out double tmp); - - Rgamma_and_gamma[0] = tmp; - - double.TryParse(bodyProperties.GetValue("referenceTemp"), out tmp); - - Rgamma_and_gamma[1] = tmp; - int index = -1; - - if (bodyProperties.HasValue("name")) - { - string name = bodyProperties.GetValue("name"); - - foreach (CelestialBody body in FlightGlobals.Bodies) - if (body.bodyName == name) - { - index = body.flightGlobalsIndex; - break; - } - } - - if (index < 0) - int.TryParse(bodyProperties.GetValue("index"), out index); - - bodyAtmosphereConfiguration.Add(index, Rgamma_and_gamma); - } - } - - //For any bodies that lack a configuration, use Earth-like properties - foreach (CelestialBody body in FlightGlobals.Bodies) - { - if (bodyAtmosphereConfiguration.ContainsKey(body.flightGlobalsIndex)) - continue; - - var Rgamma_and_gamma = new double[2]; - Rgamma_and_gamma[0] = 1.7894e-5; - Rgamma_and_gamma[1] = 288; - - bodyAtmosphereConfiguration.Add(body.flightGlobalsIndex, Rgamma_and_gamma); - } - foreach (AssemblyLoader.LoadedAssembly assembly in AssemblyLoader.loadedAssemblies) if (assembly.assembly.GetName().Name == "AJE") AJELoaded = true; @@ -370,7 +265,7 @@ public static void LoadAeroDataFromConfig() File.Delete(forceUpdatePath); //Get Kerbin - currentBodyVisc = bodyAtmosphereConfiguration[1]; + currentBodyData = FARAeroData.AtmosphericConfiguration[1]; } private static void SetDefaultValuesIfNoValuesLoaded() @@ -455,6 +350,7 @@ public static double MachBehindShockCalc(double M) public static bool IsNonphysical(Part p) { return p.physicalSignificance == Part.PhysicalSignificance.NONE || + p.Modules.Contains() || HighLogic.LoadedSceneIsEditor && p != EditorLogic.RootPart && p.PhysicsSignificance == (int)Part.PhysicalSignificance.NONE; @@ -499,7 +395,7 @@ public static List ListEditorWings() var wings = new List(); foreach (Part p in list) { - var wing = p.GetComponent(); + FARWingAerodynamicModel wing = p.GetComponent(); if (!(wing is null)) wings.Add(wing); } @@ -578,13 +474,13 @@ public static double GetCurrentDensity(Vessel v) public static double CalculateCurrentViscosity(double tempInK) { - double visc = currentBodyVisc[0]; //get viscosity + double visc = currentBodyData.ReferenceViscosity; //get viscosity - double tempRat = tempInK / currentBodyVisc[1]; + double tempRat = tempInK / currentBodyData.ReferenceTemperature; tempRat *= tempRat * tempRat; tempRat = Math.Sqrt(tempRat); - visc *= currentBodyVisc[1] + 110; + visc *= currentBodyData.ReferenceTemperature + 110; visc /= tempInK + 110; visc *= tempRat; @@ -677,7 +573,7 @@ public static void UpdateCurrentActiveBody(int index, CelestialBody body) if (index == prevBodyIndex) return; prevBodyIndex = index; - currentBodyVisc = bodyAtmosphereConfiguration[prevBodyIndex]; + currentBodyData = FARAeroData.AtmosphericConfiguration[prevBodyIndex]; currentBody = body; prandtlMeyerMach = null; diff --git a/FerramAerospaceResearch/FARAssets.cs b/FerramAerospaceResearch/FARAssets.cs deleted file mode 100644 index c44f0c21f..000000000 --- a/FerramAerospaceResearch/FARAssets.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using FerramAerospaceResearch.FARUtils; -using UnityEngine; -using Object = UnityEngine.Object; - -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace FerramAerospaceResearch -{ - [KSPAddon(KSPAddon.Startup.MainMenu, true)] - internal class FARAssets : MonoBehaviour - { - private const string AssetBundleExtension = ".far"; - - private static readonly string assetBundleRootPath = - Path.Combine(Assembly.GetExecutingAssembly().Location, "../../Assets"); - - public static FARShaderCache ShaderCache { get; private set; } - public static FARTextureCache TextureCache { get; private set; } - - private void Start() - { - ShaderCache = new FARShaderCache("farshaders"); - TextureCache = new FARTextureCache(); - TextureCache.Initialize(); - StartCoroutine(LoadAssetsAsync()); - } - - private static IEnumerator LoadAssetsAsync() - { - // using a separate method to chain asset loading in the future - yield return ShaderCache.LoadAsync(); - } - - public class FARAssetDictionary : Dictionary where T : Object - { - private AssetBundle assetBundle; - private string bundleName; - - public FARAssetDictionary(string bundleName) - { - BundleName = bundleName; - } - - public string BundleName - { - // ReSharper disable once UnusedMember.Global - get { return bundleName; } - private set - { - bundleName = value; - SetBundlePath(value); - } - } - - public string BundlePath { get; private set; } - public bool AssetsLoaded { get; private set; } - - public IEnumerator LoadAsync() - { - FARLogger.Debug($"Loading asset bundle {BundlePath}"); - AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(BundlePath); - yield return createRequest; - - assetBundle = createRequest.assetBundle; - if (assetBundle == null) - { - FARLogger.Error($"Could not load asset bundle from {BundlePath}"); - yield break; - } - - AssetBundleRequest loadRequest = assetBundle.LoadAllAssetsAsync(typeof(T)); - yield return loadRequest; - - foreach (Object asset in loadRequest.allAssets) - { - FARLogger.Debug($"Adding {asset} to dictionary"); - Add(asset.name, (T)asset); - } - - FARLogger.Debug($"Finished loading {typeof(T)} assets from {BundlePath}"); - AssetsLoaded = true; - - OnLoad(); - } - - protected virtual void OnLoad() - { - } - - protected virtual void SetBundlePath(string name) - { - BundlePath = Path.GetFullPath(Path.Combine(assetBundleRootPath, name) + AssetBundleExtension); - } - } - - public class FARShaderCache : FARAssetDictionary - { - public FARShaderCache(string bundleName) : base(bundleName) - { - } - - public ShaderMaterialPair LineRenderer { get; private set; } - public ShaderMaterialPair DebugVoxels { get; private set; } - - protected override void OnLoad() - { - LineRenderer = new ShaderMaterialPair(Shader.Find("Hidden/Internal-Colored")); - if (TryGetValue("FerramAerospaceResearch/Debug Voxel Mesh", out Shader voxelShader)) - { - DebugVoxels = new ShaderMaterialPair(voxelShader); - DebugVoxels.Material.SetFloat(ShaderPropertyIds.Cutoff, 0.45f); - } - else - { - FARLogger.Warning("Could not find voxel mesh shader. Using Sprites/Default for rendering, you WILL see depth artifacts"); - DebugVoxels = new ShaderMaterialPair(Shader.Find("Sprites/Default")); - } - } - - protected override void SetBundlePath(string name) - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (Application.platform) - { - case RuntimePlatform.LinuxPlayer: - case RuntimePlatform.WindowsPlayer - when SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL", StringComparison.Ordinal): - FARLogger.Info("Loading shaders from Linux bundle"); - name += "_linux"; //For OpenGL users on Windows we load the Linux shaders to fix OpenGL issues - break; - case RuntimePlatform.WindowsPlayer: - FARLogger.Info("Loading shaders from Windows bundle"); - name += "_windows"; - break; - case RuntimePlatform.OSXPlayer: - FARLogger.Info("Loading shaders from MacOSX bundle"); - name += "_macosx"; - break; - default: - // Should never reach this - FARLogger.Error($"Invalid runtime platform {Application.platform}"); - break; - } - - base.SetBundlePath(name); - } - - public class ShaderMaterialPair - { - public ShaderMaterialPair(Shader shader) : this(shader, new Material(shader)) - { - } - - public ShaderMaterialPair(Shader shader, Material material) - { - Shader = shader; - Material = material; - } - - public Shader Shader { get; } - public Material Material { get; } - } - } - - public class FARTextureCache : Dictionary - { - public Texture2D IconLarge { get; private set; } - public Texture2D IconSmall { get; private set; } - public Texture2D VoxelTexture { get; private set; } - - public void Initialize() - { - Add("icon_button_stock", - GameDatabase.Instance.GetTexture("FerramAerospaceResearch/Textures/icon_button_stock", false)); - Add("icon_button_blizzy", - GameDatabase.Instance.GetTexture("FerramAerospaceResearch/Textures/icon_button_blizzy", false)); - Add("sprite_debug_voxel", - GameDatabase.Instance.GetTexture("FerramAerospaceResearch/Textures/sprite_debug_voxel", false)); - IconLarge = this["icon_button_stock"]; - IconSmall = this["icon_button_blizzy"]; - VoxelTexture = this["sprite_debug_voxel"]; - } - } - } -} diff --git a/FerramAerospaceResearch/FARDebugAndSettings.cs b/FerramAerospaceResearch/FARDebugAndSettings.cs index 440ac1476..8cf50ff08 100644 --- a/FerramAerospaceResearch/FARDebugAndSettings.cs +++ b/FerramAerospaceResearch/FARDebugAndSettings.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -50,7 +50,9 @@ You should have received a copy of the GNU General Public License using FerramAerospaceResearch.FARGUI; using FerramAerospaceResearch.FARGUI.FAREditorGUI; using FerramAerospaceResearch.FARGUI.FARFlightGUI; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Resources; +using FerramAerospaceResearch.Settings; +using FerramAerospaceResearch.Threading; using KSP.IO; using KSP.UI.Screens; using UnityEngine; @@ -102,9 +104,7 @@ private void Awake() private void Start() { FARAeroSection.GenerateCrossFlowDragCurve(); - FARAeroStress.LoadStressTemplates(); FARAeroUtil.LoadAeroDataFromConfig(); - //LoadConfigs(); DontDestroyOnLoad(this); debugMenu = false; @@ -168,7 +168,7 @@ private static void OnGUIAppLauncherReady() ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH | ApplicationLauncher.AppScenes.FLIGHT, - FARAssets.TextureCache.IconLarge); + FARAssets.Instance.Textures.IconLarge); } private static void onAppLaunchToggle() @@ -201,7 +201,7 @@ public void OnGUI() debugWinPos = GUILayout.Window("FARDebug".GetHashCode(), debugWinPos, debugWindow, - "FAR Debug Options, " + FARVersion.VersionString, + "FAR Debug Options, " + Version.LongString, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); if (!inputLocked && debugWinPos.Contains(GUIUtils.GetMousePos())) @@ -319,12 +319,14 @@ private void AeroDataTab(GUIStyle buttonStyle, GUIStyle boxStyle) int flightGlobalsIndex = FlightGlobals.Bodies[atmBodyIndex].flightGlobalsIndex; - double[] atmProperties = FARAeroUtil.bodyAtmosphereConfiguration[flightGlobalsIndex]; + BodySettings atmProperties = FARAeroData.AtmosphericConfiguration[flightGlobalsIndex]; - atmProperties[0] = GUIUtils.TextEntryForDouble("Gas Viscosity:", 80, atmProperties[0]); - atmProperties[1] = GUIUtils.TextEntryForDouble("Ref Temp for Viscosity:", 80, atmProperties[1]); + atmProperties.ReferenceViscosity = + GUIUtils.TextEntryForDouble("Gas Viscosity:", 80, atmProperties.ReferenceViscosity); + atmProperties.ReferenceTemperature = + GUIUtils.TextEntryForDouble("Ref Temp for Viscosity:", 80, atmProperties.ReferenceTemperature); - FARAeroUtil.bodyAtmosphereConfiguration[flightGlobalsIndex] = atmProperties; + FARAeroData.AtmosphericConfiguration[flightGlobalsIndex] = atmProperties; GUILayout.EndVertical(); GUILayout.EndHorizontal(); @@ -341,7 +343,7 @@ private void AeroStressTab(GUIStyle buttonStyle, GUIStyle boxStyle) { GUILayout.BeginHorizontal(); bool active = GUILayout.Toggle(i == aeroStressIndex, - FARAeroStress.StressTemplates[i].name, + FARAeroStress.StressTemplates[i].Name, buttonStyle, GUILayout.Width(150)); if (GUILayout.Button("-", buttonStyle, GUILayout.Width(30), GUILayout.Height(30))) @@ -362,17 +364,18 @@ private void AeroStressTab(GUIStyle buttonStyle, GUIStyle boxStyle) { var newTemplate = new FARPartStressTemplate { - XZmaxStress = 500, - YmaxStress = 500, - name = "default", - isSpecialTemplate = false, - minNumResources = 0, - resources = new List(), - excludeResources = new List(), - rejectUnlistedResources = false, - crewed = false, - flowModeNeeded = false, - flowMode = ResourceFlowMode.NO_FLOW + XZMaxStress = 500, + YMaxStress = 500, + Name = "default", + IsSpecial = false, + Resources = + { + NumRequired = 0, + RejectUnlisted = false, + FlowMode = ResourceFlowMode.NO_FLOW + }, + RequiresCrew = false, + FlowModeNeeded = false }; FARAeroStress.StressTemplates.Add(newTemplate); @@ -383,40 +386,36 @@ private void AeroStressTab(GUIStyle buttonStyle, GUIStyle boxStyle) FARPartStressTemplate activeTemplate = FARAeroStress.StressTemplates[aeroStressIndex]; - GUIUtils.TextEntryField("Name:", 80, ref activeTemplate.name); + GUIUtils.TextEntryField("Name:", 80, ref activeTemplate.Name); - activeTemplate.YmaxStress = - GUIUtils.TextEntryForDouble("Axial (Y-axis) Max Stress:", 240, activeTemplate.YmaxStress); - activeTemplate.XZmaxStress = - GUIUtils.TextEntryForDouble("Lateral (X,Z-axis) Max Stress:", 240, activeTemplate.XZmaxStress); + activeTemplate.YMaxStress = + GUIUtils.TextEntryForDouble("Axial (Y-axis) Max Stress:", 240, activeTemplate.YMaxStress); + activeTemplate.XZMaxStress = + GUIUtils.TextEntryForDouble("Lateral (X,Z-axis) Max Stress:", 240, activeTemplate.XZMaxStress); - activeTemplate.crewed = GUILayout.Toggle(activeTemplate.crewed, "Requires Crew Compartment"); + activeTemplate.RequiresCrew = GUILayout.Toggle(activeTemplate.RequiresCrew, "Requires Crew Compartment"); - string tmp = activeTemplate.minNumResources.ToString(); + string tmp = activeTemplate.Resources.NumRequired.ToString(); GUIUtils.TextEntryField("Min Num Resources:", 80, ref tmp); tmp = Regex.Replace(tmp, @"[^\d]", ""); - activeTemplate.minNumResources = Convert.ToInt32(tmp); + activeTemplate.Resources.NumRequired = Convert.ToInt32(tmp); GUILayout.Label("Req Resources:"); - StringListUpdateGUI(activeTemplate.resources, buttonStyle, boxStyle); + StringListUpdateGUI(activeTemplate.Resources.Resources, buttonStyle, boxStyle); GUILayout.Label("Exclude Resources:"); - StringListUpdateGUI(activeTemplate.excludeResources, buttonStyle, boxStyle); - - activeTemplate.rejectUnlistedResources = - GUILayout.Toggle(activeTemplate.rejectUnlistedResources, "Reject Unlisted Res"); - - activeTemplate.flowModeNeeded = - GUILayout.Toggle(activeTemplate.flowModeNeeded, "Requires Specific Flow Mode"); - if (activeTemplate.flowModeNeeded) - activeTemplate.flowMode = - (ResourceFlowMode)GUILayout.SelectionGrid((int)activeTemplate.flowMode, FlowMode_str, 1); + StringListUpdateGUI(activeTemplate.Resources.Excluded, buttonStyle, boxStyle); - activeTemplate.isSpecialTemplate = - GUILayout.Toggle(activeTemplate.isSpecialTemplate, "Special Hardcoded Usage"); + activeTemplate.Resources.RejectUnlisted = + GUILayout.Toggle(activeTemplate.Resources.RejectUnlisted, "Reject Unlisted Res"); - FARAeroStress.StressTemplates[aeroStressIndex] = activeTemplate; + activeTemplate.FlowModeNeeded = + GUILayout.Toggle(activeTemplate.FlowModeNeeded, "Requires Specific Flow Mode"); + if (activeTemplate.FlowModeNeeded) + activeTemplate.Resources.FlowMode = + (ResourceFlowMode)GUILayout.SelectionGrid((int)activeTemplate.Resources.FlowMode, FlowMode_str, 1); + activeTemplate.IsSpecial = GUILayout.Toggle(activeTemplate.IsSpecial, "Special Hardcoded Usage"); GUILayout.EndVertical(); GUILayout.EndHorizontal(); @@ -459,21 +458,21 @@ private void DebugAndDataTab(GUIStyle thisStyle) GUILayout.Label("Editor GUI Graph Colors"); - Color tmpColor = GUIColors.Instance[0]; + Color tmpColor = FARConfig.GUIColors.ClColor; ChangeColor("Cl", ref tmpColor, ref cLTexture); - GUIColors.Instance[0] = tmpColor; + FARConfig.GUIColors.ClColor = tmpColor; - tmpColor = GUIColors.Instance[1]; + tmpColor = FARConfig.GUIColors.CdColor; ChangeColor("Cd", ref tmpColor, ref cDTexture); - GUIColors.Instance[1] = tmpColor; + FARConfig.GUIColors.CdColor = tmpColor; - tmpColor = GUIColors.Instance[2]; + tmpColor = FARConfig.GUIColors.CmColor; ChangeColor("Cm", ref tmpColor, ref cMTexture); - GUIColors.Instance[2] = tmpColor; + FARConfig.GUIColors.CmColor = tmpColor; - tmpColor = GUIColors.Instance[3]; + tmpColor = FARConfig.GUIColors.LdColor; ChangeColor("L_D", ref tmpColor, ref l_DTexture); - GUIColors.Instance[3] = tmpColor; + FARConfig.GUIColors.LdColor = tmpColor; FARActionGroupConfiguration.DrawGUI(); GUILayout.Label("Other Options"); // DaMichel: put it above the toolbar toggle @@ -581,10 +580,8 @@ public static void LoadConfigs(ConfigNode node) else FARDebugValues.aeroFailureExplosions = true; - FARAeroStress.LoadStressTemplates(); FARAeroUtil.LoadAeroDataFromConfig(); FARActionGroupConfiguration.LoadConfiguration(); - FARAnimOverrides.LoadAnimOverrides(); hasScenarioChanged = true; } @@ -592,11 +589,10 @@ public static void LoadConfigs(ConfigNode node) /// Update GUI after a new scenario was loaded. private void OnScenarioChanged() { - GUIColors guiColors = GUIColors.Instance; - ReColorTexture(guiColors[0], ref cLTexture); - ReColorTexture(guiColors[1], ref cDTexture); - ReColorTexture(guiColors[2], ref cMTexture); - ReColorTexture(guiColors[3], ref l_DTexture); + ReColorTexture(FARConfig.GUIColors.ClColor, ref cLTexture); + ReColorTexture(FARConfig.GUIColors.CdColor, ref cDTexture); + ReColorTexture(FARConfig.GUIColors.CmColor, ref cMTexture); + ReColorTexture(FARConfig.GUIColors.LdColor, ref l_DTexture); } public static void SaveConfigs(ConfigNode node) @@ -606,10 +602,9 @@ public static void SaveConfigs(ConfigNode node) node.AddValue("useBlizzyToolbar", FARDebugValues.useBlizzyToolbar & ToolbarManager.ToolbarAvailable); node.AddValue("aeroFailureExplosions", FARDebugValues.aeroFailureExplosions); - FARAeroUtil.SaveCustomAeroDataToConfig(); - FARAeroStress.SaveCustomStressTemplates(); FARActionGroupConfiguration.SaveConfiguration(); - GUIColors.Instance.SaveColors(); + // save in off thread so that it doesn't delay scene changes + MainThread.StartCoroutine(ConfigAdapter.SaveAll); config.save(); } diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AeroStabilityConcern.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AeroStabilityConcern.cs index f582e75ec..41a901c27 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AeroStabilityConcern.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AeroStabilityConcern.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AreaRulingConcern.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AreaRulingConcern.cs index 290b96c6f..849bd8b98 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AreaRulingConcern.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/DesignConcerns/AreaRulingConcern.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAeroCenter.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAeroCenter.cs index 8149e54cf..ff5a5e3b6 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAeroCenter.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAeroCenter.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -107,6 +107,8 @@ private void UpdateAerodynamicCenter() float mass = 0; foreach (Part p in EditorLogic.SortedShipList) { + if (FARAeroUtil.IsNonphysical(p)) + continue; float tmpMass = p.mass + p.GetResourceMass(); mass += tmpMass; pos += p.partTransform.position * tmpMass; diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAreaRulingOverlay.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAreaRulingOverlay.cs index 4ad81a64c..7b7b81c4b 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAreaRulingOverlay.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorAreaRulingOverlay.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,7 +44,7 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Resources; using UnityEngine; using Object = UnityEngine.Object; @@ -105,7 +105,7 @@ private void Initialize() //Based on Kronal Vessel Viewer CoM axes rendering if (_rendererMaterial == null) { - Material lineMaterial = FARAssets.ShaderCache.LineRenderer.Material; + Material lineMaterial = FARAssets.Instance.Shaders.LineRenderer; _rendererMaterial = new Material(lineMaterial) { @@ -160,7 +160,7 @@ private static LineRenderer CreateNewRenderer(Color color, float width, Material { var o = new GameObject(); - var renderer = o.gameObject.AddComponent(); + LineRenderer renderer = o.gameObject.AddComponent(); // need to copy the material properties so the same material is not // reused between renderers @@ -280,7 +280,8 @@ private static void UpdateRenderer( for (int i = 0; i < xCoords.Length; i++) { - Vector3 vec = Vector3.up * (float)xCoords[i] - Vector3.forward * (float)(yCoords[i] * yScalingFactor); + Vector3 vec = Vector3.up * (float)xCoords[i] - + Vector3.forward * (float)(yCoords[i] * yScalingFactor); vec = transformMatrix.MultiplyVector(vec); renderer.SetPosition(i, vec); } diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorGUI.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorGUI.cs index 35a0e07fd..a83ab3da8 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/EditorGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -53,7 +53,7 @@ You should have received a copy of the GNU General Public License using FerramAerospaceResearch.FARGUI.FAREditorGUI.Simulation; using FerramAerospaceResearch.FARPartGeometry; using FerramAerospaceResearch.FARThreading; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Resources; using KSP.Localization; using KSP.UI.Screens; using ModuleWheels; @@ -87,7 +87,7 @@ public class EditorGUI : MonoBehaviour private readonly List _customDesignConcerns = new List(); private int _updateRateLimiter; - private bool _updateQueued = true; + public bool VoxelizationUpdateQueued { get; private set; } = true; private Rect guiRect; private VehicleAerodynamics _vehicleAero; @@ -169,10 +169,10 @@ private void Start() _stabDeriv = new StabilityDerivGUI(_simManager, flapSettingDropDown, celestialBodyDropdown); _stabDerivLinSim = new StabilityDerivSimulationGUI(_simManager); - Color crossSection = GUIColors.GetColor(3); + Color crossSection = FARConfig.GUIColors.LdColor; crossSection.a = 0.8f; - Color crossSectionDeriv = GUIColors.GetColor(2); + Color crossSectionDeriv = FARConfig.GUIColors.CmColor; crossSectionDeriv.a = 0.8f; _areaRulingOverlay = @@ -303,7 +303,7 @@ private static void UpdateGeometryModule(ConstructionEventType type, Part p) { if (p is null) return; - var g = p.GetComponent(); + GeometryPartModule g = p.GetComponent(); if (g == null || !g.Ready) return; if (type == ConstructionEventType.Unknown) @@ -316,7 +316,7 @@ private static void UpdateGeometryModule(Part p) { if (p is null) return; - var g = p.GetComponent(); + GeometryPartModule g = p.GetComponent(); if (g != null && g.Ready) g.EditorUpdate(); } @@ -332,14 +332,14 @@ private void LEGACY_UpdateWingAeroModels(bool updateWingInteractions) continue; if (p.Modules.Contains()) { - var w = p.Modules.GetModule(); + FARWingAerodynamicModel w = p.Modules.GetModule(); if (updateWingInteractions) w.EditorUpdateWingInteractions(); _wingAerodynamicModel.Add(w); } else if (p.Modules.Contains()) { - var c = p.Modules.GetModule(); + FARControllableSurface c = p.Modules.GetModule(); if (updateWingInteractions) c.EditorUpdateWingInteractions(); _wingAerodynamicModel.Add(c); @@ -383,7 +383,7 @@ private void FixedUpdate() { _updateRateLimiter++; } - else if (_updateQueued) + else if (VoxelizationUpdateQueued) { string shipname = EditorLogic.fetch.ship.shipName ?? "unknown ship"; FARLogger.Info("Updating " + shipname); @@ -392,7 +392,7 @@ private void FixedUpdate() } else { - _updateQueued = true; + VoxelizationUpdateQueued = true; _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; } } @@ -401,7 +401,7 @@ public static void RequestUpdateVoxel() { if (Instance._updateRateLimiter > FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate) Instance._updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; - Instance._updateQueued = true; + Instance.VoxelizationUpdateQueued = true; } private void RecalculateVoxel() @@ -409,12 +409,12 @@ private void RecalculateVoxel() //this has been updated recently in the past; queue an update and return if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate) { - _updateQueued = true; + VoxelizationUpdateQueued = true; return; } _updateRateLimiter = 0; - _updateQueued = false; + VoxelizationUpdateQueued = false; List partList = EditorLogic.SortedShipList; _currentGeometryModules.Clear(); @@ -423,7 +423,7 @@ private void RecalculateVoxel() { if (!p.Modules.Contains()) continue; - var g = p.Modules.GetModule(); + GeometryPartModule g = p.Modules.GetModule(); if (g == null) continue; if (g.Ready) @@ -433,7 +433,7 @@ private void RecalculateVoxel() else { _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; - _updateQueued = true; + VoxelizationUpdateQueued = true; return; } } @@ -453,7 +453,7 @@ private void RecalculateVoxel() voxelWatch.Stop(); voxelWatch.Reset(); _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; - _updateQueued = true; + VoxelizationUpdateQueued = true; } private void TriggerIGeometryUpdaters() @@ -571,6 +571,7 @@ private void OverallSelectionGUI(int windowId) private void DebugVisualizationGUI() { GUILayout.BeginHorizontal(); + GUI.enabled = !Instance.VoxelizationUpdateQueued; if (GUILayout.Button(Localizer.Format("FARDebugVoxels"))) { Matrix4x4? localToWorldMatrix = null; @@ -588,6 +589,7 @@ private void DebugVisualizationGUI() _vehicleAero.DebugVisualizeVoxels((Matrix4x4)localToWorldMatrix); } + GUI.enabled = true; GUILayout.EndHorizontal(); } @@ -683,7 +685,7 @@ private static void GenerateBlizzyToolbarButton() if (blizzyEditorGUIButton != null) return; blizzyEditorGUIButton = ToolbarManager.Instance.add("FerramAerospaceResearch", "FAREditorButtonBlizzy"); - blizzyEditorGUIButton.TexturePath = "FerramAerospaceResearch/Textures/icon_button_blizzy"; + blizzyEditorGUIButton.TexturePath = FARAssets.Instance.Textures.IconSmall.Url; blizzyEditorGUIButton.ToolTip = "FAR Editor"; blizzyEditorGUIButton.OnClick += e => showGUI = !showGUI; } @@ -712,7 +714,7 @@ private void ToggleGear() { if (p.Modules.Contains()) { - var l = p.Modules.GetModule(); + ModuleWheelDeployment l = p.Modules.GetModule(); l.ActionToggle(new KSPActionParam(KSPActionGroup.Gear, gearToggle ? KSPActionType.Activate : KSPActionType.Deactivate)); } diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EditorSimManager.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EditorSimManager.cs index 45c0f0fcb..977a2af75 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EditorSimManager.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EditorSimManager.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EquationSystem.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EquationSystem.cs index 6a5d3d3da..682a6a2b7 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EquationSystem.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/EquationSystem.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,7 +43,6 @@ You should have received a copy of the GNU General Public License */ using System.Text; -using FerramAerospaceResearch.FARUtils; namespace FerramAerospaceResearch.FARGUI.FAREditorGUI.Simulation { diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/GraphData.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/GraphData.cs index ff2f72394..704905f29 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/GraphData.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/GraphData.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSim.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSim.cs index 30ef0353c..ecf84f338 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSim.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSim.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimInput.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimInput.cs index 36c18a5e3..6e1b70231 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimInput.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimInput.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimOutput.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimOutput.cs index 7fe03b0a7..2de88ed45 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimOutput.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/InstantConditionSimOutput.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/RungeKutta.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/RungeKutta.cs index 2119d4c0d..660c72ecf 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/RungeKutta.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/RungeKutta.cs @@ -1,8 +1,8 @@ -/*Ferram Aerospace Research v0.15.11.4 "Mach" +/*Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -42,7 +42,6 @@ You should have received a copy of the GNU General Public License */ using System; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARGUI.FAREditorGUI.Simulation diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivApproxSim.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivApproxSim.cs index 5294d3bc4..63886a9b1 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivApproxSim.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivApproxSim.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,7 +43,6 @@ You should have received a copy of the GNU General Public License */ using System; -using FerramAerospaceResearch.FARUtils; namespace FerramAerospaceResearch.FARGUI.FAREditorGUI.Simulation { @@ -144,19 +143,19 @@ double[] InitCond double[] yVal = transSolve.GetSolution(0); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(3), "β", true); + lines.AddData(yVal, FARConfig.GUIColors.LdColor, "β", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(2), "p", true); + lines.AddData(yVal, FARConfig.GUIColors.CmColor, "p", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(1), "r", true); + lines.AddData(yVal, FARConfig.GUIColors.CdColor, "r", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(0), "φ", true); + lines.AddData(yVal, FARConfig.GUIColors.ClColor, "φ", true); return lines; } @@ -233,19 +232,19 @@ double[] InitCond double[] yVal = transSolve.GetSolution(0); ScaleAndClampValues(yVal, 1, 50); - lines.AddData(yVal, GUIColors.GetColor(3), "w", true); + lines.AddData(yVal, FARConfig.GUIColors.LdColor, "w", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 1, 50); - lines.AddData(yVal, GUIColors.GetColor(2), "u", true); + lines.AddData(yVal, FARConfig.GUIColors.CmColor, "u", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(1), "q", true); + lines.AddData(yVal, FARConfig.GUIColors.CdColor, "q", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); - lines.AddData(yVal, GUIColors.GetColor(0), "θ", true); + lines.AddData(yVal, FARConfig.GUIColors.ClColor, "θ", true); return lines; } diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivCalculator.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivCalculator.cs index 3a93a6eb5..932d54fb1 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivCalculator.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivCalculator.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -46,7 +46,6 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Globalization; using ferram4; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARGUI.FAREditorGUI.Simulation @@ -116,7 +115,7 @@ double phi // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass CoM += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset); mass += partMass; - var w = p.GetComponent(); + FARWingAerodynamicModel w = p.GetComponent(); if (w == null) continue; if (w.isShielded) @@ -192,16 +191,14 @@ double phi 2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w)); var Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w), - -prncInertRot.x * prncInertRot.x + - prncInertRot.y * prncInertRot.y - + -prncInertRot.x * prncInertRot.x + prncInertRot.y * prncInertRot.y - prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w, 2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w)); var Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w), 2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w), - -prncInertRot.x * prncInertRot.x - - prncInertRot.y * prncInertRot.y + + -prncInertRot.x * prncInertRot.x - prncInertRot.y * prncInertRot.y + prncInertRot.z * prncInertRot.z + prncInertRot.w * prncInertRot.w); diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivOutput.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivOutput.cs index 8d24f8da4..6eafc2ae5 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivOutput.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/StabilityDerivOutput.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/SweepSim.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/SweepSim.cs index f430887c1..120f2eb5a 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/SweepSim.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/Simulation/SweepSim.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -99,10 +99,10 @@ CelestialBody body } var data = new GraphData {xValues = AlphaValues}; - data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true); - data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true); - data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true); - data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true); + data.AddData(ClValues, FARConfig.GUIColors.ClColor, Localizer.Format("FARAbbrevCl"), true); + data.AddData(CdValues, FARConfig.GUIColors.CdColor, Localizer.Format("FARAbbrevCd"), true); + data.AddData(CmValues, FARConfig.GUIColors.CmColor, Localizer.Format("FARAbbrevCm"), true); + data.AddData(LDValues, FARConfig.GUIColors.LdColor, Localizer.Format("FARAbbrevL_D"), true); return data; } @@ -168,17 +168,17 @@ CelestialBody body } var data = new GraphData {xValues = AlphaValues}; - data.AddData(ClValues2, GUIColors.GetColor(0) * 0.5f, "Cl2", false); - data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true); + data.AddData(ClValues2, FARConfig.GUIColors.ClColor * 0.5f, "Cl2", false); + data.AddData(ClValues, FARConfig.GUIColors.ClColor, Localizer.Format("FARAbbrevCl"), true); - data.AddData(CdValues2, GUIColors.GetColor(1) * 0.5f, "Cd2", false); - data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true); + data.AddData(CdValues2, FARConfig.GUIColors.CdColor * 0.5f, "Cd2", false); + data.AddData(CdValues, FARConfig.GUIColors.CdColor, Localizer.Format("FARAbbrevCd"), true); - data.AddData(CmValues2, GUIColors.GetColor(2) * 0.5f, "Cm2", false); - data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true); + data.AddData(CmValues2, FARConfig.GUIColors.CmColor * 0.5f, "Cm2", false); + data.AddData(CmValues, FARConfig.GUIColors.CmColor, Localizer.Format("FARAbbrevCm"), true); - data.AddData(LDValues2, GUIColors.GetColor(3) * 0.5f, "L/D2", false); - data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true); + data.AddData(LDValues2, FARConfig.GUIColors.LdColor * 0.5f, "L/D2", false); + data.AddData(LDValues, FARConfig.GUIColors.LdColor, Localizer.Format("FARAbbrevL_D"), true); return data; diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivGUI.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivGUI.cs index 34ddcf994..26143c7f9 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -120,10 +120,12 @@ public void Display() GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); + GUI.enabled = !EditorGUI.Instance.VoxelizationUpdateQueued; if (GUILayout.Button(Localizer.Format("FAREditorStabDerivCalcButton"), GUILayout.Width(250.0F), GUILayout.Height(25.0F))) StabDerivCalcButtonAction(); + GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivSimulationGUI.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivSimulationGUI.cs index 49b92bbe2..38b636962 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivSimulationGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StabilityDerivSimulationGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -319,6 +319,7 @@ private void DataInput(InitialConditions inits, StabilityDerivOutput vehicleData inits.maxTime = GUILayout.TextField(inits.maxTime, GUILayout.ExpandWidth(true)); GUILayout.Label(Localizer.Format("FAREditorSimTimestep")); inits.dt = GUILayout.TextField(inits.dt, GUILayout.ExpandWidth(true)); + GUI.enabled = !EditorGUI.Instance.VoxelizationUpdateQueued; if (GUILayout.Button(Localizer.Format("FAREditorSimRunButton"), GUILayout.Width(150.0F), GUILayout.Height(25.0F))) @@ -352,6 +353,7 @@ private void DataInput(InitialConditions inits, StabilityDerivOutput vehicleData 50); } + GUI.enabled = true; GUILayout.EndHorizontal(); } diff --git a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StaticAnalysisGraphGUI.cs b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StaticAnalysisGraphGUI.cs index 8b454dbfc..4a5a37400 100644 --- a/FerramAerospaceResearch/FARGUI/FAREditorGUI/StaticAnalysisGraphGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FAREditorGUI/StaticAnalysisGraphGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -229,6 +229,7 @@ private void BelowGraphInputsGUI(GraphInputs input) GUILayout.Height(25.0F)); input.otherInput = GUILayout.TextField(input.otherInput, GUILayout.ExpandWidth(true)); + GUI.enabled = !EditorGUI.Instance.VoxelizationUpdateQueued; if (GUILayout.Button(isMachMode ? Localizer.Format("FAREditorStaticSweepMach") : Localizer.Format("FAREditorStaticSweepAoA"), @@ -298,6 +299,7 @@ private void BelowGraphInputsGUI(GraphInputs input) } } + GUI.enabled = true; GUILayout.EndHorizontal(); } diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/AeroVisualizationGUI.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/AeroVisualizationGUI.cs index f1a11fac1..8e0478298 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/AeroVisualizationGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/AeroVisualizationGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,7 +44,6 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Linq; -using FerramAerospaceResearch.FARUtils; using KSP.Localization; using UnityEngine; diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/AirspeedSettingsGUI.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/AirspeedSettingsGUI.cs index ccc15b6e8..d27dc3abc 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/AirspeedSettingsGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/AirspeedSettingsGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using System.Linq; -using FerramAerospaceResearch.FARUtils; using KSP.Localization; using KSP.UI.Screens.Flight; using UnityEngine; diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataGUI.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataGUI.cs index ef5303fc8..b8ba2d1e5 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Linq; using System.Text; -using FerramAerospaceResearch.FARUtils; using KSP.Localization; using StringLeakTest; using UnityEngine; diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataLogger.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataLogger.cs new file mode 100644 index 000000000..23b389aa1 --- /dev/null +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightDataLogger.cs @@ -0,0 +1,290 @@ +/* +Ferram Aerospace Research v0.16.0.0 "Mader" +========================= +Aerodynamics model for Kerbal Space Program + +Copyright 2020, Daumantas Kavolis, aka dkavolis + + This file is part of Ferram Aerospace Research. + + Ferram Aerospace Research is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Ferram Aerospace Research is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Ferram Aerospace Research. If not, see . + + Serious thanks: a.g., for tons of bugfixes and code-refactorings + stupid_chris, for the RealChuteLite implementation + Taverius, for correcting a ton of incorrect values + Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts + sarbian, for refactoring code for working with MechJeb, and the Module Manager updates + ialdabaoth (who is awesome), who originally created Module Manager + Regex, for adding RPM support + DaMichel, for some ferramGraph updates and some control surface-related features + Duxwing, for copy editing the readme + + CompatibilityChecker by Majiir, BSD 2-clause http://opensource.org/licenses/BSD-2-Clause + + Part.cfg changes powered by sarbian & ialdabaoth's ModuleManager plugin; used with permission + http://forum.kerbalspaceprogram.com/threads/55219 + + ModularFLightIntegrator by Sarbian, Starwaster and Ferram4, MIT: http://opensource.org/licenses/MIT + http://forum.kerbalspaceprogram.com/threads/118088 + + Toolbar integration powered by blizzy78's Toolbar plugin; used with permission + http://forum.kerbalspaceprogram.com/threads/60863 + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace FerramAerospaceResearch.FARGUI.FARFlightGUI +{ + // inheriting from MonoBehaviour for coroutines and attaching to vessel + internal class FlightDataLogger : MonoBehaviour + { + private const string VesselNameKey = "VESSEL_NAME"; + private const string DatetimeKey = "DATETIME"; + + private static readonly string[] headers = + { + "time", + "altitude", + "speed", + " lift", + " drag", + " lateral force", + " dynamic pressure", + " CL", + " CD", + " CQ", + // " reference area", + " L/D", + " VL/D", + " AoA", + " sideslip", + " pitch", + " heading", + " roll", + // " dry mass", + // " full mass", + // " tSFC", + // " intake air fraction", + // " specific excess power", + // " range", + // " endurance", + // " ballistic coefficient", + // " terminal velocity", + " stall fraction" + }; + + private readonly Dictionary replacements = new Dictionary + { + {VesselNameKey, "unknown"}, + {DatetimeKey, "no_date"} + }; + + private CsvWriter writer; + + private Coroutine coroutine; + private bool headerWritten; + + public int Period { get; set; } = 50; + public int FlushPeriod { get; set; } = 10; + + public bool IsActive + { + get { return coroutine != null; } + } + + public Vessel Vessel { get; private set; } + + public string FileName + { + get { return writer.Filename; } + } + + public static FlightDataLogger CreateLogger(Vessel vessel) + { + if (vessel == null) + throw new ArgumentNullException(nameof(vessel)); + + var logger = vessel.gameObject.AddComponent(); + logger.Vessel = vessel; + logger.writer = new CsvWriter(logger.GetFilename()); + logger.Period = FARConfig.FlightLog.LogPeriod; + logger.FlushPeriod = FARConfig.FlightLog.FlushPeriod; + + return logger; + } + + public void StartLogging() + { + if (IsActive) + return; + coroutine = StartCoroutine(DoLogging()); + } + + public void StopLogging() + { + if (!IsActive) + return; + + FARLogger.Debug($"Stopping logging to {FileName}"); + StopCoroutine(coroutine); + writer.Close(); + coroutine = null; + } + + public void PauseLogging() + { + if (!IsActive) + return; + + FARLogger.Debug($"Pausing logging to {FileName}"); + StopCoroutine(coroutine); + coroutine = null; + } + + private IEnumerator DoLogging() + { + if (Vessel == null) + { + LogError("Cannot log a null vessel"); + yield break; + } + + if (!FlightGUI.vesselFlightGUI.TryGetValue(Vessel, out FlightGUI gui)) + { + LogError("Cannot log a vessel without FlightGUI"); + yield break; + } + + if (gui == null) + { + LogError("Cannot log a vessel with null FlightGUI"); + yield break; + } + + OpenFile(); + + if (!headerWritten && !writer.Appending) + { + writer.WriteLine(headers); + headerWritten = true; + } + + double logTime = Planetarium.fetch.time; + int flushCounter = 0; + while (true) + { + Log(gui); + logTime += Period * 0.001; + + while (Planetarium.fetch.time <= logTime) + yield return null; + + if (flushCounter >= FlushPeriod) + { + writer.Flush(); + flushCounter = 0; + } + else + { + flushCounter++; + } + } + } + + private void LogError(string msg) + { + FARLogger.Error(msg); + StopLogging(); + } + + private void Log(FlightGUI gui) + { + writer.Write(Planetarium.fetch.time); + writer.Write(Vessel.altitude); + writer.Write(Vessel.srfSpeed); + writer.Write(gui.InfoParameters.liftForce); + writer.Write(gui.InfoParameters.dragForce); + writer.Write(gui.InfoParameters.sideForce); + writer.Write(gui.InfoParameters.dynPres); + writer.Write(gui.InfoParameters.liftCoeff); + writer.Write(gui.InfoParameters.dragCoeff); + writer.Write(gui.InfoParameters.sideCoeff); + // writer.Write(gui.InfoParameters.refArea); + writer.Write(gui.InfoParameters.liftToDragRatio); + writer.Write(gui.InfoParameters.velocityLiftToDragRatio); + writer.Write(gui.InfoParameters.aoA); + writer.Write(gui.InfoParameters.sideslipAngle); + writer.Write(gui.InfoParameters.pitchAngle); + writer.Write(gui.InfoParameters.headingAngle); + writer.Write(gui.InfoParameters.rollAngle); + // writer.Write(gui.InfoParameters.dryMass); + // writer.Write(gui.InfoParameters.fullMass); + // writer.Write(gui.InfoParameters.tSFC); + // writer.Write(gui.InfoParameters.intakeAirFrac); + // writer.Write(gui.InfoParameters.specExcessPower); + // writer.Write(gui.InfoParameters.range); + // writer.Write(gui.InfoParameters.endurance); + // writer.Write(gui.InfoParameters.ballisticCoeff); + // writer.Write(gui.InfoParameters.termVelEst); + writer.WriteLine(gui.InfoParameters.stallFraction); + } + + private string GetFilename() + { + if (Vessel != null) + replacements[VesselNameKey] = Vessel.vesselName; + replacements[DatetimeKey] = DateTime.Now.ToString(FARConfig.FlightLog.DatetimeFormat); + string filename = Path.Combine(FARConfig.FlightLog.Directory, + FARConfig.FlightLog.NameFormat.ToString(replacements)); + + return filename; + } + + private void OpenFile() + { + if (writer.IsOpen) + { + FARLogger.Debug($"Continuing logging to {FileName}"); + return; + } + + string directory = Path.GetDirectoryName(FileName); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + FARLogger.Debug($"Logs directory {directory} does not exist, creating"); + Directory.CreateDirectory(directory); + } + else if (File.Exists(FileName)) + { + FARLogger.Info($"Appending logs to {FileName}"); + } + else + { + FARLogger.Info($"Starting logging to {FileName}"); + } + + writer.Open(); + } + + private void OnDestroy() + { + StopLogging(); + Vessel = null; + } + } +} diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUI.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUI.cs index dc51afa8a..ed8abe398 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -46,7 +46,7 @@ You should have received a copy of the GNU General Public License using System.Text; using ferram4; using FerramAerospaceResearch.FARAeroComponents; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Resources; using KSP.IO; using KSP.Localization; using StringLeakTest; @@ -79,6 +79,7 @@ public class FlightGUI : VesselModule private FlightStatusGUI _flightStatusGUI; private StabilityAugmentation _stabilityAugmentation; private FlightDataGUI _flightDataGUI; + private FlightDataLogger flightDataLogger; private bool showFlightDataWindow; private bool showSettingsWindow; @@ -129,6 +130,7 @@ protected override void OnStart() vesselFlightGUI[_vessel] = this; else vesselFlightGUI.Add(_vessel, this); + flightDataLogger = FlightDataLogger.CreateLogger(_vessel); enabled = true; @@ -165,6 +167,12 @@ private void OnDestroy() AeroVizGUI?.SaveSettings(); + if (flightDataLogger) + { + flightDataLogger.StopLogging(); + flightDataLogger = null; + } + _flightStatusGUI = null; settingsWindow = null; @@ -282,7 +290,7 @@ public void DrawGUI() mainGuiRect = GUILayout.Window(GetHashCode(), mainGuiRect, MainFlightGUIWindow, - "FAR, " + FARVersion.VersionString, + "FAR, " + Version.LongString, GUILayout.MinWidth(230)); GUIUtils.ClampToScreen(mainGuiRect); @@ -336,6 +344,25 @@ private void MainFlightGUIWindow(int windowId) buttonStyle, GUILayout.ExpandWidth(true)); + bool logging = GUILayout.Toggle(flightDataLogger.IsActive, + Localizer.Format("FARFlightGUIFltLogging"), + buttonStyle, + GUILayout.ExpandWidth(true)); + if (logging != flightDataLogger.IsActive) + { + if (!flightDataLogger.IsActive) + flightDataLogger.StartLogging(); + else + flightDataLogger.StopLogging(); + } + + flightDataLogger.Period = + GUIUtils.TextEntryForInt(Localizer.Format("FARFlightGUIFltLogPeriod"), 150, flightDataLogger.Period); + flightDataLogger.FlushPeriod = + GUIUtils.TextEntryForInt(Localizer.Format("FARFlightGUIFltLogFlushPeriod"), + 150, + flightDataLogger.FlushPeriod); + GUILayout.Label(Localizer.Format("FARFlightGUIFltAssistance")); _stabilityAugmentation.Display(); @@ -386,7 +413,7 @@ private static void GenerateBlizzyToolbarButton() if (blizzyFlightGUIButton != null) return; blizzyFlightGUIButton = ToolbarManager.Instance.add("FerramAerospaceResearch", "FARFlightButtonBlizzy"); - blizzyFlightGUIButton.TexturePath = "FerramAerospaceResearch/Textures/icon_button_blizzy"; + blizzyFlightGUIButton.TexturePath = FARAssets.Instance.Textures.IconSmall.Url; blizzyFlightGUIButton.ToolTip = "FAR Flight Sys"; blizzyFlightGUIButton.OnClick += e => showGUI = !showGUI; } diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUIDrawer.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUIDrawer.cs index 86b977c1a..a3153d7b9 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUIDrawer.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightGUIDrawer.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightStatusGUI.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightStatusGUI.cs index eef740c5e..36003f510 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightStatusGUI.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/FlightStatusGUI.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/InternalSpeedFAR.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/InternalSpeedFAR.cs index 0f3ac5349..317cca9fd 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/InternalSpeedFAR.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/InternalSpeedFAR.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/PhysicsCalcs.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/PhysicsCalcs.cs index e7d0461c4..15deb949f 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/PhysicsCalcs.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/PhysicsCalcs.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/StabilityAugmentation.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/StabilityAugmentation.cs index 99f8f8e34..cf34536a9 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/StabilityAugmentation.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/StabilityAugmentation.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using System.Linq; -using FerramAerospaceResearch.FARUtils; using KSP.Localization; using UnityEngine; diff --git a/FerramAerospaceResearch/FARGUI/FARFlightGUI/VesselFlightInfo.cs b/FerramAerospaceResearch/FARGUI/FARFlightGUI/VesselFlightInfo.cs index 0e669a431..887fc5d4c 100644 --- a/FerramAerospaceResearch/FARGUI/FARFlightGUI/VesselFlightInfo.cs +++ b/FerramAerospaceResearch/FARGUI/FARFlightGUI/VesselFlightInfo.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARGUI/GUIColors.cs b/FerramAerospaceResearch/FARGUI/GUIColors.cs deleted file mode 100644 index 055a17fd6..000000000 --- a/FerramAerospaceResearch/FARGUI/GUIColors.cs +++ /dev/null @@ -1,171 +0,0 @@ -/* -Ferram Aerospace Research v0.15.11.4 "Mach" -========================= -Aerodynamics model for Kerbal Space Program - -Copyright 2019, Michael Ferrara, aka Ferram4 - - This file is part of Ferram Aerospace Research. - - Ferram Aerospace Research is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Ferram Aerospace Research is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Ferram Aerospace Research. If not, see . - - Serious thanks: a.g., for tons of bugfixes and code-refactorings - stupid_chris, for the RealChuteLite implementation - Taverius, for correcting a ton of incorrect values - Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts - sarbian, for refactoring code for working with MechJeb, and the Module Manager updates - ialdabaoth (who is awesome), who originally created Module Manager - Regex, for adding RPM support - DaMichel, for some ferramGraph updates and some control surface-related features - Duxwing, for copy editing the readme - - CompatibilityChecker by Majiir, BSD 2-clause http://opensource.org/licenses/BSD-2-Clause - - Part.cfg changes powered by sarbian & ialdabaoth's ModuleManager plugin; used with permission - http://forum.kerbalspaceprogram.com/threads/55219 - - ModularFLightIntegrator by Sarbian, Starwaster and Ferram4, MIT: http://opensource.org/licenses/MIT - http://forum.kerbalspaceprogram.com/threads/118088 - - Toolbar integration powered by blizzy78's Toolbar plugin; used with permission - http://forum.kerbalspaceprogram.com/threads/60863 - */ - -using System.Collections.Generic; -using System.Text; -using FerramAerospaceResearch.FARUtils; -using UnityEngine; - -namespace FerramAerospaceResearch.FARGUI -{ - internal class GUIColors - { - private static GUIColors _instance; - private List colors; - - private GUIColors() - { - LoadColors(); - } - - public static GUIColors Instance - { - get { return _instance ??= new GUIColors(); } - } - - public Color this[int index] - { - get - { - if (_instance == null) - _instance = new GUIColors(); - return _instance.colors[index]; - } - set - { - if (_instance == null) - _instance = new GUIColors(); - _instance.colors[index] = value; - } - } - - public static Color GetColor(int index) - { - if (_instance == null) - _instance = new GUIColors(); - - return _instance.colors[index]; - } - - public void LoadColors() - { - colors = new List(); - FARLogger.Info("Loading FAR GUI Colors"); - foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("FARGUIColors")) - { - if (node.HasValue("ClColor")) - colors.Add(ReadColor(node.GetValue("ClColor"))); - - if (node.HasValue("CdColor")) - colors.Add(ReadColor(node.GetValue("CdColor"))); - - if (node.HasValue("CmColor")) - colors.Add(ReadColor(node.GetValue("CmColor"))); - - if (node.HasValue("L_DColor")) - colors.Add(ReadColor(node.GetValue("L_DColor"))); - } - } - - public void SaveColors() - { - var node = new ConfigNode("@FARGUIColors[default]:FOR[FerramAerospaceResearch]"); - node.AddValue("%ClColor", SaveColor(colors[0])); - node.AddValue("%CdColor", SaveColor(colors[1])); - node.AddValue("%CmColor", SaveColor(colors[2])); - node.AddValue("%L_DColor", SaveColor(colors[3])); - - var saveNode = new ConfigNode(); - saveNode.AddNode(node); - saveNode.Save(KSPUtil.ApplicationRootPath.Replace("\\", "/") + - "GameData/FerramAerospaceResearch/CustomFARGUIColors.cfg"); - } - - private static Color ReadColor(string input) - { - char[] separators = {',', ' ', ';'}; - string[] splitValues = input.Split(separators); - - int curIndex = 0; - var color = new Color {a = 1}; - foreach (string s in splitValues) - { - if (s.Length <= 0) - continue; - if (!float.TryParse(s, out float val)) - continue; - switch (curIndex) - { - case 0: - color.r = val; - break; - case 1: - color.g = val; - break; - default: - color.b = val; - return color; - } - - curIndex++; - } - - return color; - } - - private static string SaveColor(Color color) - { - var builder = new StringBuilder(); - - //Should return string in format of color.r, color.g, color.b - builder.Append(color.r); - builder.Append(","); - builder.Append(color.g); - builder.Append(","); - builder.Append(color.b); - - return builder.ToString(); - } - } -} diff --git a/FerramAerospaceResearch/FARGUI/GUIDropDown.cs b/FerramAerospaceResearch/FARGUI/GUIDropDown.cs index 0af8a6231..22fb64a8c 100644 --- a/FerramAerospaceResearch/FARGUI/GUIDropDown.cs +++ b/FerramAerospaceResearch/FARGUI/GUIDropDown.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -42,7 +42,7 @@ You should have received a copy of the GNU General Public License http://forum.kerbalspaceprogram.com/threads/60863 */ -using FerramAerospaceResearch.FARUtils; + using UnityEngine; // ReSharper disable StaticMemberInGenericType diff --git a/FerramAerospaceResearch/FARGUI/GUIUtils.cs b/FerramAerospaceResearch/FARGUI/GUIUtils.cs index 42f31e641..2fc7fa528 100644 --- a/FerramAerospaceResearch/FARGUI/GUIUtils.cs +++ b/FerramAerospaceResearch/FARGUI/GUIUtils.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARKSPAdapter.cs b/FerramAerospaceResearch/FARKSPAdapter.cs new file mode 100644 index 000000000..6a7bfb158 --- /dev/null +++ b/FerramAerospaceResearch/FARKSPAdapter.cs @@ -0,0 +1,19 @@ +using FerramAerospaceResearch.Resources; + +namespace FerramAerospaceResearch +{ + [KSPAddon(KSPAddon.Startup.Instantly, true)] + public class FARKSPAdapter : MonoSingleton + { + protected override void OnAwake() + { + FARAddonLoader loader = FARAddonLoader.Instance; + loader.Load(() => FARAssets.Instance.Loaders.Textures.Add(new GameDatabaseTextureLoader())); + } + + public void ModuleManagerPostLoad() + { + StartCoroutine(FARAddonLoader.Instance.Reload()); + } + } +} diff --git a/FerramAerospaceResearch/FARKSPAddonFlightScene.cs b/FerramAerospaceResearch/FARKSPAddonFlightScene.cs index 39ff120db..d9a3ef529 100644 --- a/FerramAerospaceResearch/FARKSPAddonFlightScene.cs +++ b/FerramAerospaceResearch/FARKSPAddonFlightScene.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -58,9 +58,7 @@ private void Awake() VoxelizationThreadpool.RunInMainThread = Debug.isDebugBuild; FARAeroSection.GenerateCrossFlowDragCurve(); - FARAeroStress.LoadStressTemplates(); FARAeroUtil.LoadAeroDataFromConfig(); - FARAnimOverrides.LoadAnimOverrides(); FARAeroForceDisplayScale = PhysicsGlobals.AeroForceDisplayScale; PhysicsGlobals.AeroForceDisplayScale = 0; diff --git a/FerramAerospaceResearch/FARKSPAddonMainMenuSetup.cs b/FerramAerospaceResearch/FARKSPAddonMainMenuSetup.cs index 6d7fe3082..9a9f1fb43 100644 --- a/FerramAerospaceResearch/FARKSPAddonMainMenuSetup.cs +++ b/FerramAerospaceResearch/FARKSPAddonMainMenuSetup.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARMathUtil.cs b/FerramAerospaceResearch/FARMathUtil.cs index 8bbdc3ecd..4672a829c 100644 --- a/FerramAerospaceResearch/FARMathUtil.cs +++ b/FerramAerospaceResearch/FARMathUtil.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,7 +44,6 @@ You should have received a copy of the GNU General Public License using System; using System.Globalization; -using FerramAerospaceResearch.FARUtils; namespace FerramAerospaceResearch { @@ -211,7 +210,7 @@ public static OptimizationResult BrentsMethod( double c = a, d = a, fc = function(c); int funcCalls = 3; - double s = b, fs = fb; + double s = b; bool flag = true; for (int iter = 0; iter < maxIter; iter++) @@ -284,7 +283,7 @@ public static OptimizationResult BrentsMethod( flag = false; } - fs = function(s); + double fs = function(s); funcCalls++; d = c; c = b; diff --git a/FerramAerospaceResearch/FARPM.cs b/FerramAerospaceResearch/FARPM.cs index a700cee51..36731cce3 100644 --- a/FerramAerospaceResearch/FARPM.cs +++ b/FerramAerospaceResearch/FARPM.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartExtensions.cs b/FerramAerospaceResearch/FARPartExtensions.cs index ac40737ea..46e3b8d3e 100644 --- a/FerramAerospaceResearch/FARPartExtensions.cs +++ b/FerramAerospaceResearch/FARPartExtensions.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/DebugVoxel.cs b/FerramAerospaceResearch/FARPartGeometry/DebugVoxel.cs deleted file mode 100644 index 21a0bab21..000000000 --- a/FerramAerospaceResearch/FARPartGeometry/DebugVoxel.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace FerramAerospaceResearch.FARPartGeometry -{ - public struct DebugVoxel - { - public float Scale; - public Vector3 Position; - - public DebugVoxel(Vector3 pos, float elementScale) - { - Scale = elementScale; - Position = pos; - } - - public Vector3 BottomLeft - { - get { return new Vector3(Position.x - Scale, Position.y - Scale, Position.z); } - } - - public Vector3 BottomRight - { - get { return new Vector3(Position.x + Scale, Position.y - Scale, Position.z); } - } - - public Vector3 TopRight - { - get { return new Vector3(Position.x + Scale, Position.y + Scale, Position.z); } - } - - public Vector3 TopLeft - { - get { return new Vector3(Position.x - Scale, Position.y + Scale, Position.z); } - } - - public struct Builder : IDebugVoxelMeshBuilder - { - /// - public int VerticesPerVoxel - { - get { return 4; } - } - - /// - public int UVChannels - { - get { return 1; } - } - - /// - public MeshTopology Topology - { - // using triangles since they have better performance than quads - get { return MeshTopology.Triangles; } - } - - /// - public int PrimitivesPerVoxel - { - get { return 2; } - } - - /// - public Material MeshMaterial - { - get - { - Material mat = FARAssets.ShaderCache.DebugVoxels.Material; - mat.mainTexture = FARAssets.TextureCache.VoxelTexture; - return mat; - } - } - - /// - public void Build( - DebugVoxel voxel, - List vertices, - List> uvs, - List indices, - int offset - ) - { - int counter = vertices.Count - offset; - - vertices.Add(voxel.BottomLeft); - uvs[0].Add(new Vector2(0, 0)); - - vertices.Add(voxel.TopLeft); - uvs[0].Add(new Vector2(0, 1)); - - vertices.Add(voxel.TopRight); - uvs[0].Add(new Vector2(1, 1)); - - vertices.Add(voxel.BottomRight); - uvs[0].Add(new Vector2(1, 0)); - - // left-handed triangles - indices.Add(counter); - indices.Add(counter + 1); - indices.Add(counter + 2); - - indices.Add(counter); - indices.Add(counter + 2); - indices.Add(counter + 3); - } - } - } -} diff --git a/FerramAerospaceResearch/FARPartGeometry/FARAnimOverrides.cs b/FerramAerospaceResearch/FARPartGeometry/FARAnimOverrides.cs deleted file mode 100644 index 6599bc72f..000000000 --- a/FerramAerospaceResearch/FARPartGeometry/FARAnimOverrides.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; - -// ReSharper disable once CheckNamespace -namespace FerramAerospaceResearch -{ - public static class FARAnimOverrides - { - private static Dictionary animOverrides; - - public static void LoadAnimOverrides() - { - animOverrides = new Dictionary(); - ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("FARAnimOverride"); - foreach (ConfigNode node in nodes) - { - string moduleName = node.GetValue("moduleName"); - string animNameField = node.GetValue("animNameField"); - if (moduleName != null && - animNameField != null && - moduleName != string.Empty && - animNameField != string.Empty) - animOverrides.Add(moduleName, animNameField); - } - } - - // ReSharper disable once UnusedMember.Global - public static bool OverrideExists(string moduleName) - { - return animOverrides.ContainsKey(moduleName); - } - - public static string FieldNameForModule(string moduleName) - { - try - { - return animOverrides[moduleName]; - } - catch (KeyNotFoundException) - { - return null; - } - } - } -} diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryMesh.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryMesh.cs index c33f21a8f..77c9d153a 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryMesh.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryMesh.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,7 +44,6 @@ You should have received a copy of the GNU General Public License using System; using FerramAerospaceResearch.FARThreading; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/AirbreathingEngineCrossSectionAdjuster.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/AirbreathingEngineCrossSectionAdjuster.cs index 88c2ac06b..a2415eccd 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/AirbreathingEngineCrossSectionAdjuster.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/AirbreathingEngineCrossSectionAdjuster.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/CompoundPartGeoUpdater.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/CompoundPartGeoUpdater.cs index 33aa5242d..35e9d9661 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/CompoundPartGeoUpdater.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/CompoundPartGeoUpdater.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/ICrossSectionAdjuster.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/ICrossSectionAdjuster.cs index 7b4f47ea3..5ddeffbff 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/ICrossSectionAdjuster.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/ICrossSectionAdjuster.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IGeometryUpdater.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IGeometryUpdater.cs index 499f3100b..0ed98326a 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IGeometryUpdater.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IGeometryUpdater.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntakeCrossSectionAdjuster.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntakeCrossSectionAdjuster.cs index 4dbba1f71..5f977d874 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntakeCrossSectionAdjuster.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntakeCrossSectionAdjuster.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,7 +43,6 @@ You should have received a copy of the GNU General Public License */ using System; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry.GeometryModification diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntegratedIntakeEngineCrossSectionAdjuster.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntegratedIntakeEngineCrossSectionAdjuster.cs index 7da58868b..139254149 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntegratedIntakeEngineCrossSectionAdjuster.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/IntegratedIntakeEngineCrossSectionAdjuster.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -42,7 +42,7 @@ You should have received a copy of the GNU General Public License http://forum.kerbalspaceprogram.com/threads/60863 */ -using FerramAerospaceResearch.FARUtils; + using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry.GeometryModification diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockJettisonTransformGeoUpdater.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockJettisonTransformGeoUpdater.cs index 68e4dccbf..69910b080 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockJettisonTransformGeoUpdater.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockJettisonTransformGeoUpdater.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcAsteroidGeoUpdater.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcAsteroidGeoUpdater.cs index 9d26c5a16..665a31676 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcAsteroidGeoUpdater.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcAsteroidGeoUpdater.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -42,7 +42,6 @@ You should have received a copy of the GNU General Public License http://forum.kerbalspaceprogram.com/threads/60863 */ -using FerramAerospaceResearch.FARUtils; namespace FerramAerospaceResearch.FARPartGeometry.GeometryModification { diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcFairingGeoUpdater.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcFairingGeoUpdater.cs index 93dc821f5..8a6c97566 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcFairingGeoUpdater.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryModification/StockProcFairingGeoUpdater.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,7 +44,6 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using FerramAerospaceResearch.FARThreading; -using FerramAerospaceResearch.FARUtils; using ProceduralFairings; using UnityEngine; diff --git a/FerramAerospaceResearch/FARPartGeometry/GeometryPartModule.cs b/FerramAerospaceResearch/FARPartGeometry/GeometryPartModule.cs index ec97f9fb0..16a27ed46 100644 --- a/FerramAerospaceResearch/FARPartGeometry/GeometryPartModule.cs +++ b/FerramAerospaceResearch/FARPartGeometry/GeometryPartModule.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,14 +43,14 @@ You should have received a copy of the GNU General Public License */ using System; +using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using FerramAerospaceResearch.FARGUI.FAREditorGUI; using FerramAerospaceResearch.FARPartGeometry.GeometryModification; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Settings; using KSP.UI.Screens; using TweakScale; using UnityEngine; @@ -84,23 +84,17 @@ public class GeometryPartModule : PartModule, IRescalable private int _sendUpdateTick; private int _meshesToUpdate = -1; - [SerializeField] - private bool forceUseColliders; + [SerializeField] private bool forceUseColliders; - [SerializeField] - private bool forceUseMeshes; + [SerializeField] private bool forceUseMeshes; - [SerializeField] - private bool ignoreForMainAxis; + [SerializeField] private bool ignoreForMainAxis; - [SerializeField] - private List ignoredTransforms, unignoredTransforms; + [SerializeField] private List ignoredTransforms, unignoredTransforms; - [SerializeField] - private bool ignoreIfNoRenderer; + [SerializeField] private bool ignoreIfNoRenderer = true; - [SerializeField] - private bool rebuildOnAnimation; + [SerializeField] private bool rebuildOnAnimation; public bool HasCrossSectionAdjusters { @@ -154,44 +148,34 @@ public void OnRescale(ScalingFactor factor) Rescale(factor.absolute.linear * Vector3.one); } - [Conditional("DEBUG")] private void DebugAddMesh(Transform t) { -#if DEBUG - debugInfo.meshes.Add(t.name); -#endif + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + debugInfo.meshes.Add(t.name); } - [Conditional("DEBUG")] private void DebugAddCollider(Transform t) { -#if DEBUG - debugInfo.colliders.Add(t.name); -#endif + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + debugInfo.colliders.Add(t.name); } - [Conditional("DEBUG")] private void DebugAddNoRenderer(Transform t) { -#if DEBUG - debugInfo.noRenderer.Add(t.name); -#endif + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + debugInfo.noRenderer.Add(t.name); } - [Conditional("DEBUG")] private void DebugClear() { -#if DEBUG - debugInfo.Clear(); -#endif + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + debugInfo.Clear(); } - [Conditional("DEBUG")] private void DebugPrint() { -#if DEBUG - debugInfo.Print(part); -#endif + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + debugInfo.Print(part); } public override void OnAwake() @@ -227,16 +211,67 @@ public override void OnStart(StartState state) _sceneSetup = true; //this exists only to ensure that OnStart has occurred first if (ignoreLayer0 < 0) ignoreLayer0 = LayerMask.NameToLayer("TransparentFX"); + + if (part.collider == null && + !part.Modules.Contains() && + !part.Modules.Contains() && + !part.Modules.Contains()) + return; + + if (HighLogic.LoadedSceneIsEditor) + StartCoroutine(DoRebuildMeshEditor()); + else if (HighLogic.LoadedSceneIsFlight) + StartCoroutine(DoRebuildMeshFlight()); + } + + private IEnumerator DoRebuildMeshFlight() + { + var waiter = new WaitForFixedUpdate(); + + while (!FlightGlobals.ready) + yield return waiter; + + // have to wait for the vessel to be loaded fully so that unused model transforms are disabled before + // gathering meshes for voxelization + while (part.vessel.HoldPhysics) + yield return waiter; + + RebuildAllMeshData(); + } + + private IEnumerator DoRebuildMeshEditor() + { + var waiter = new WaitForFixedUpdate(); + + // skip a physics frame to allow part setup to complete + yield return waiter; + + while (!ApplicationLauncher.Ready) + yield return waiter; + + // don't voxelize until the part is placed + while (EditorLogic.SelectedPart == part) + yield return waiter; + + RebuildAllMeshData(); } private void FixedUpdate() { - //waiting prevents changes in physics in flight or in predictions because the voxel switches to colliders rather than meshes - if (ReadyToBuildMesh()) - RebuildAllMeshData(); if (!_ready && _meshesToUpdate == 0) { overallMeshBounds = SetBoundsFromMeshes(); + + // @DRVeyl: Force all cubes to have the same bounds. Do this any time you recalculate a mesh + // (ie when handling animations since this breaks the cubes for anything other than the *current* cube.) + foreach (DragCube cube in part.DragCubes.Cubes) + { + cube.Size = overallMeshBounds.size; + cube.Center = overallMeshBounds.center; + } + + part.DragCubes.ForceUpdate(true, true); + _ready = true; } @@ -244,21 +279,6 @@ private void FixedUpdate() CheckAnimations(); } - private bool ReadyToBuildMesh() - { - bool returnVal = !_started && _sceneSetup; - - returnVal &= HighLogic.LoadedSceneIsFlight && FlightGlobals.ready || - HighLogic.LoadedSceneIsEditor && ApplicationLauncher.Ready; - - returnVal &= part.collider != null || - part.Modules.Contains() || - part.Modules.Contains() || - part.Modules.Contains(); - - return returnVal; - } - public void ClearMeshData() { meshDataList = null; @@ -455,13 +475,13 @@ private void SetupICrossSectionAdjusters() if (module is ModuleResourceIntake intake) { - IntegratedIntakeEngineCrossSectionAdjuster intakeAdjuster = + var intakeAdjuster = IntegratedIntakeEngineCrossSectionAdjuster.CreateAdjuster(intake, worldToVesselMatrix); crossSectionAdjusters.Add(intakeAdjuster); } else { - IntegratedIntakeEngineCrossSectionAdjuster intakeAdjuster = + var intakeAdjuster = IntegratedIntakeEngineCrossSectionAdjuster.CreateAdjuster(module, worldToVesselMatrix); crossSectionAdjusters.Add(intakeAdjuster); } @@ -475,14 +495,12 @@ private void SetupICrossSectionAdjusters() if (module is ModuleResourceIntake intake) { - IntakeCrossSectionAdjuster intakeAdjuster = - IntakeCrossSectionAdjuster.CreateAdjuster(intake, worldToVesselMatrix); + var intakeAdjuster = IntakeCrossSectionAdjuster.CreateAdjuster(intake, worldToVesselMatrix); crossSectionAdjusters.Add(intakeAdjuster); } else { - IntakeCrossSectionAdjuster intakeAdjuster = - IntakeCrossSectionAdjuster.CreateAdjuster(module, worldToVesselMatrix); + var intakeAdjuster = IntakeCrossSectionAdjuster.CreateAdjuster(module, worldToVesselMatrix); crossSectionAdjusters.Add(intakeAdjuster); } @@ -659,13 +677,13 @@ internal void DecrementMeshesToUpdate() private static MeshData GetColliderMeshData(Transform t) { - var mc = t.GetComponent(); + MeshCollider mc = t.GetComponent(); if (mc != null) { //we can't used mc.sharedMesh because it does not contain all the triangles or verts for some reason //must instead get the mesh filter and use its shared mesh - var mf = t.GetComponent(); + MeshFilter mf = t.GetComponent(); if (mf != null) { Mesh m = mf.sharedMesh; @@ -684,7 +702,7 @@ private static MeshData GetColliderMeshData(Transform t) } else { - var bc = t.GetComponent(); + BoxCollider bc = t.GetComponent(); if (bc != null) return CreateBoxMeshFromBoxCollider(bc.size, bc.center); } @@ -695,7 +713,7 @@ private static MeshData GetColliderMeshData(Transform t) private MeshData GetVisibleMeshData(Transform t, bool skipIfNoRenderer, bool onlyMeshes) { Mesh m; - var mf = t.GetComponent(); + MeshFilter mf = t.GetComponent(); //if we've decided to force use of meshes, we don't want colliders if (onlyMeshes && t.GetComponent() != null) @@ -705,21 +723,13 @@ private MeshData GetVisibleMeshData(Transform t, bool skipIfNoRenderer, bool onl { if (skipIfNoRenderer && !unignoredTransforms.Contains(t.name)) { - var mr = t.GetComponent(); + MeshRenderer mr = t.GetComponent(); if (mr == null) { DebugAddNoRenderer(t); return null; } } -#if DEBUG - else - { - var mr = t.GetComponent(); - if (mr == null) - DebugAddNoRenderer(t); - } -#endif m = mf.sharedMesh; @@ -732,7 +742,7 @@ private MeshData GetVisibleMeshData(Transform t, bool skipIfNoRenderer, bool onl return new MeshData(m.vertices, m.triangles, m.bounds); } - var smr = t.GetComponent(); + SkinnedMeshRenderer smr = t.GetComponent(); if (smr == null) return null; m = new Mesh(); @@ -995,7 +1005,6 @@ private void LoadList(ConfigNode node, string nodeName, ref List list) _ready = false; } -#if DEBUG private class DebugInfoBuilder { public readonly List meshes; @@ -1018,7 +1027,7 @@ public void Clear() public void Print(Part p) { - var sb = new StringBuilder(); + StringBuilder sb = StringBuilderCache.Acquire(); sb.Append($"{p.name} - mesh build info:"); if (meshes.Count > 0) { @@ -1043,6 +1052,5 @@ public void Print(Part p) } private readonly DebugInfoBuilder debugInfo = new DebugInfoBuilder(); -#endif } } diff --git a/FerramAerospaceResearch/FARPartGeometry/MeshData.cs b/FerramAerospaceResearch/FARPartGeometry/MeshData.cs index 316819435..ab063ae0d 100644 --- a/FerramAerospaceResearch/FARPartGeometry/MeshData.cs +++ b/FerramAerospaceResearch/FARPartGeometry/MeshData.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/PartGeometryExtensions.cs b/FerramAerospaceResearch/FARPartGeometry/PartGeometryExtensions.cs index b281d5553..595aaf02e 100644 --- a/FerramAerospaceResearch/FARPartGeometry/PartGeometryExtensions.cs +++ b/FerramAerospaceResearch/FARPartGeometry/PartGeometryExtensions.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,6 +44,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Reflection; +using FerramAerospaceResearch.Settings; using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry @@ -74,7 +75,7 @@ public static Bounds GetPartOverallMeshBoundsInBasis(this Part part, Matrix4x4 w Matrix4x4 matrix = worldToBasisMatrix * t.localToWorldMatrix; - var mc = t.GetComponent(); + MeshCollider mc = t.GetComponent(); Mesh m = null; if (mc != null) { @@ -84,7 +85,7 @@ public static Bounds GetPartOverallMeshBoundsInBasis(this Part part, Matrix4x4 w } - var mf = t.GetComponent(); + MeshFilter mf = t.GetComponent(); if (mf != null) { m = mf.sharedMesh; @@ -93,7 +94,7 @@ public static Bounds GetPartOverallMeshBoundsInBasis(this Part part, Matrix4x4 w } else { - var smr = t.GetComponent(); + SkinnedMeshRenderer smr = t.GetComponent(); if (smr != null) { m = new Mesh(); @@ -150,12 +151,12 @@ public static Bounds GetPartColliderBoundsInBasis(this Part part, Matrix4x4 worl { Transform t = transforms[i]; - var mc = t.GetComponent(); + MeshCollider mc = t.GetComponent(); Matrix4x4 matrix = worldToBasisMatrix * t.localToWorldMatrix; if (mc == null) { - var bc = t.GetComponent(); + BoxCollider bc = t.GetComponent(); if (bc != null) { bounds.Encapsulate(matrix.MultiplyPoint3x4(bc.bounds.min)); @@ -181,7 +182,7 @@ public static List PartModelTransformList(this Part p) { var returnList = new List(); - List ignoredModelTransforms = IgnoreModelTransformList(p); + List ignoredModelTransforms = FARPartModuleTransformExceptions.IgnoreModelTransformList(p); returnList.AddRange(p.FindModelComponents()); @@ -194,48 +195,6 @@ public static List PartModelTransformList(this Part p) return returnList; } - private static List IgnoreModelTransformList(this Part p) - { - var Transform = new List(); - if (ignorePartModuleTransforms == null) - LoadPartModuleTransformStrings(); - - // ReSharper disable once PossibleNullReferenceException - foreach (List currentPartModuleTransforms in ignorePartModuleTransforms) - { - //The first index of each list is the name of the part module; the rest are the transforms - if (!p.Modules.Contains(currentPartModuleTransforms[0])) - continue; - PartModule module = p.Modules[currentPartModuleTransforms[0]]; - - for (int j = 1; j < currentPartModuleTransforms.Count; ++j) - { - string transformString = - (string)module.GetType().GetField(currentPartModuleTransforms[j]).GetValue(module); - Transform.AddRange(string.IsNullOrEmpty(transformString) - ? p.FindModelComponents(currentPartModuleTransforms[j]) - : p.FindModelComponents(transformString)); - } - } - - foreach (Transform t in p.FindModelComponents()) - { - if (Transform.Contains(t)) - continue; - if (!t.gameObject.activeInHierarchy) - { - Transform.Add(t); - continue; - } - - string tag = t.tag.ToLowerInvariant(); - if (tag == "ladder" || tag == "airlock") - Transform.Add(t); - } - - return Transform; - } - private static void ProceduralAsteroidTransforms(Part p, List transformList) { var asteroid = (ModuleAsteroid)p.Modules["ModuleAsteroid"]; @@ -253,21 +212,5 @@ private static void GetChildTransforms(List transformList, Transform for (int i = 0; i < parent.childCount; ++i) GetChildTransforms(transformList, parent.GetChild(i)); } - - private static void LoadPartModuleTransformStrings() - { - ignorePartModuleTransforms = new List>(); - foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("FARPartModuleTransformExceptions")) - if (node != null) - foreach (ConfigNode template in node.GetNodes("FARPartModuleException")) - { - if (!template.HasValue("PartModuleName")) - continue; - var transformExceptions = new List {template.GetValue("PartModuleName")}; - transformExceptions.AddRange(template.GetValues("TransformException")); - - ignorePartModuleTransforms.Add(transformExceptions); - } - } } } diff --git a/FerramAerospaceResearch/FARPartGeometry/PartSizePair.cs b/FerramAerospaceResearch/FARPartGeometry/PartSizePair.cs index eba5ca793..43cf30111 100644 --- a/FerramAerospaceResearch/FARPartGeometry/PartSizePair.cs +++ b/FerramAerospaceResearch/FARPartGeometry/PartSizePair.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/PartSizePair4Bit.cs b/FerramAerospaceResearch/FARPartGeometry/PartSizePair4Bit.cs index 1d6ea538e..41c9f0217 100644 --- a/FerramAerospaceResearch/FARPartGeometry/PartSizePair4Bit.cs +++ b/FerramAerospaceResearch/FARPartGeometry/PartSizePair4Bit.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/PartSizePair8Bit.cs b/FerramAerospaceResearch/FARPartGeometry/PartSizePair8Bit.cs index 110dad728..0944540cd 100644 --- a/FerramAerospaceResearch/FARPartGeometry/PartSizePair8Bit.cs +++ b/FerramAerospaceResearch/FARPartGeometry/PartSizePair8Bit.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/PartTint.cs b/FerramAerospaceResearch/FARPartGeometry/PartTint.cs new file mode 100644 index 000000000..4e6ba4ec5 --- /dev/null +++ b/FerramAerospaceResearch/FARPartGeometry/PartTint.cs @@ -0,0 +1,57 @@ +using System.Collections; +using System.Collections.Generic; +using FerramAerospaceResearch.Settings; +using UnityEngine; + +namespace FerramAerospaceResearch.FARPartGeometry +{ + public class PartTint : IEnumerable> + { + private readonly ColorMap map; + private int count; + + private readonly Dictionary tints = + new Dictionary(ObjectReferenceEqualityComparer.Default); + + public PartTint() : this(VoxelizationSettings.Default) + { + } + + public PartTint(string mapName) + { + map = VoxelizationSettings.FirstOrDefault(mapName); + } + + public Color this[Part part] + { + get { return tints[part]; } + } + + public Color GetOrAdd(Part part) + { + return tints.TryGetValue(part, out Color tint) ? tint : Add(part); + } + + public Color Add(Part part) + { + Color tint = map.Get(count++); + tints.Add(part, tint); + return tint; + } + + public Dictionary.Enumerator GetEnumerator() + { + return tints.GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return tints.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return tints.GetEnumerator(); + } + } +} diff --git a/FerramAerospaceResearch/FARPartGeometry/PartTransformInfo.cs b/FerramAerospaceResearch/FARPartGeometry/PartTransformInfo.cs index a7f15bc11..f44881cb8 100644 --- a/FerramAerospaceResearch/FARPartGeometry/PartTransformInfo.cs +++ b/FerramAerospaceResearch/FARPartGeometry/PartTransformInfo.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARPartGeometry/VehicleVoxel.cs b/FerramAerospaceResearch/FARPartGeometry/VehicleVoxel.cs index 25814fd35..4340888bb 100644 --- a/FerramAerospaceResearch/FARPartGeometry/VehicleVoxel.cs +++ b/FerramAerospaceResearch/FARPartGeometry/VehicleVoxel.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,10 +45,11 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading; using ferram4; using FerramAerospaceResearch.FARThreading; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Geometry; using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry @@ -68,12 +69,12 @@ public class VehicleVoxel private static double maxLocation = 255; private static byte maxLocationByte = 255; private static bool useHigherResVoxels; - private DebugVoxelMesh voxelMesh; private readonly object _locker = new object(); + private DebugVoxelMesh voxelMesh; private double invElementSize; private VoxelChunk[,,] voxelChunks; - private HashSet overridingParts; + private Dictionary partPriorities; private int xLength, yLength, zLength; private int xCellLength, yCellLength, zCellLength; private int threadsQueued; @@ -171,7 +172,7 @@ bool solidify var min = new Vector3d(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity); var max = new Vector3d(double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity); - overridingParts = new HashSet(ObjectReferenceEqualityComparer.Default); + partPriorities = new Dictionary(ObjectReferenceEqualityComparer.Default); //Determine bounds and "overriding parts" from geoModules foreach (GeometryPartModule m in geoModules) { @@ -203,8 +204,8 @@ bool solidify min = Vector3d.Min(min, minBounds); max = Vector3d.Max(max, maxBounds); - if (CheckPartForOverridingPartList(m)) - overridingParts.Add(m.part); + if (!(m.part is null)) + partPriorities.Add(m.part, PartPriorityLevel(m)); } Vector3d size = max - min; @@ -267,23 +268,25 @@ bool solidify } } - private static bool CheckPartForOverridingPartList(GeometryPartModule g) + private static int PartPriorityLevel(GeometryPartModule g) { if (g.part is null) - return false; + return int.MinValue; PartModuleList modules = g.part.Modules; - bool returnVal = modules.Contains() || - modules.Contains() || - modules.Contains() || - modules.Contains() || - modules.Contains("ProceduralFairingBase") || - modules.Contains("ProceduralFairingSide"); - if (g.HasCrossSectionAdjusters) - returnVal |= g.MaxCrossSectionAdjusterArea > 0; + if (g.HasCrossSectionAdjusters && g.MaxCrossSectionAdjusterArea > 0) + return int.MaxValue; + if (modules.Contains("ProceduralFairingSide") || modules.Contains()) + return 3; + if (modules.Contains("ProceduralFairingBase")) + return 2; + if (modules.Contains() || + modules.Contains() || + modules.Contains()) + return 1; - return returnVal; + return -1; } private void BuildVoxel(List geoModules, bool multiThreaded, bool solidify) @@ -407,10 +410,10 @@ out double maxCrossSectionArea sectionThickness = ElementSize; - Matrix4x4 sectionNormalToVesselCoords = Matrix4x4.TRS(Vector3.zero, - Quaternion.FromToRotation(new Vector3(0, 0, 1), - orientationVector), - Vector3.one); + var sectionNormalToVesselCoords = Matrix4x4.TRS(Vector3.zero, + Quaternion.FromToRotation(new Vector3(0, 0, 1), + orientationVector), + Vector3.one); Matrix4x4 vesselToSectionNormal = sectionNormalToVesselCoords.inverse; //Code has multiple optimizations to take advantage of the limited range of values that are included. They are listed below @@ -482,7 +485,7 @@ out double maxCrossSectionArea jSect1 = jMin >> 3; jSect2 >>= 3; - jSect3 = (jMax - 1) >> 3; + jSect3 = jMax - 1 >> 3; if (jSect1 >= yLength) //if the smallest sect is above the limit, they all are continue; @@ -739,7 +742,7 @@ out double maxCrossSectionArea iSect1 = iMin >> 3; iSect2 >>= 3; - iSect3 = (iMax - 1) >> 3; + iSect3 = iMax - 1 >> 3; if (iSect1 >= xLength) //if the smallest sect is above the limit, they all are continue; @@ -998,7 +1001,7 @@ out double maxCrossSectionArea kSect1 = kMin >> 3; kSect2 >>= 3; - kSect3 = (kMax - 1) >> 3; + kSect3 = kMax - 1 >> 3; if (kSect1 >= zLength) //if the smallest sect is above the limit, they all are continue; @@ -1246,7 +1249,7 @@ int k ) { // ReSharper disable BitwiseOperatorOnEnumWithoutFlags - var filledPlanes = VoxelOrientationPlane.NONE; + VoxelOrientationPlane filledPlanes = VoxelOrientationPlane.NONE; bool partGetsForces = true; Part p = voxel.part; @@ -1363,16 +1366,35 @@ public void VisualizeVoxel(Matrix4x4 vesselLocalToWorldMatrix) { FARLogger.Debug("Creating visual voxels"); var builder = new DebugVoxel.Builder(); + var tintMap = new PartTint(); voxelMesh.Clear(builder, xLength * yLength * zLength * 128, false); for (int i = 0; i < xLength; i++) { for (int j = 0; j < yLength; j++) { for (int k = 0; k < zLength; k++) - voxelChunks[i, j, k]?.VisualizeVoxels(vesselLocalToWorldMatrix, voxelMesh, builder); + voxelChunks[i, j, k]?.VisualizeVoxels(vesselLocalToWorldMatrix, tintMap, voxelMesh, builder); } } + // TODO: should be a list view in GUI + if (FARLogger.IsEnabledFor(LogLevel.Debug)) + { + StringBuilder sb = StringBuilderCache.Acquire(); + sb.AppendLine("Tints applied:"); + foreach (KeyValuePair pair in tintMap) + { + sb.Append(pair.Key.name) + .Append(" (") + .Append(pair.Key.persistentId) + .Append(") = ") + .AppendLine(pair.Value.ToString()); + } + + FARLogger.Debug(sb); + sb.Release(); + } + VoxelizationThreadpool.Instance.RunOnMainThread(() => { voxelMesh.Apply(builder); @@ -1404,7 +1426,7 @@ private void SetVoxelPointNoLock(int i, int j, int k) iSec * 8, jSec * 8, kSec * 8, - overridingParts, + partPriorities, useHigherResVoxels); else section.SetChunk(ElementSize, @@ -1412,7 +1434,7 @@ private void SetVoxelPointNoLock(int i, int j, int k) iSec * 8, jSec * 8, kSec * 8, - overridingParts); + partPriorities); voxelChunks[iSec, jSec, kSec] = section; } @@ -1445,7 +1467,7 @@ private void SetVoxelPointPartOnlyNoLock(int i, int j, int k, Part part) iSec * 8, jSec * 8, kSec * 8, - overridingParts, + partPriorities, useHigherResVoxels); else section.SetChunk(ElementSize, @@ -1453,7 +1475,7 @@ private void SetVoxelPointPartOnlyNoLock(int i, int j, int k, Part part) iSec * 8, jSec * 8, kSec * 8, - overridingParts); + partPriorities); voxelChunks[iSec, jSec, kSec] = section; } @@ -1485,7 +1507,7 @@ private void SetVoxelPointNoLock(int i, int j, int k, Part part) iSec * 8, jSec * 8, kSec * 8, - overridingParts, + partPriorities, useHigherResVoxels); else section.SetChunk(ElementSize, @@ -1493,7 +1515,7 @@ private void SetVoxelPointNoLock(int i, int j, int k, Part part) iSec * 8, jSec * 8, kSec * 8, - overridingParts); + partPriorities); voxelChunks[iSec, jSec, kSec] = section; } @@ -1529,7 +1551,7 @@ private void SetVoxelPoint(int i, int j, int k, Part part, VoxelOrientationPlane iSec * 8, jSec * 8, kSec * 8, - overridingParts, + partPriorities, useHigherResVoxels); else section.SetChunk(ElementSize, @@ -1537,7 +1559,7 @@ private void SetVoxelPoint(int i, int j, int k, Part part, VoxelOrientationPlane iSec * 8, jSec * 8, kSec * 8, - overridingParts); + partPriorities); voxelChunks[iSec, jSec, kSec] = section; } @@ -2186,7 +2208,7 @@ private Vector4d CalculateEquationOfPlaneInIndices(Vector3d pt1, Vector3d pt2, V Vector3d p1p2 = pt2 - pt1; Vector3d p1p3 = pt3 - pt1; - Vector3d tmp = Vector3d.Cross(p1p2, p1p3); + var tmp = Vector3d.Cross(p1p2, p1p3); var result = new Vector4d(tmp.x, tmp.y, tmp.z); @@ -2205,7 +2227,7 @@ private Vector4d CalculateEquationOfPlane(Vector3d pt1, Vector3d pt2, Vector3d p Vector3d p1p2 = pt2 - pt1; Vector3d p1p3 = pt3 - pt1; - Vector3d tmp = Vector3d.Cross(p1p2, p1p3); + var tmp = Vector3d.Cross(p1p2, p1p3); var result = new Vector4d(tmp.x, tmp.y, tmp.z); diff --git a/FerramAerospaceResearch/FARPartGeometry/VoxelChunk.cs b/FerramAerospaceResearch/FARPartGeometry/VoxelChunk.cs index f8047debb..8b3762c7a 100644 --- a/FerramAerospaceResearch/FARPartGeometry/VoxelChunk.cs +++ b/FerramAerospaceResearch/FARPartGeometry/VoxelChunk.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -42,7 +42,9 @@ You should have received a copy of the GNU General Public License http://forum.kerbalspaceprogram.com/threads/60863 */ +using System; using System.Collections.Generic; +using FerramAerospaceResearch.Geometry; using UnityEngine; namespace FerramAerospaceResearch.FARPartGeometry @@ -50,7 +52,7 @@ namespace FerramAerospaceResearch.FARPartGeometry internal class VoxelChunk { private readonly PartSizePair[] voxelPoints; - private HashSet overridingParts; + private Dictionary partPriorities; private double _size; @@ -63,7 +65,7 @@ public VoxelChunk( int iOffset, int jOffset, int kOffset, - HashSet overridingParts, + Dictionary partPriorities, bool usePartSize256 ) { @@ -79,7 +81,7 @@ bool usePartSize256 this.lowerCorner = lowerCorner; - this.overridingParts = overridingParts; + this.partPriorities = partPriorities; } // ReSharper disable ParameterHidesMember -> update member values @@ -89,13 +91,13 @@ public void SetChunk( int iOffset, int jOffset, int kOffset, - HashSet overridingParts + Dictionary partPriorities ) { _size = size; offset = iOffset + 8 * jOffset + 64 * kOffset; this.lowerCorner = lowerCorner; - this.overridingParts = overridingParts; + this.partPriorities = partPriorities; // ReSharper restore ParameterHidesMember } @@ -107,7 +109,7 @@ public void ClearChunk() foreach (PartSizePair voxelPoint in voxelPoints) voxelPoint.Clear(); - overridingParts = null; + partPriorities = null; } //Use when locking is unnecessary and only to change size, not part @@ -202,12 +204,19 @@ private void SetPart(Part p, int index, VoxelOrientationPlane plane, byte locati Part currentPart = pair.part; //if we update the plane location with this, then we can consider replacing the part here. Otherwise, we don't bool largerThanLast = pair.SetPlaneLocation(plane, location); - if (currentPart is null || - overridingParts.Contains(p) || - largerThanLast && !overridingParts.Contains(currentPart)) + int currentPriority = PartPriority(currentPart); + int newPriority = PartPriority(p); + + if (newPriority > currentPriority || + largerThanLast && currentPriority <= 0) pair.part = p; } + private int PartPriority(Part p) + { + return (!(p is null) && partPriorities.TryGetValue(p, out int v)) ? v : int.MinValue; + } + // ReSharper disable once UnusedMember.Global public bool VoxelPointExistsLocalIndex(int zeroBaseIndex) { @@ -264,8 +273,12 @@ public PartSizePair GetVoxelPartSizePairGlobalIndex(int i, int j, int k) return voxelPoints[index]; } - public void VisualizeVoxels(Matrix4x4 vesselLocalToWorldMatrix, DebugVoxelMesh voxelMesh, T builder) - where T : IDebugVoxelMeshBuilder + public void VisualizeVoxels( + Matrix4x4 vesselLocalToWorldMatrix, + PartTint tint, + DebugVoxelMesh voxelMesh, + T builder + ) where T : IDebugVoxelMeshBuilder { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) @@ -281,8 +294,9 @@ public void VisualizeVoxels(Matrix4x4 vesselLocalToWorldMatrix, DebugVoxelMes elementSize *= _size * 0.5f; var vx = new DebugVoxel(vesselLocalToWorldMatrix.MultiplyPoint3x4(lowerCorner + - new Vector3d(i, j, k) * _size), - (float)elementSize); + new Vector3d(i, j, k) * _size), + (float)elementSize, + tint.GetOrAdd(pair.part)); voxelMesh.Add(builder, vx); } } diff --git a/FerramAerospaceResearch/FARPartGeometry/VoxelCrossSection.cs b/FerramAerospaceResearch/FARPartGeometry/VoxelCrossSection.cs index d6e4d82fb..30e787535 100644 --- a/FerramAerospaceResearch/FARPartGeometry/VoxelCrossSection.cs +++ b/FerramAerospaceResearch/FARPartGeometry/VoxelCrossSection.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARSettingsScenarioModule.cs b/FerramAerospaceResearch/FARSettingsScenarioModule.cs index c16adf36a..836569fcb 100644 --- a/FerramAerospaceResearch/FARSettingsScenarioModule.cs +++ b/FerramAerospaceResearch/FARSettingsScenarioModule.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -47,7 +47,7 @@ You should have received a copy of the GNU General Public License using FerramAerospaceResearch.FARGUI; using FerramAerospaceResearch.FARGUI.FARFlightGUI; using FerramAerospaceResearch.FARPartGeometry; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Geometry; using UnityEngine; namespace FerramAerospaceResearch @@ -128,7 +128,7 @@ public override void OnSave(ConfigNode node) node.AddValue("numVoxelsDebrisVessel", voxelSettings.numVoxelsDebrisVessel); node.AddValue("minPhysTicksPerUpdate", voxelSettings.minPhysTicksPerUpdate); node.AddValue("useHigherResVoxelPoints", voxelSettings.useHigherResVoxelPoints); - node.AddValue("use32BitIndices", voxelSettings.use32BitIndices); + node.AddValue("use32BitIndices", DebugVoxelMesh.Use32BitIndices); node.AddValue("index", settings.index); FlightGUI.SaveActiveData(); @@ -166,7 +166,7 @@ public override void OnLoad(ConfigNode node) if (node.HasValue("useHigherResVoxelPoints")) voxelSettings.useHigherResVoxelPoints = bool.Parse(node.GetValue("useHigherResVoxelPoints")); if (node.HasValue("use32BitIndices")) - voxelSettings.use32BitIndices = bool.Parse(node.GetValue("use32BitIndices")); + DebugVoxelMesh.Use32BitIndices = bool.Parse(node.GetValue("use32BitIndices")); if (index == -1) { @@ -311,10 +311,10 @@ public void DisplaySelection() GUILayout.BeginHorizontal(); GUILayout.Label("Mesh: use 32 bit indices: "); - voxelSettings.use32BitIndices = GUILayout.Toggle(voxelSettings.use32BitIndices, - voxelSettings.use32BitIndices - ? "32 bit indices" - : "16 bit indices"); + DebugVoxelMesh.Use32BitIndices = GUILayout.Toggle(DebugVoxelMesh.Use32BitIndices, + DebugVoxelMesh.Use32BitIndices + ? "32 bit indices" + : "16 bit indices"); GUILayout.EndHorizontal(); GUILayout.EndVertical(); @@ -359,25 +359,17 @@ public class FARVoxelSettings public int numVoxelsDebrisVessel; public int minPhysTicksPerUpdate; public bool useHigherResVoxelPoints; - public bool use32BitIndices; public FARVoxelSettings() : this(250000, 20000, 80, true) { } - public FARVoxelSettings( - int vesselCount, - int debrisCount, - int minPhysTicks, - bool higherResVoxPoints, - bool use32BitIndices = false - ) + public FARVoxelSettings(int vesselCount, int debrisCount, int minPhysTicks, bool higherResVoxPoints) { numVoxelsControllableVessel = vesselCount; numVoxelsDebrisVessel = debrisCount; minPhysTicksPerUpdate = minPhysTicks; useHigherResVoxelPoints = higherResVoxPoints; - this.use32BitIndices = use32BitIndices; } } } diff --git a/FerramAerospaceResearch/FARThreading/ThreadBarrier.cs b/FerramAerospaceResearch/FARThreading/ThreadBarrier.cs index 93d066752..a347eb172 100644 --- a/FerramAerospaceResearch/FARThreading/ThreadBarrier.cs +++ b/FerramAerospaceResearch/FARThreading/ThreadBarrier.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/FARThreading/ThreadSafeDebugLogger.cs b/FerramAerospaceResearch/FARThreading/ThreadSafeDebugLogger.cs index 8e7efb999..58c512791 100644 --- a/FerramAerospaceResearch/FARThreading/ThreadSafeDebugLogger.cs +++ b/FerramAerospaceResearch/FARThreading/ThreadSafeDebugLogger.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -46,7 +46,6 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Diagnostics; using System.Text; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch.FARThreading diff --git a/FerramAerospaceResearch/FARThreading/VoxelizationThreadpool.cs b/FerramAerospaceResearch/FARThreading/VoxelizationThreadpool.cs index 3c3bb17ba..bede52d76 100644 --- a/FerramAerospaceResearch/FARThreading/VoxelizationThreadpool.cs +++ b/FerramAerospaceResearch/FARThreading/VoxelizationThreadpool.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using System.Threading; -using FerramAerospaceResearch.FARUtils; namespace FerramAerospaceResearch.FARThreading { @@ -100,7 +99,6 @@ public bool inMainThread private void SetupMainThread() { _mainThread = Thread.CurrentThread; - FARLogger.Debug("Main thread: " + _mainThread.Name); } private void ExecuteQueuedVoxelization() diff --git a/FerramAerospaceResearch/FARUtils/FARLogger.cs b/FerramAerospaceResearch/FARUtils/FARLogger.cs deleted file mode 100644 index 4f7dfab67..000000000 --- a/FerramAerospaceResearch/FARUtils/FARLogger.cs +++ /dev/null @@ -1,364 +0,0 @@ -/* -Ferram Aerospace Research v0.15.11.4 "Mach" -========================= -Copyright 2019, Daumantas Kavolis, aka dkavolis - - This file is part of Ferram Aerospace Research. - - Ferram Aerospace Research is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Ferram Aerospace Research is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Ferram Aerospace Research. If not, see . - - Serious thanks: a.g., for tons of bugfixes and code-refactorings - stupid_chris, for the RealChuteLite implementation - Taverius, for correcting a ton of incorrect values - Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts - sarbian, for refactoring code for working with MechJeb, and the Module Manager updates - ialdabaoth (who is awesome), who originally created Module Manager - Regex, for adding RPM support - DaMichel, for some ferramGraph updates and some control surface-related features - Duxwing, for copy editing the readme - - CompatibilityChecker by Majiir, BSD 2-clause http: //opensource.org/licenses/BSD-2-Clause - - Part.cfg changes powered by sarbian & ialdabaoth's ModuleManager plugin; used with permission - http: //forum.kerbalspaceprogram.com/threads/55219 - - ModularFLightIntegrator by Sarbian, Starwaster and Ferram4, MIT: http: //opensource.org/licenses/MIT - http: //forum.kerbalspaceprogram.com/threads/118088 - - Toolbar integration powered by blizzy78's Toolbar plugin; used with permission - http: //forum.kerbalspaceprogram.com/threads/60863 - */ - -// defining symbols here doesn't work, see https://forum.unity.com/threads/conditionalattribute-not-working.469720/ -// #if !DEBUG && !INFO && !WARNING && !ERROR -// #define INFO -// #endif - -using System; -using System.Diagnostics; -using Object = UnityEngine.Object; - -// ReSharper disable InvocationIsSkipped UnusedMember.Global - -namespace FerramAerospaceResearch.FARUtils -{ - public static class FARLogger - { - public static readonly string defaultTag = $"[FAR {FARVersion.String}] "; - private static readonly string[] separators = {"\r\n", "\r", "\n"}; - - public static string Tag { get; } = defaultTag; - - [Conditional("DEBUG"), Conditional("INFO")] - public static void Info(object message) - { - UnityEngine.Debug.Log(Tag + message); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void Info(object message, Object context) - { - UnityEngine.Debug.Log(Tag + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoFormat(string format, params object[] args) - { - UnityEngine.Debug.LogFormat(Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoFormat(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogFormat(context, Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoWithCaller(object message) - { - UnityEngine.Debug.Log(Tag + GetCallerInfo() + " - " + message); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoWithCaller(object message, Object context) - { - UnityEngine.Debug.Log(Tag + GetCallerInfo() + " - " + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoFormatWithCaller(string format, params object[] args) - { - UnityEngine.Debug.LogFormat(Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO")] - public static void InfoFormatWithCaller(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogFormat(context, Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG")] - public static void Debug(object message) - { - UnityEngine.Debug.Log(Tag + message); - } - - [Conditional("DEBUG")] - public static void Debug(object message, Object context) - { - UnityEngine.Debug.Log(Tag + message, context); - } - - [Conditional("DEBUG")] - public static void DebugFormat(string format, params object[] args) - { - UnityEngine.Debug.LogFormat(Tag + format, args); - } - - [Conditional("DEBUG")] - public static void DebugFormat(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogFormat(context, Tag + format, args); - } - - [Conditional("DEBUG")] - public static void DebugWithCaller(object message) - { - UnityEngine.Debug.Log(Tag + GetCallerInfo() + " - " + message); - } - - [Conditional("DEBUG")] - public static void DebugWithCaller(object message, Object context) - { - UnityEngine.Debug.Log(Tag + GetCallerInfo() + " - " + message, context); - } - - [Conditional("DEBUG")] - public static void DebugFormatWithCaller(string format, params object[] args) - { - UnityEngine.Debug.LogFormat(Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG")] - public static void DebugFormatWithCaller(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogFormat(context, Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void Warning(object message) - { - UnityEngine.Debug.LogWarning(Tag + message); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void Warning(object message, Object context) - { - UnityEngine.Debug.LogWarning(Tag + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningFormat(string format, params object[] args) - { - UnityEngine.Debug.LogWarningFormat(Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningFormat(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogWarningFormat(context, Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningWithCaller(object message) - { - UnityEngine.Debug.LogWarning(Tag + GetCallerInfo() + " - " + message); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningWithCaller(object message, Object context) - { - UnityEngine.Debug.LogWarning(Tag + GetCallerInfo() + " - " + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningFormatWithCaller(string format, params object[] args) - { - UnityEngine.Debug.LogWarningFormat(Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING")] - public static void WarningFormatWithCaller(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogWarningFormat(context, Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void Error(object message) - { - UnityEngine.Debug.LogError(Tag + message); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void Error(object message, Object context) - { - UnityEngine.Debug.LogError(Tag + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorFormat(string format, params object[] args) - { - UnityEngine.Debug.LogErrorFormat(Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorFormat(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogErrorFormat(context, Tag + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorWithCaller(object message) - { - UnityEngine.Debug.LogError(Tag + GetCallerInfo() + " - " + message); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorWithCaller(object message, Object context) - { - UnityEngine.Debug.LogError(Tag + GetCallerInfo() + " - " + message, context); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorFormatWithCaller(string format, params object[] args) - { - UnityEngine.Debug.LogErrorFormat(Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("DEBUG"), Conditional("INFO"), Conditional("WARNING"), Conditional("ERROR")] - public static void ErrorFormatWithCaller(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogErrorFormat(context, Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void Assertion(object message) - { - UnityEngine.Debug.LogAssertion(Tag + message); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void Assertion(object message, Object context) - { - UnityEngine.Debug.LogAssertion(Tag + message, context); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionFormat(string format, params object[] args) - { - UnityEngine.Debug.LogAssertionFormat(Tag + format, args); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionFormat(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogAssertionFormat(context, Tag + format, args); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionWithCaller(object message) - { - UnityEngine.Debug.LogAssertion(Tag + GetCallerInfo() + " - " + message); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionWithCaller(object message, Object context) - { - UnityEngine.Debug.LogAssertion(Tag + GetCallerInfo() + " - " + message, context); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionFormatWithCaller(string format, params object[] args) - { - UnityEngine.Debug.LogAssertionFormat(Tag + GetCallerInfo() + " - " + format, args); - } - - [Conditional("UNITY_ASSERTIONS")] - public static void AssertionFormatWithCaller(Object context, string format, params object[] args) - { - UnityEngine.Debug.LogAssertionFormat(context, Tag + GetCallerInfo() + " - " + format, args); - } - - public static void Exception(Exception exception) - { - Error("Logged exception:"); - UnityEngine.Debug.LogException(exception); - } - - public static void Exception(Exception exception, Object context) - { - Error("Logged exception:"); - UnityEngine.Debug.LogException(exception, context); - } - - public static void ExceptionWithCaller(Exception exception) - { - Error(GetCallerInfo() + " - Logged exception:"); - UnityEngine.Debug.LogException(exception); - } - - public static void ExceptionWithCaller(Exception exception, Object context) - { - Error(GetCallerInfo() + " - Logged exception:"); - UnityEngine.Debug.LogException(exception, context); - } - - //http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx - private static string GetCallerInfo() - { - // frame 0 - GetCallerInfo - // frame 1 - one of the log methods - // frame 2 - source of the log method caller - // StackFrame frame = new StackFrame(2, true); - // string method = frame.GetMethod().Name; - // #if DEBUG - // // release mode doesn't have debug symbols - // string fileName = frame.GetFileName(); - // int lineNumber = frame.GetFileLineNumber(); - - // return $"{fileName}({lineNumber}):{method}"; - // #else - // return method - // #endif - string trace = Environment.StackTrace; - if (string.IsNullOrEmpty(trace)) - return ""; - string[] lines = trace.Split(separators, StringSplitOptions.None); - string caller = lines[3].Trim(); - return caller.Substring(0, caller.IndexOf("(", StringComparison.Ordinal)); - } - -#if NET_NEWER_4_5 - // For reference if KSP .NET version is updated - // there's a much faster method to obtain caller info in .NET >= 4.5 - public static string MessageWithCallerInfo(object message, - [CallerMemberName] string memberName = "", - [CallerFilePath] string fileName = "", - [CallerLineNumber] int lineNumber = 0) - { - return fileName + "(" + lineNumber + "):" + memberName + " - " + message; - } -#endif - } -} diff --git a/FerramAerospaceResearch/FARUtils/FARVersion.cs b/FerramAerospaceResearch/FARUtils/FARVersion.cs deleted file mode 100644 index 9a1d27822..000000000 --- a/FerramAerospaceResearch/FARUtils/FARVersion.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* -Ferram Aerospace Research v0.15.11.4 "Mach" -========================= -Copyright 2019, Daumantas Kavolis, aka dkavolis - - This file is part of Ferram Aerospace Research. - - Ferram Aerospace Research is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Ferram Aerospace Research is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Ferram Aerospace Research. If not, see . - - Serious thanks: a.g., for tons of bugfixes and code-refactorings - stupid_chris, for the RealChuteLite implementation - Taverius, for correcting a ton of incorrect values - Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts - sarbian, for refactoring code for working with MechJeb, and the Module Manager updates - ialdabaoth (who is awesome), who originally created Module Manager - Regex, for adding RPM support - DaMichel, for some ferramGraph updates and some control surface-related features - Duxwing, for copy editing the readme - - CompatibilityChecker by Majiir, BSD 2-clause http: //opensource.org/licenses/BSD-2-Clause - - Part.cfg changes powered by sarbian & ialdabaoth's ModuleManager plugin; used with permission - http: //forum.kerbalspaceprogram.com/threads/55219 - - ModularFLightIntegrator by Sarbian, Starwaster and Ferram4, MIT: http: //opensource.org/licenses/MIT - http: //forum.kerbalspaceprogram.com/threads/118088 - - Toolbar integration powered by blizzy78's Toolbar plugin; used with permission - http: //forum.kerbalspaceprogram.com/threads/60863 - */ - -namespace FerramAerospaceResearch.FARUtils -{ - public class FARVersion - { - // using byte here because 0-255 should be enough for any version number - public const byte Major = 0; - public const byte Minor = 15; - public const byte Build = 11; - public const byte Revision = 4; - public const string Name = "Mach"; - - public static readonly string String = $"v{Major}.{Minor}.{Build}.{Revision}"; - public static readonly string VersionString = $"{String} '{Name}'"; - } -} diff --git a/FerramAerospaceResearch/FARUtils/ShaderPropertyIds.cs b/FerramAerospaceResearch/FARUtils/ShaderPropertyIds.cs deleted file mode 100644 index 7f8fb9436..000000000 --- a/FerramAerospaceResearch/FARUtils/ShaderPropertyIds.cs +++ /dev/null @@ -1,10 +0,0 @@ -using UnityEngine; - -namespace FerramAerospaceResearch.FARUtils -{ - public static class ShaderPropertyIds - { - public static int Color { get; } = Shader.PropertyToID("_Color"); - public static int Cutoff { get; } = Shader.PropertyToID("_Cutoff"); - } -} diff --git a/FerramAerospaceResearch/FARWind.cs b/FerramAerospaceResearch/FARWind.cs index fbef10f75..2b305ea7a 100644 --- a/FerramAerospaceResearch/FARWind.cs +++ b/FerramAerospaceResearch/FARWind.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -43,7 +43,6 @@ You should have received a copy of the GNU General Public License */ using System; -using FerramAerospaceResearch.FARUtils; using UnityEngine; namespace FerramAerospaceResearch @@ -81,7 +80,7 @@ public static Vector3 GetWind(CelestialBody body, Part part, Vector3 position) } catch (Exception e) { - FARLogger.Info("[FARWIND] Exception! " + e.Message + e.StackTrace); + FARLogger.InfoFormat("[FARWIND] Exception! {0}\n{1}", e.Message, e.StackTrace); return Vector3.zero; } } diff --git a/FerramAerospaceResearch/FerramAerospaceResearch.csproj b/FerramAerospaceResearch/FerramAerospaceResearch.csproj index ea6d2fd8b..e9887b190 100644 --- a/FerramAerospaceResearch/FerramAerospaceResearch.csproj +++ b/FerramAerospaceResearch/FerramAerospaceResearch.csproj @@ -21,7 +21,7 @@ portable false $(SolutionDir)bin\$(Configuration)\ - DEBUG;TRACE + DEBUG;TRACE;ASSERT;LOG_TRACE prompt 4 true @@ -86,18 +86,19 @@ + - + @@ -106,39 +107,34 @@ + - - - - + - - - @@ -182,14 +178,27 @@ + + + + + + - - + + + + + + + {8e4e9138-a949-4ded-a08c-4ce3442887b4} + FerramAerospaceResearch.Base + {0ccfed24-728c-432b-9fdc-30bef1116ede} ferramGraph diff --git a/FerramAerospaceResearch/InstallChecker.cs b/FerramAerospaceResearch/InstallChecker.cs index 1fb418d09..70a31f233 100644 --- a/FerramAerospaceResearch/InstallChecker.cs +++ b/FerramAerospaceResearch/InstallChecker.cs @@ -9,11 +9,12 @@ using System.Linq; using System.Reflection; using UnityEngine; -using FerramAerospaceResearch.FARUtils; + +// ReSharper disable PossibleMultipleEnumeration namespace FerramAerospaceResearch { - [KSPAddon(KSPAddon.Startup.Instantly, true)] + [FARAddon(800)] internal class InstallChecker : MonoBehaviour { protected void Start() diff --git a/FerramAerospaceResearch/LEGACYferram4/FARAction.cs b/FerramAerospaceResearch/LEGACYferram4/FARAction.cs index 7fe7a5bd0..134a440bb 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARAction.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARAction.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System; using FerramAerospaceResearch; using FerramAerospaceResearch.FARGUI; -using FerramAerospaceResearch.FARUtils; using KSP.IO; using KSP.Localization; using UnityEngine; diff --git a/FerramAerospaceResearch/LEGACYferram4/FARAeroStress.cs b/FerramAerospaceResearch/LEGACYferram4/FARAeroStress.cs deleted file mode 100644 index d941b20d4..000000000 --- a/FerramAerospaceResearch/LEGACYferram4/FARAeroStress.cs +++ /dev/null @@ -1,260 +0,0 @@ -/* -Ferram Aerospace Research v0.15.11.4 "Mach" -========================= -Aerodynamics model for Kerbal Space Program - -Copyright 2019, Michael Ferrara, aka Ferram4 - - This file is part of Ferram Aerospace Research. - - Ferram Aerospace Research is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Ferram Aerospace Research is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Ferram Aerospace Research. If not, see . - - Serious thanks: a.g., for tons of bugfixes and code-refactorings - stupid_chris, for the RealChuteLite implementation - Taverius, for correcting a ton of incorrect values - Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts - sarbian, for refactoring code for working with MechJeb, and the Module Manager updates - ialdabaoth (who is awesome), who originally created Module Manager - Regex, for adding RPM support - DaMichel, for some ferramGraph updates and some control surface-related features - Duxwing, for copy editing the readme - - CompatibilityChecker by Majiir, BSD 2-clause http://opensource.org/licenses/BSD-2-Clause - - Part.cfg changes powered by sarbian & ialdabaoth's ModuleManager plugin; used with permission - http://forum.kerbalspaceprogram.com/threads/55219 - - ModularFLightIntegrator by Sarbian, Starwaster and Ferram4, MIT: http://opensource.org/licenses/MIT - http://forum.kerbalspaceprogram.com/threads/118088 - - Toolbar integration powered by blizzy78's Toolbar plugin; used with permission - http://forum.kerbalspaceprogram.com/threads/60863 - */ - -using System.Collections.Generic; - -namespace FerramAerospaceResearch -{ - public static class FARAeroStress - { - public static readonly List StressTemplates = new List(); - public static bool loaded; - - - public static void SaveCustomStressTemplates() - { - var node = new ConfigNode("@FARAeroStress[default]:FOR[FerramAerospaceResearch]"); - node.AddNode(new ConfigNode("!FARPartStressTemplate,*")); - - foreach (FARPartStressTemplate template in StressTemplates) - node.AddNode(CreateAeroStressConfigNode(template)); - - var saveNode = new ConfigNode(); - saveNode.AddNode(node); - saveNode.Save(KSPUtil.ApplicationRootPath.Replace("\\", "/") + - "GameData/FerramAerospaceResearch/CustomFARAeroStress.cfg"); - } - - private static ConfigNode CreateAeroStressConfigNode(FARPartStressTemplate template) - { - var node = new ConfigNode("FARPartStressTemplate"); - node.AddValue("name", template.name); - node.AddValue("YmaxStress", template.YmaxStress); - node.AddValue("XZmaxStress", template.XZmaxStress); - node.AddValue("requiresCrew", template.crewed.ToString()); - node.AddValue("isSpecialTemplate", template.isSpecialTemplate.ToString()); - - var res = new ConfigNode("Resources"); - - res.AddValue("numReq", template.minNumResources); - res.AddValue("rejectUnlistedResources", template.rejectUnlistedResources); - - //Make sure to update this whenever MM fixes how it goes through nodes and values - foreach (string s in template.resources) - res.AddValue("res", s); - foreach (string s in template.excludeResources) - res.AddValue("excludeRes", s); - - res.AddValue("flowMode", - template.flowModeNeeded - ? FARDebugAndSettings.FlowMode_str[(int)template.flowMode] - : "unneeded"); - - node.AddNode(res); - - return node; - } - - - public static void LoadStressTemplates() - { - if (loaded) - return; - StressTemplates.Clear(); - foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("FARAeroStress")) - if (node != null) - foreach (ConfigNode template in node.GetNodes("FARPartStressTemplate")) - StressTemplates.Add(CreateFARPartStressTemplate(template)); - - loaded = true; - } - - private static FARPartStressTemplate CreateFARPartStressTemplate(ConfigNode template) - { - var parsedTemplate = new FARPartStressTemplate - { - XZmaxStress = 500, - YmaxStress = 500, - name = "default", - isSpecialTemplate = false, - minNumResources = 0, - resources = new List(), - excludeResources = new List(), - rejectUnlistedResources = false, - crewed = false, - flowModeNeeded = false, - flowMode = ResourceFlowMode.NO_FLOW - }; - - if (template.HasValue("name")) - parsedTemplate.name = template.GetValue("name"); - if (template.HasValue("isSpecialTemplate")) - bool.TryParse(template.GetValue("isSpecialTemplate"), out parsedTemplate.isSpecialTemplate); - if (template.HasValue("YmaxStress")) - double.TryParse(template.GetValue("YmaxStress"), out parsedTemplate.YmaxStress); - if (template.HasValue("XZmaxStress")) - double.TryParse(template.GetValue("XZmaxStress"), out parsedTemplate.XZmaxStress); - if (template.HasValue("requiresCrew")) - bool.TryParse(template.GetValue("requiresCrew"), out parsedTemplate.crewed); - - if (!template.HasNode("Resources")) - return parsedTemplate; - ConfigNode resources = template.GetNode("Resources"); - if (resources.HasValue("numReq")) - int.TryParse(resources.GetValue("numReq"), out parsedTemplate.minNumResources); - - if (resources.HasValue("rejectUnlistedResources")) - bool.TryParse(resources.GetValue("rejectUnlistedResources"), - out parsedTemplate.rejectUnlistedResources); - - if (resources.HasValue("flowMode")) - { - parsedTemplate.flowModeNeeded = true; - string flowString = resources.GetValue("flowMode").ToLowerInvariant(); - - switch (flowString) - { - case "all_vessel": - parsedTemplate.flowMode = ResourceFlowMode.ALL_VESSEL; - break; - case "stack_priority_search": - parsedTemplate.flowMode = ResourceFlowMode.STACK_PRIORITY_SEARCH; - break; - case "stage_priority_flow": - parsedTemplate.flowMode = ResourceFlowMode.STAGE_PRIORITY_FLOW; - break; - case "no_flow": - parsedTemplate.flowMode = ResourceFlowMode.NO_FLOW; - break; - default: - parsedTemplate.flowModeNeeded = false; - break; - } - } - - PartResourceLibrary l = PartResourceLibrary.Instance; - foreach (string resString in resources.GetValues("res")) - if (l.resourceDefinitions.Contains(resString)) - parsedTemplate.resources.Add(resString); - foreach (string resString in resources.GetValues("excludeRes")) - if (l.resourceDefinitions.Contains(resString)) - parsedTemplate.excludeResources.Add(resString); - - return parsedTemplate; - } - - public static FARPartStressTemplate DetermineStressTemplate(Part p) - { - FARPartStressTemplate template = StressTemplates[0]; - - int resCount = p.Resources.Count; - bool crewed = p.CrewCapacity > 0; - if (p.Modules.Contains() || p.Resources.Contains("Ablator")) - return template; - - foreach (FARPartStressTemplate candidate in StressTemplates) - { - if (candidate.isSpecialTemplate) - continue; - if (candidate.crewed != crewed) - continue; - - if (resCount < candidate.minNumResources) - continue; - - if (candidate.rejectUnlistedResources) - { - bool cont = true; - int numRes = 0; - foreach (PartResource res in p.Resources) - if (candidate.resources.Contains(res.info.name)) - { - numRes++; - cont = false; - } - else - { - cont = true; - break; - } - - if (cont || numRes < candidate.minNumResources) - continue; - } - else - { - int numRes = 0; - foreach (PartResource res in p.Resources) - if (!candidate.excludeResources.Contains(res.info.name)) - if (!candidate.flowModeNeeded || res.info.resourceFlowMode == candidate.flowMode) - numRes++; - - - if (numRes < candidate.minNumResources) - continue; - } - - template = candidate; - } - - - return template; - } - } - - public struct FARPartStressTemplate - { - public string name; - public bool isSpecialTemplate; - public double YmaxStress; - public double XZmaxStress; - public List resources; - public List excludeResources; - public ResourceFlowMode flowMode; - public bool flowModeNeeded; - public int minNumResources; - public bool rejectUnlistedResources; - public bool crewed; - } -} diff --git a/FerramAerospaceResearch/LEGACYferram4/FARBaseAerodynamics.cs b/FerramAerospaceResearch/LEGACYferram4/FARBaseAerodynamics.cs index 93ba7c580..e0ef47742 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARBaseAerodynamics.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARBaseAerodynamics.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/LEGACYferram4/FARCenterQuery.cs b/FerramAerospaceResearch/LEGACYferram4/FARCenterQuery.cs index b73f078f6..05db906dc 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARCenterQuery.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARCenterQuery.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/LEGACYferram4/FARControllableSurface.cs b/FerramAerospaceResearch/LEGACYferram4/FARControllableSurface.cs index cb2b83e11..4999daa89 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARControllableSurface.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARControllableSurface.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -44,6 +44,7 @@ You should have received a copy of the GNU General Public License using System; using FerramAerospaceResearch; +using FerramAerospaceResearch.Settings; using UnityEngine; // ReSharper disable once CheckNamespace @@ -51,25 +52,28 @@ namespace ferram4 { public class FARControllableSurface : FARWingAerodynamicModel, ITorqueProvider { - public static double timeConstant = 0.25; - public static double timeConstantFlap = 10; - public static double timeConstantSpoiler = 0.75; protected Transform movableSection; private bool flipAxis; // ReSharper disable once NotAccessedField.Global - [KSPField(isPersistant = false)] public Vector3 controlSurfacePivot = new Vector3(1f, 0f, 0f); + [KSPField(isPersistant = false)] + public Vector3 controlSurfacePivot = new Vector3(1f, 0f, 0f); - [KSPField(isPersistant = false)] public float ctrlSurfFrac = 1; + [KSPField(isPersistant = false)] + public float ctrlSurfFrac = 1; - [KSPField(isPersistant = false)] public string transformName = "obj_ctrlSrf"; + [KSPField(isPersistant = false)] + public string transformName = "obj_ctrlSrf"; // These TWO fields MUST be set up so that they are copied by Object.Instantiate. // Otherwise detaching and re-attaching wings with deflected flaps etc breaks until save/load. - [SerializeField] protected Quaternion MovableOrig = Quaternion.identity; - [SerializeField] private bool MovableOrigReady; + [SerializeField] + protected Quaternion MovableOrig = Quaternion.identity; + + [SerializeField] + private bool MovableOrigReady; // protected int MovableSectionFlip = 1; @@ -77,86 +81,86 @@ public class FARControllableSurface : FARWingAerodynamicModel, ITorqueProvider [KSPField(guiName = "FARCtrlSurfPitch", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 100.0f, - minValue = -100f, - scene = UI_Scene.All, - stepIncrement = 5f)] + maxValue = 100.0f, + minValue = -100f, + scene = UI_Scene.All, + stepIncrement = 5f)] public float pitchaxis = 100.0f; [KSPField(guiName = "FARCtrlSurfYaw", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 100.0f, - minValue = -100f, - scene = UI_Scene.All, - stepIncrement = 5f)] + maxValue = 100.0f, + minValue = -100f, + scene = UI_Scene.All, + stepIncrement = 5f)] public float yawaxis = 100.0f; [KSPField(guiName = "FARCtrlSurfRoll", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 100.0f, - minValue = -100f, - scene = UI_Scene.All, - stepIncrement = 5f)] + maxValue = 100.0f, + minValue = -100f, + scene = UI_Scene.All, + stepIncrement = 5f)] public float rollaxis = 100.0f; [KSPField(guiName = "FARCtrlSurfAoA", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 200.0f, - minValue = -200f, - scene = UI_Scene.All, - stepIncrement = 5f)] + maxValue = 200.0f, + minValue = -200f, + scene = UI_Scene.All, + stepIncrement = 5f)] public float pitchaxisDueToAoA; [KSPField(guiName = "FARCtrlSurfBrakeRudder", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 100.0f, - minValue = -100f, - scene = UI_Scene.All, - stepIncrement = 5f)] + maxValue = 100.0f, + minValue = -100f, + scene = UI_Scene.All, + stepIncrement = 5f)] public float brakeRudder; [KSPField(guiName = "FARCtrlSurfCtrlDeflect", guiActiveEditor = false, isPersistant = true), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 40, - minValue = -40, - scene = UI_Scene.All, - stepIncrement = 0.5f)] + maxValue = 40, + minValue = -40, + scene = UI_Scene.All, + stepIncrement = 0.5f)] public float maxdeflect = 15; // ReSharper disable once ConvertToConstant.Local // ReSharper disable once FieldCanBeMadeReadOnly.Local [KSPField(guiName = "FARCtrlSurfFlapSpoiler", guiActiveEditor = true, guiActive = true), UI_Toggle(affectSymCounterparts = UI_Scene.All, - scene = UI_Scene.All, - disabledText = "FARCtrlSurfStdText", - enabledText = "FARCtrlSurfStdText")] + scene = UI_Scene.All, + disabledText = "FARCtrlSurfStdText", + enabledText = "FARCtrlSurfStdText")] private bool showFlpCtrl = false; // ReSharper disable once FieldCanBeMadeReadOnly.Local // ReSharper disable once ConvertToConstant.Local [KSPField(guiName = "FARCtrlSurfStdTitle", guiActiveEditor = true, guiActive = true), UI_Toggle(affectSymCounterparts = UI_Scene.All, - scene = UI_Scene.All, - disabledText = "FARCtrlSurfStdText", - enabledText = "FARCtrlSurfStdText")] + scene = UI_Scene.All, + disabledText = "FARCtrlSurfStdText", + enabledText = "FARCtrlSurfStdText")] private bool showStdCtrl = false; private bool prevFlpCtrl = true; [KSPField(guiName = "FARCtrlSurfFlap", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_Toggle(affectSymCounterparts = UI_Scene.All, - enabledText = "FARCtrlSurfFlapActive", - scene = UI_Scene.All, - disabledText = "FARCtrlSurfFlapInActive")] + enabledText = "FARCtrlSurfFlapActive", + scene = UI_Scene.All, + disabledText = "FARCtrlSurfFlapInActive")] public bool isFlap; private bool prevIsFlap; [KSPField(guiName = "FARCtrlSurfSpoiler", isPersistant = true, guiActiveEditor = false, guiActive = false), UI_Toggle(affectSymCounterparts = UI_Scene.All, - enabledText = "FARCtrlSurfFlapActive", - scene = UI_Scene.All, - disabledText = "FARCtrlSurfFlapInActive")] + enabledText = "FARCtrlSurfFlapActive", + scene = UI_Scene.All, + disabledText = "FARCtrlSurfFlapInActive")] public bool isSpoiler; private bool prevIsSpoiler; @@ -166,10 +170,10 @@ public class FARControllableSurface : FARWingAerodynamicModel, ITorqueProvider [KSPField(guiName = "FARCtrlSurfFlapDeflect", guiActiveEditor = false, isPersistant = true), UI_FloatRange(affectSymCounterparts = UI_Scene.All, - maxValue = 85, - minValue = -85, - scene = UI_Scene.All, - stepIncrement = 0.5f)] + maxValue = 85, + minValue = -85, + scene = UI_Scene.All, + stepIncrement = 0.5f)] public float maxdeflectFlap = 15; protected double PitchLocation; @@ -196,6 +200,24 @@ public class FARControllableSurface : FARWingAerodynamicModel, ITorqueProvider private Transform lastReferenceTransform; + public static double timeConstant + { + get { return FARAeroData.ControlSurfaceTimeConstant; } + set { FARAeroData.ControlSurfaceTimeConstant = value; } + } + + public static double timeConstantFlap + { + get { return FARAeroData.ControlSurfaceTimeConstantFlap; } + set { FARAeroData.ControlSurfaceTimeConstantFlap = value; } + } + + public static double timeConstantSpoiler + { + get { return FARAeroData.ControlSurfaceTimeConstantSpoiler; } + set { FARAeroData.ControlSurfaceTimeConstantSpoiler = value; } + } + protected Transform MovableSection { get @@ -226,7 +248,7 @@ public void GetPotentialTorque(out Vector3 pos, out Vector3 neg) Vector3 relPosVector = AerodynamicCenter - vessel.CoM; - Vector3 maxMomentVector = Vector3.Cross(relPosVector, maxLiftVec); + var maxMomentVector = Vector3.Cross(relPosVector, maxLiftVec); Vector3 vesselRelMaxMoment = vessel.ReferenceTransform.worldToLocalMatrix.MultiplyVector(maxMomentVector); @@ -370,7 +392,7 @@ public override void Initialization() if (!FARDebugValues.allowStructuralFailures) return; foreach (FARPartStressTemplate temp in FARAeroStress.StressTemplates) - if (temp.name == "ctrlSurfStress") + if (temp.Name == "ctrlSurfStress") { FARPartStressTemplate template = temp; double maxForceMult = Math.Pow(massMultiplier, FARAeroUtil.massStressPower); @@ -378,11 +400,11 @@ public override void Initialization() YmaxForce *= 1 - ctrlSurfFrac; XZmaxForce *= 1 - ctrlSurfFrac; - double tmp = template.YmaxStress; //in MPa + double tmp = template.YMaxStress; //in MPa tmp *= S * ctrlSurfFrac * maxForceMult; YmaxForce += tmp; - tmp = template.XZmaxStress; //in MPa + tmp = template.XZMaxStress; //in MPa tmp *= S * ctrlSurfFrac * maxForceMult; XZmaxForce += tmp; break; diff --git a/FerramAerospaceResearch/LEGACYferram4/FARPartModule.cs b/FerramAerospaceResearch/LEGACYferram4/FARPartModule.cs index 7e827c38b..0886050a4 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARPartModule.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARPartModule.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -45,7 +45,6 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using FerramAerospaceResearch; -using FerramAerospaceResearch.FARUtils; using UnityEngine; // ReSharper disable once CheckNamespace diff --git a/FerramAerospaceResearch/LEGACYferram4/FARWingAerodynamicModel.cs b/FerramAerospaceResearch/LEGACYferram4/FARWingAerodynamicModel.cs index 51abb020a..1bd7527ef 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARWingAerodynamicModel.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARWingAerodynamicModel.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. @@ -46,8 +46,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using FerramAerospaceResearch; using FerramAerospaceResearch.FARAeroComponents; -using FerramAerospaceResearch.FARGUI; -using FerramAerospaceResearch.FARUtils; +using FerramAerospaceResearch.Settings; using KSP.Localization; using TweakScale; using UnityEngine; @@ -81,15 +80,19 @@ public class FARWingAerodynamicModel : FARBaseAerodynamics, IRescalable unity [KSPField(isPersistant = false, - guiActive = false, - guiActiveEditor = false, - guiFormat = "F3", - guiUnits = "FARUnitKN")] + guiActive = false, + guiActiveEditor = false, + guiFormat = "F3", + guiUnits = "FARUnitKN")] public float dragForceWing; // ReSharper disable once NotAccessedField.Global -> unity [KSPField(isPersistant = false, - guiActive = false, - guiActiveEditor = false, - guiFormat = "F3", - guiUnits = "FARUnitKN")] + guiActive = false, + guiActiveEditor = false, + guiFormat = "F3", + guiUnits = "FARUnitKN")] public float liftForceWing; private double rawLiftSlope; @@ -146,7 +152,8 @@ public class FARWingAerodynamicModel : FARBaseAerodynamics, IRescalable(); + FARAeroPartModule a = part.Modules.GetModule(); NUFAR_areaExposedFactor = Math.Min(a.ProjectedAreas.kN, a.ProjectedAreas.kP); NUFAR_totalExposedAreaFactor = Math.Max(a.ProjectedAreas.kN, a.ProjectedAreas.kP); @@ -383,10 +390,7 @@ private void PrecomputeCentroid() { Vector3d WC = rootMidChordOffsetFromOrig; if (nonSideAttach <= 0) - WC += -b_2_actual / - 3 * - (1 + TaperRatio * 2) / - (1 + TaperRatio) * + WC += -b_2_actual / 3 * (1 + TaperRatio * 2) / (1 + TaperRatio) * (Vector3d.right * srfAttachNegative + Vector3d.up * Math.Tan(MidChordSweep * FARMathUtil.deg2rad)); else @@ -488,8 +492,8 @@ public void MathAndFunctionInitialization() MidChordSweepSideways = (Math.PI * 0.5 - - Math.Atan(Math.Tan(MidChordSweep * FARMathUtil.deg2rad) + MidChordSweepSideways * 4 / transformed_AR) - ) * + Math.Atan(Math.Tan(MidChordSweep * FARMathUtil.deg2rad) + + MidChordSweepSideways * 4 / transformed_AR)) * MidChordSweepSideways * 0.5; @@ -507,14 +511,14 @@ public void MathAndFunctionInitialization() if (!FARDebugValues.allowStructuralFailures) return; foreach (FARPartStressTemplate temp in FARAeroStress.StressTemplates) - if (temp.name == "wingStress") + if (temp.Name == "wingStress") { FARPartStressTemplate template = temp; - YmaxForce = template.YmaxStress; //in MPa + YmaxForce = template.YMaxStress; //in MPa YmaxForce *= S; - XZmaxForce = template.XZmaxStress; + XZmaxForce = template.XZMaxStress; XZmaxForce *= S; break; } @@ -556,8 +560,7 @@ public virtual void FixedUpdate() { CurWingCentroid = WingCentroid(); - Vector3d velocity = rb.GetPointVelocity(CurWingCentroid) + - Krakensbane.GetFrameVelocity() - + Vector3d velocity = rb.GetPointVelocity(CurWingCentroid) + Krakensbane.GetFrameVelocity() - FARWind.GetWind(FlightGlobals.currentMainBody, part, rb.position); double v_scalar = velocity.magnitude; @@ -881,7 +884,7 @@ private void GetRefAreaChildren() foreach (Part p in part.children) { - var childWing = p.GetComponent(); + FARWingAerodynamicModel childWing = p.GetComponent(); if (childWing is null) continue; @@ -1478,7 +1481,7 @@ private void UpdateAeroDisplay(Vector3 lift, Vector3 drag) localWingCentroid, lift, lift.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale, - GUIColors.GetColor(0), + FARConfig.GUIColors.ClColor, true); } else @@ -1493,7 +1496,7 @@ private void UpdateAeroDisplay(Vector3 lift, Vector3 drag) localWingCentroid, drag, drag.magnitude * FARKSPAddonFlightScene.FARAeroForceDisplayScale, - GUIColors.GetColor(1), + FARConfig.GUIColors.CdColor, true); } else diff --git a/FerramAerospaceResearch/LEGACYferram4/FARWingInteraction.cs b/FerramAerospaceResearch/LEGACYferram4/FARWingInteraction.cs index 59de64976..1598a9d31 100644 --- a/FerramAerospaceResearch/LEGACYferram4/FARWingInteraction.cs +++ b/FerramAerospaceResearch/LEGACYferram4/FARWingInteraction.cs @@ -1,9 +1,9 @@ /* -Ferram Aerospace Research v0.15.11.4 "Mach" +Ferram Aerospace Research v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of Ferram Aerospace Research. diff --git a/FerramAerospaceResearch/Properties/AssemblyInfo.cs b/FerramAerospaceResearch/Properties/AssemblyInfo.cs index 2b8392684..751fc9040 100644 --- a/FerramAerospaceResearch/Properties/AssemblyInfo.cs +++ b/FerramAerospaceResearch/Properties/AssemblyInfo.cs @@ -9,10 +9,10 @@ [assembly: AssemblyConfiguration("")] //[assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("FerramAerospaceResearch")] -[assembly: AssemblyCopyright("Copyright © Michael Ferrara et al. 2019")] +[assembly: AssemblyCopyright("Copyright © Michael Ferrara et al. 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: KSPAssembly("FerramAerospaceResearch", 0, 15)] +[assembly: KSPAssembly("FerramAerospaceResearch", 0, 16)] //[assembly: KSPAssemblyDependency("KerbalGraph", 1, 3)] // Setting ComVisible to false makes the types in this assembly not visible @@ -34,6 +34,6 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.15.11.4")] -[assembly: AssemblyFileVersion("0.15.11.4")] +[assembly: AssemblyVersion("0.16.0.0")] +[assembly: AssemblyFileVersion("0.16.0.0")] [assembly: KSPAssemblyDependency("ModularFlightIntegrator", 1, 0)] diff --git a/FerramAerospaceResearch/RealChuteLite/ChuteCalculator.cs b/FerramAerospaceResearch/RealChuteLite/ChuteCalculator.cs index ccf15a9a8..431c6f3e5 100644 --- a/FerramAerospaceResearch/RealChuteLite/ChuteCalculator.cs +++ b/FerramAerospaceResearch/RealChuteLite/ChuteCalculator.cs @@ -1,5 +1,4 @@ using System; -using FerramAerospaceResearch.FARUtils; using UnityEngine; /* RealChuteLite is the work of Christophe Savard (stupid_chris), and is licensed the same way than the rest of FAR is. @@ -20,7 +19,7 @@ private void Start() if (prefab == null || !prefab.Modules.Contains()) continue; //Updates the part's GetInfo. - var module = prefab.Modules.GetModule(); + RealChuteFAR module = prefab.Modules.GetModule(); DragCubeSystem.Instance.LoadDragCubes(prefab); DragCube semi = prefab.DragCubes.Cubes.Find(c => c.Name == "SEMIDEPLOYED"), deployed = prefab.DragCubes.Cubes.Find(c => c.Name == "DEPLOYED"); diff --git a/FerramAerospaceResearch/Settings/FARAeroData.cs b/FerramAerospaceResearch/Settings/FARAeroData.cs new file mode 100644 index 000000000..2fb00f202 --- /dev/null +++ b/FerramAerospaceResearch/Settings/FARAeroData.cs @@ -0,0 +1,127 @@ +using System.Collections; +using System.Collections.Generic; +using FerramAerospaceResearch.Reflection; +using FerramAerospaceResearch.Threading; +using UnityEngine; + +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnassignedField.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable CollectionNeverUpdated.Global + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("BodyAtmosphericData")] + public struct BodySettings + { + [ConfigValue("index")] + public int Index; + + [ConfigValue("name")] + public string Name; + + [ConfigValue("viscosityAtReferenceTemp")] + public double ReferenceViscosity; + + [ConfigValue("referenceTemp")] + public double ReferenceTemperature; + } + + [ConfigNode("FARAeroData", true)] + public class FARAeroData : Singleton, FerramAerospaceResearch.Interfaces.IConfigNode + { + [ConfigValue("massPerWingAreaSupported")] + public static double MassPerWingAreaSupported = 0.04f; + + [ConfigValue("massStressPower")] + public static double MassStressPower = 0.85f; + + [ConfigValue("ctrlSurfTimeConstant")] + public static double ControlSurfaceTimeConstant = 0.25f; + + [ConfigValue("ctrlSurfTimeConstantFlap")] + public static double ControlSurfaceTimeConstantFlap = 10; + + [ConfigValue("ctrlSurfTimeConstantSpoiler")] + public static double ControlSurfaceTimeConstantSpoiler = 0.75f; + + [ConfigValue] + private static readonly List AtmosphericData = new List(); + + [ConfigValueIgnore] + public static readonly Dictionary AtmosphericConfiguration = + new Dictionary(); + + private MainThread.CoroutineTask OnLoad; + + /// + public void BeforeLoaded() + { + AtmosphericConfiguration.Clear(); + AtmosphericData.Clear(); + } + + /// + public void AfterLoaded() + { + OnLoad?.Cancel(); + OnLoad = MainThread.StartCoroutine(LoadGlobals); + } + + private static IEnumerator LoadGlobals() + { + yield return new WaitWhile(() => HighLogic.LoadedScene == GameScenes.LOADING || + FlightGlobals.fetch == null); + + foreach (BodySettings settings in AtmosphericData) + { + int index = settings.Index; + if (!string.IsNullOrEmpty(settings.Name)) + { + foreach (CelestialBody body in FlightGlobals.Bodies) + if (body.bodyName == settings.Name) + { + index = body.flightGlobalsIndex; + break; + } + } + + if (AtmosphericConfiguration.ContainsKey(index)) + continue; + + AtmosphericConfiguration.Add(index, settings); + } + + //For any bodies that lack a configuration, use Earth-like properties + foreach (CelestialBody body in FlightGlobals.Bodies) + { + if (AtmosphericConfiguration.ContainsKey(body.flightGlobalsIndex)) + continue; + + AtmosphericConfiguration.Add(body.flightGlobalsIndex, + new BodySettings + { + Index = body.flightGlobalsIndex, + Name = body.name, + ReferenceTemperature = 288, + ReferenceViscosity = 1.7894e-5f + }); + } + } + + /// + public void BeforeSaved() + { + if (AtmosphericConfiguration.Count == 0) + return; + AtmosphericData.Clear(); + foreach (KeyValuePair pair in AtmosphericConfiguration) + AtmosphericData.Add(pair.Value); + } + + /// + public void AfterSaved() + { + } + } +} diff --git a/FerramAerospaceResearch/Settings/FARAeroStress.cs b/FerramAerospaceResearch/Settings/FARAeroStress.cs new file mode 100644 index 000000000..48e312fb6 --- /dev/null +++ b/FerramAerospaceResearch/Settings/FARAeroStress.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("Resources")] + public class ResourceSettings + { + [ConfigValue("excludeRes")] + public readonly List Excluded = new List(); + + [ConfigValue("res")] + public readonly List Resources = new List(); + + // ReSharper disable once FieldCanBeMadeReadOnly.Global + // ReSharper disable once ConvertToConstant.Global + [ConfigValue("flowMode")] + public ResourceFlowMode FlowMode = ResourceFlowMode.NULL; + + [ConfigValue("numReq")] + public int NumRequired = 0; + + [ConfigValue("rejectUnlistedResources")] + public bool RejectUnlisted = false; + } + + + [ConfigNode("FARPartStressTemplate")] + public class FARPartStressTemplate : Interfaces.IConfigNode + { + [ConfigValue] + public readonly ResourceSettings Resources = new ResourceSettings(); + + [ConfigValueIgnore] + public bool FlowModeNeeded; + + [ConfigValue("isSpecialTemplate")] + public bool IsSpecial = false; + + [ConfigValue("name")] + public string Name = "default"; + + [ConfigValue("requiresCrew")] + public bool RequiresCrew = false; + + [ConfigValue("XZmaxStress")] + public double XZMaxStress = 500; + + [ConfigValue("YmaxStress")] + public double YMaxStress = 500; + + public void BeforeLoaded() + { + } + + public void AfterLoaded() + { + FlowModeNeeded = Resources.FlowMode == ResourceFlowMode.ALL_VESSEL || + Resources.FlowMode == ResourceFlowMode.STACK_PRIORITY_SEARCH || + Resources.FlowMode == ResourceFlowMode.STAGE_PRIORITY_FLOW || + Resources.FlowMode == ResourceFlowMode.NO_FLOW; + + Resources.Resources.RemoveAll(s => !PartResourceLibrary.Instance.resourceDefinitions.Contains(s)); + Resources.Excluded.RemoveAll(s => !PartResourceLibrary.Instance.resourceDefinitions.Contains(s)); + } + + public void BeforeSaved() + { + } + + public void AfterSaved() + { + } + } + + [ConfigNode("FARAeroStress", true)] + public static class FARAeroStress + { + [ConfigValue] + public static readonly List StressTemplates = new List(); + + + public static FARPartStressTemplate DetermineStressTemplate(Part p) + { + FARPartStressTemplate template = StressTemplates[0]; + + int resCount = p.Resources.Count; + bool crewed = p.CrewCapacity > 0; + if (p.Modules.Contains() || p.Resources.Contains("Ablator")) + return template; + + foreach (FARPartStressTemplate candidate in StressTemplates) + { + if (candidate.IsSpecial) + continue; + if (candidate.RequiresCrew != crewed) + continue; + + if (resCount < candidate.Resources.NumRequired) + continue; + + if (candidate.Resources.RejectUnlisted) + { + bool cont = true; + int numRes = 0; + foreach (PartResource res in p.Resources) + if (candidate.Resources.Resources.Contains(res.info.name)) + { + numRes++; + cont = false; + } + else + { + cont = true; + break; + } + + if (cont || numRes < candidate.Resources.NumRequired) + continue; + } + else + { + int numRes = 0; + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (PartResource res in p.Resources) + if (!candidate.Resources.Excluded.Contains(res.info.name)) + if (!candidate.FlowModeNeeded || res.info.resourceFlowMode == candidate.Resources.FlowMode) + numRes++; + + + if (numRes < candidate.Resources.NumRequired) + continue; + } + + template = candidate; + } + + + return template; + } + } +} diff --git a/FerramAerospaceResearch/Settings/FARAnimOverrides.cs b/FerramAerospaceResearch/Settings/FARAnimOverrides.cs new file mode 100644 index 000000000..5685179ee --- /dev/null +++ b/FerramAerospaceResearch/Settings/FARAnimOverrides.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using FerramAerospaceResearch.Reflection; + +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable CollectionNeverUpdated.Global + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("FARAnimOverride", true, true, false)] + public class FARAnimOverrides : Singleton, Interfaces.IConfigNode + { + [ConfigValue] + private static readonly List overrideList = new List(); + + [ConfigValueIgnore] + public static readonly Dictionary Overrides = new Dictionary(); + + public void BeforeLoaded() + { + overrideList.Clear(); + } + + public void AfterLoaded() + { + if (overrideList.Count == 0) + return; + + Overrides.Clear(); + foreach (Override item in overrideList) + if (!string.IsNullOrEmpty(item.ModuleName)) + Overrides.Add(item.ModuleName, item.FieldName); + } + + public void BeforeSaved() + { + overrideList.Clear(); + + foreach (KeyValuePair pair in Overrides) + { + overrideList.Add(new Override + { + ModuleName = pair.Key, + FieldName = pair.Value + }); + } + } + + public void AfterSaved() + { + } + + [ConfigNode("FARAnimOverride")] + public struct Override + { + [ConfigValue("moduleName")] + public string ModuleName; + + [ConfigValue("animNameField")] + public string FieldName; + } + + public static string FieldNameForModule(string moduleName) + { + return Overrides.TryGetValue(moduleName, out string v) ? v : null; + } + } +} diff --git a/FerramAerospaceResearch/Settings/FARPartModuleTransformExceptions.cs b/FerramAerospaceResearch/Settings/FARPartModuleTransformExceptions.cs new file mode 100644 index 000000000..3b7d121c7 --- /dev/null +++ b/FerramAerospaceResearch/Settings/FARPartModuleTransformExceptions.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using System.Linq; +using FerramAerospaceResearch.Reflection; +using UnityEngine; + +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnassignedField.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable CollectionNeverUpdated.Global + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("FARPartModuleTransformExceptions", true, shouldSave: false)] + public class FARPartModuleTransformExceptions : Singleton, Interfaces.IConfigNode + { + [ConfigValue] + private static readonly List exceptions = new List(); + + [ConfigValueIgnore] + public static readonly Dictionary Exceptions = + new Dictionary(); + + public void BeforeLoaded() + { + } + + public void AfterLoaded() + { + Exceptions.Clear(); + foreach (FARPartModuleException exception in exceptions) + if (!string.IsNullOrEmpty(exception.PartModuleName)) + Exceptions.Add(exception.PartModuleName, exception); + } + + public void BeforeSaved() + { + exceptions.Clear(); + exceptions.AddRange(Exceptions.Select(pair => pair.Value)); + } + + public void AfterSaved() + { + } + + public static List IgnoreModelTransformList(Part p) + { + var Transform = new List(); + + // ReSharper disable once PossibleNullReferenceException + foreach (KeyValuePair pair in Exceptions) + { + //The first index of each list is the name of the part module; the rest are the transforms + if (!p.Modules.Contains(pair.Value.Transforms[0])) + continue; + PartModule module = p.Modules[pair.Value.Transforms[0]]; + + for (int j = 1; j < pair.Value.Transforms.Count; ++j) + { + string transformString = + (string)module.GetType().GetField(pair.Value.Transforms[j]).GetValue(module); + Transform.AddRange(string.IsNullOrEmpty(transformString) + ? p.FindModelComponents(pair.Value.Transforms[j]) + : p.FindModelComponents(transformString)); + } + } + + foreach (Transform t in p.FindModelComponents()) + { + if (Transform.Contains(t)) + continue; + if (!t.gameObject.activeInHierarchy) + { + Transform.Add(t); + continue; + } + + string tag = t.tag.ToLowerInvariant(); + if (tag == "ladder" || tag == "airlock") + Transform.Add(t); + } + + return Transform; + } + + [ConfigNode("FARPartModuleException")] + public class FARPartModuleException + { + [ConfigValue("TransformException")] + public readonly List Transforms = new List(); + + [ConfigValue("PartModuleName")] + public string PartModuleName; + } + } +} diff --git a/FerramAerospaceResearch/Settings/Settings.cs b/FerramAerospaceResearch/Settings/Settings.cs new file mode 100644 index 000000000..b2f204934 --- /dev/null +++ b/FerramAerospaceResearch/Settings/Settings.cs @@ -0,0 +1,13 @@ +using FerramAerospaceResearch.Reflection; + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("Settings", parent: typeof(FARConfig))] + public static class FARSettings + { + [ConfigValue("exposedAreaUsesKSPHack")] + public static bool ExposedAreaUsesKSPHack = true; + [ConfigValue("exposedAreaLimited")] + public static bool ExposedAreaLimited = true; + } +} diff --git a/FerramAerospaceResearch/Settings/VoxelizationSettings.cs b/FerramAerospaceResearch/Settings/VoxelizationSettings.cs new file mode 100644 index 000000000..d2bee4383 --- /dev/null +++ b/FerramAerospaceResearch/Settings/VoxelizationSettings.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using FerramAerospaceResearch.Reflection; +using UnityEngine; + +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable ClassNeverInstantiated.Global + +namespace FerramAerospaceResearch.Settings +{ + [ConfigNode("ColorMap")] + public class ColorMap + { + [ConfigValueIgnore] + public static readonly ColorMap Default = new ColorMap + { + Name = "default", + Colors = {new Color(0.18f, 0f, 0.106f)} + }; + + [ConfigValue("name")] public string Name { get; set; } + + [ConfigValue("color")] public List Colors { get; } = new List(); + + public Color this[int index] + { + get { return Colors[index]; } + set { Colors[index] = value; } + } + + public Color Get(int index) + { + return Colors[index % Colors.Count]; + } + } + + [ConfigNode("Voxelization", shouldSave: false, parent: typeof(FARConfig))] + public static class VoxelizationSettings + { + [ConfigValue("default")] public static string Default { get; set; } + + [ConfigValue("ColorMap")] public static List ColorMaps { get; } = new List(); + + public static ColorMap FirstOrDefault() + { + return FirstOrDefault(Default); + } + public static ColorMap FirstOrDefault(string name) + { + if (string.IsNullOrEmpty(name)) + return ColorMap.Default; + foreach (ColorMap map in ColorMaps) + { + if (map.Name == name) + return map; + } + + return ColorMap.Default; + } + } +} diff --git a/FerramAerospaceResearch/Utils/ConfigAdapter.cs b/FerramAerospaceResearch/Utils/ConfigAdapter.cs new file mode 100644 index 000000000..53292ac27 --- /dev/null +++ b/FerramAerospaceResearch/Utils/ConfigAdapter.cs @@ -0,0 +1,373 @@ +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using FerramAerospaceResearch.Interfaces; +using FerramAerospaceResearch.Reflection; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + [FARAddon(700, true)] + public class ConfigAdapter : MonoSingleton, IWaitForAddon, IReloadable + { + private static readonly Dictionary lastConfigs = new Dictionary(); + public int Priority { get; set; } = 999; + + public void DoReload() + { + StartCoroutine(DoLoadConfig()); + } + + public bool Completed { get; set; } + + private void Start() + { + StartCoroutine(DoSetup()); + } + + private IEnumerator DoSetup() + { + try + { + Task task = Task.Factory.StartNew(() => ConfigReflection.Instance.Initialize()); + + while (!task.IsCompleted) + yield return null; + + if (task.Exception != null) + FARLogger.Exception(task.Exception, "Exception while setting up config"); + } + finally + { + Completed = true; + } + } + + public static void LoadConfigs() + { + FARConfig.IsLoading = true; + + // clear config cache so it can be rebuilt + lastConfigs.Clear(); + + var load = new LoadVisitor(); + try + { + foreach (KeyValuePair pair in ConfigReflection.Instance.Configs) + { + ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes(pair.Key); + if (pair.Value.Reflection.AllowMultiple) + { + var root = new ConfigNode(); + foreach (ConfigNode configNode in nodes) + root.AddNode(configNode); + + load.Node = root; + object instance = pair.Value.Instance; + int errors = pair.Value.Reflection.Load(load, ref instance); + + if (errors > 0) + FARLogger.ErrorFormat("{0} errors while loading {1}", errors.ToString(), pair.Key); + } + else + { + if (nodes.Length == 0) + { + FARLogger.Warning($"Could not find config nodes {pair.Key}"); + continue; + } + + if (nodes.Length > 1) + FARLogger.Warning($"Found {nodes.Length.ToString()} {pair.Key} nodes"); + + foreach (ConfigNode node in nodes) + { + load.Node = node; + object instance = pair.Value.Instance; + int errors = pair.Value.Reflection.Load(load, ref instance); + + if (errors > 0) + FARLogger.ErrorFormat("{0} errors while loading {1}", errors.ToString(), node.name); + } + } + } + + SaveConfigs("Custom", true, ".cfg.far", FARConfig.Debug.DumpOnLoad); + } + finally + { + FARConfig.IsLoading = false; + } + } + + public static IEnumerator SaveAll() + { + if (FARConfig.IsLoading) + yield break; + + FARConfig.IsLoading = true; + + try + { + Task task = Task.Factory.StartNew(Save); + yield return new WaitUntil(() => task.IsCompleted); + + if (task.Exception != null) + FARLogger.Exception(task.Exception, "Exception while saving up configs"); + } + finally + { + FARConfig.IsLoading = false; + } + } + + public static void Save() + { + SaveConfigs("Custom"); + } + + private static void SaveConfigs( + string prefix, + bool isPatch = true, + string extension = ".cfg", + bool force = false + ) + { + var topNode = new ConfigNode(); + var node = new ConfigNode(); + var save = new SaveVisitor + { + IsPatch = isPatch, + Node = node + }; + foreach (KeyValuePair pair in ConfigReflection.Instance.Configs) + { + if (!pair.Value.Reflection.ShouldSave) + continue; + + pair.Value.Reflection.Save(save, pair.Value.Instance); + + if (!save.Node.HasData) + continue; + + string path = PathUtil.Combine(KSPUtils.GameDataPath, $"{prefix}_{pair.Key}{extension}"); + string nodeStr; + + if (!pair.Value.Reflection.AllowMultiple) + { + Serialization.MakeTopNode(topNode, node, pair.Key, null, isPatch); + nodeStr = topNode.ToString(); + } + else + { + nodeStr = node.ToString(); + } + + if (lastConfigs.TryGetValue(pair.Key, out string oldStr)) + lastConfigs[pair.Key] = nodeStr; + else + lastConfigs.Add(pair.Key, nodeStr); + + // only write if requested or if the node has been modified, first time oldStr should be null so can be skipped + if (force || (!string.IsNullOrEmpty(oldStr) && nodeStr != oldStr)) + { + FARLogger.DebugFormat("Saving {0} config to {1}", pair.Key, path); + System.IO.File.WriteAllText(path, nodeStr); + } + else + { + FARLogger.DebugFormat("{0} does not require saving", pair.Key); + } + + topNode.ClearData(); + node.ClearData(); + } + } + + private IEnumerator DoLoadConfig() + { + Task task = Task.Factory.StartNew(LoadConfigs); + + yield return new WaitWhile(() => !task.IsCompleted); + + if (task.Exception != null) + FARLogger.Exception(task.Exception, "Exception while loading config"); + + Completed = true; + } + } + + public class SaveVisitor : INodeSaver + { + public ConfigNode Node { get; set; } + public bool IsPatch { get; set; } + + /// + public bool OnValue(object value, ValueReflection reflection, out object newValue) + { + newValue = default; + if (value != null) + Serialization.AddValue(Node, reflection.Name, value, reflection.ValueType, IsPatch); + + return false; + } + + /// + public bool OnListValue(int index, object value, ListValueReflection reflection, out object newValue) + { + if (index == 0 && IsPatch) + Node.AddValue($"!{reflection.Name}", "deleted"); + + newValue = default; + if (value != null) + Serialization.AddValue(Node, reflection.Name, value, reflection.ValueType, false, index); + + return false; + } + + /// + public bool OnNode(object value, NodeReflection reflection, out object newValue) + { + newValue = default; + var save = new SaveVisitor + { + IsPatch = IsPatch, + Node = new ConfigNode() + }; + reflection.Save(save, value); + + if (save.Node.HasData) + Serialization.AddNode(Node, save.Node, reflection.Id, reflection.Name, IsPatch); + + return false; + } + + /// + public bool OnListNode( + int index, + object value, + ListValueReflection reflection, + NodeReflection nodeReflection, + out object newValue + ) + { + if (index == 0 && IsPatch) + { + Node.AddNode(string.IsNullOrEmpty(reflection.Name) + ? $"!{reflection.NodeId},*" + : $"!{reflection.NodeId}[{reflection.Name}],*"); + } + + newValue = default; + var save = new SaveVisitor + { + IsPatch = false, + Node = new ConfigNode() + }; + nodeReflection.Save(save, value); + + if (save.Node.HasData) + Serialization.AddNode(Node, save.Node, nodeReflection.Id, reflection.Name); + + return false; + } + } + + public class LoadVisitor : INodeLoader + { + public ConfigNode Node { get; set; } + + /// + public bool OnValue(ValueReflection reflection, out object newValue) + { + if (!Serialization.TryGetValue(Node, reflection.Name, out newValue, reflection.ValueType)) + return false; + + FARLogger.DebugFormat("Parsed {0}.{1} = {2}", Node.name, reflection.Name, newValue); + return true; + } + + /// + public bool OnValueList(ListValueReflection reflection, out IList newValue) + { + List values = Node.GetValuesList(reflection.Name); + newValue = default; + if (values.Count == 0) + return false; + + newValue = new List(); + foreach (string str in values) + { + if (!Serialization.TryGetValue(str, out object v, reflection.ValueType)) + continue; + + newValue.Add(v); + } + FARLogger.DebugFormat("Parsed {0}.{1} with {2} values", Node.name, reflection.Name, newValue.Count); + + return true; + } + + /// + public bool OnNode(object nodeObject, NodeReflection reflection, out object newValue) + { + ConfigNode node = string.IsNullOrEmpty(reflection.Name) + ? Node.GetNode(reflection.Id) + : Node.GetNode(reflection.Id, "name", reflection.Name); + if (node != null) + { + var load = new LoadVisitor {Node = node}; + int errors = reflection.Load(load, ref nodeObject); + + if (errors > 0) + FARLogger.ErrorFormat("{0} errors while loading {1}[{2}]", + errors.ToString(), + node.name, + reflection.Name); + } + + newValue = nodeObject; + return true; + } + + /// + public bool OnNodeList(ListValueReflection reflection, NodeReflection nodeReflection, out IList newValue) + { + ConfigNode[] nodes = Node.GetNodes(reflection.NodeId); + var load = new LoadVisitor(); + + int index = 0; + int i = 0; + + var items = new List(nodes.Length); + + foreach (ConfigNode node in nodes) + { + if (!node.TryGetValue("index", ref i)) + i = index; + index++; + + load.Node = node; + object item = nodeReflection.Load(load, out int errors); + SetItem(items, item, i); + + if (errors > 0) + FARLogger.ErrorFormat("{0} errors while loading {1}[{2}]", + errors.ToString(), + node.name, + i.ToString()); + } + + newValue = items; + return true; + } + + private static void SetItem(IList list, object item, int index) + { + for (int i = list.Count; i <= index; i++) + list.Add(default); + + list[index] = item; + } + } +} diff --git a/FerramAerospaceResearch/Utils/GameDatabaseTextureLoader.cs b/FerramAerospaceResearch/Utils/GameDatabaseTextureLoader.cs new file mode 100644 index 000000000..ec9f75373 --- /dev/null +++ b/FerramAerospaceResearch/Utils/GameDatabaseTextureLoader.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using FerramAerospaceResearch.Resources.Loading; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + public class GameDatabaseTextureLoader : IAssetLoader + { + public IEnumerator Load(IAssetRequest assetRequest) + { + if (!GameDatabase.Instance.IsReady()) + { + FARLogger.Warning("Trying to load textures before GameDatabase has been loaded"); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + yield break; + } + + assetRequest.State = Progress.InProgress; + try + { + FARLogger.DebugFormat("Getting texture {0} from GameDatabase", assetRequest.Url); + Texture2D texture = GameDatabase.Instance.GetTexture(assetRequest.Url, false); + assetRequest.State = Progress.Completed; + assetRequest.OnLoad(texture); + } + catch (Exception e) + { + FARLogger.Exception(e, $"While loading texture {assetRequest.Url} from game database:"); + assetRequest.State = Progress.Error; + assetRequest.OnError(); + } + } + + public string Name { get; } = "GameDatabase"; + } +} diff --git a/FerramAerospaceResearch/Utils/KSPUtils.cs b/FerramAerospaceResearch/Utils/KSPUtils.cs new file mode 100644 index 000000000..73addf0b7 --- /dev/null +++ b/FerramAerospaceResearch/Utils/KSPUtils.cs @@ -0,0 +1,41 @@ +using System.IO; + +namespace FerramAerospaceResearch +{ + public static class KSPUtils + { + public static string FARRelativePath { get; } = Path.Combine("GameData", PathUtil.ModDirectoryName); + public static string GameDataPath { get; } = Path.GetFullPath(Path.Combine(PathUtil.RootDir, "..")); + public static string KSPRootPath { get; } = Path.GetFullPath(Path.Combine(GameDataPath, "..")); + + public static string CombineKSPRoot(string filename) + { + return PathUtil.Combine(KSPRootPath, filename); + } + + public static string CombineKSPRoot(string dir1, string filename) + { + return PathUtil.Combine(KSPRootPath, dir1, filename); + } + + public static string CombineKSPRoot(string dir1, string dir2, string filename) + { + return PathUtil.Combine(KSPRootPath, dir1, dir2, filename); + } + + public static string CombineGameData(string filename) + { + return PathUtil.Combine(GameDataPath, filename); + } + + public static string CombineGameData(string dir1, string filename) + { + return PathUtil.Combine(GameDataPath, dir1, filename); + } + + public static string CombineGameData(string dir1, string dir2, string filename) + { + return PathUtil.Combine(GameDataPath, dir1, dir2, filename); + } + } +} diff --git a/FerramAerospaceResearch/Utils/ModuleControlSurfaceUpgradeFix.cs b/FerramAerospaceResearch/Utils/ModuleControlSurfaceUpgradeFix.cs new file mode 100644 index 000000000..e2b92cc48 --- /dev/null +++ b/FerramAerospaceResearch/Utils/ModuleControlSurfaceUpgradeFix.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + [KSPAddon(KSPAddon.Startup.MainMenu, true)] + public class ModuleControlSurfaceUpgradeFix : MonoBehaviour + { + private void Awake() + { + PropertyInfo pipelineProperty = typeof(KSPUpgradePipeline).GetProperty("Pipeline", + BindingFlags.Static | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.IgnoreCase); + + if (!(pipelineProperty?.GetValue(null) is SaveUpgradePipeline.SaveUpgradePipeline pipeline)) + { + FARLogger.Error("Could not find SaveUpgradePipeline"); + return; + } + + FARLogger.Info("Removing ModuleControlSurface upgrade script from SaveUpgradePipeline"); + pipeline.upgradeScripts.RemoveAll(script => script.Name.Contains("ModuleControlSurface")); + } + } +} diff --git a/FerramAerospaceResearch/Utils/Serialization.cs b/FerramAerospaceResearch/Utils/Serialization.cs new file mode 100644 index 000000000..1bf370ea2 --- /dev/null +++ b/FerramAerospaceResearch/Utils/Serialization.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace FerramAerospaceResearch +{ + public static class Serialization + { + private delegate bool TryParseDelegate(string str, out T value); + + private static readonly Dictionary serializers = new Dictionary + { + { + typeof(int), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, int.TryParse), + Save = (node, s, value) => node.AddValue(s, (int)value) + } + }, + { + typeof(float), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, float.TryParse), + Save = (node, s, value) => node.AddValue(s, (float)value) + } + }, + { + typeof(double), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, double.TryParse), + Save = (node, s, value) => node.AddValue(s, (double)value) + } + }, + { + typeof(long), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, long.TryParse), + Save = (node, s, value) => node.AddValue(s, (long)value) + } + }, + { + typeof(string), new Serializer + { + Parse = (string s, out object value) => + { + value = s; + return true; + }, + Save = (node, s, value) => node.AddValue(s, (string)value) + } + }, + { + typeof(Color), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseColor), + Save = (node, s, value) => node.AddValue(s, (Color)value) + } + }, + { + typeof(Color32), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseColor), + Save = (node, s, value) => node.AddValue(s, (Color32)value) + } + }, + { + typeof(Guid), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseGuid), + Save = (node, s, value) => node.AddValue(s, value) + } + }, + { + typeof(Quaternion), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseQuaternion), + Save = (node, s, value) => node.AddValue(s, (Quaternion)value) + } + }, + { + typeof(Rect), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseRect), + Save = (node, s, value) => node.AddValue(s, value) + } + }, + { + typeof(Vector2), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseVector2), + Save = (node, s, value) => node.AddValue(s, (Vector2)value) + } + }, + { + typeof(Vector3), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseVector3), + Save = (node, s, value) => node.AddValue(s, (Vector3)value) + } + }, + { + typeof(bool), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, bool.TryParse), + Save = (node, s, value) => node.AddValue(s, (bool)value) + } + }, + { + typeof(Vector4), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseVector4), + Save = (node, s, value) => node.AddValue(s, (Vector4)value) + } + }, + { + typeof(uint), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, uint.TryParse), + Save = (node, s, value) => node.AddValue(s, (uint)value) + } + }, + { + typeof(ulong), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, ulong.TryParse), + Save = (node, s, value) => node.AddValue(s, (ulong)value) + } + }, + { + typeof(string[]), + new Serializer + { + Parse = (string s, out object value) => TryParse(s, out value, TryParseStringArray), + Save = (node, s, value) => node.AddValue(s, (string[])value) + } + } + }; + + public static bool TryParseColor(string str, out Color value) + { + return ParseExtensions.TryParseColor(str, out value) || ColorUtility.TryParseHtmlString(str, out value); + } + + public static bool TryParseColor(string str, out Color32 value) + { + return ParseExtensions.TryParseColor32(str, out value); + } + + public static bool TryParseGuid(string str, out Guid g) + { + try + { + g = new Guid(str); + return true; + } + catch (Exception e) + { + FARLogger.Exception(e, "While trying to parse Guid"); + g = Guid.Empty; + return false; + } + } + + public static bool TryParseQuaternion(string str, out Quaternion value) + { + return ParseExtensions.TryParseQuaternion(str, out value); + } + + public static bool TryParseRect(string str, out Rect value) + { + return ParseExtensions.TryParseRect(str, out value); + } + + public static bool TryParseVector2(string str, out Vector2 value) + { + return ParseExtensions.TryParseVector2(str, out value); + } + + public static bool TryParseVector3(string str, out Vector3 value) + { + return ParseExtensions.TryParseVector3(str, out value); + } + + public static bool TryParseVector4(string str, out Vector4 value) + { + return ParseExtensions.TryParseVector4(str, out value); + } + + public static bool TryParseStringArray(string str, out string[] value) + { + value = ParseExtensions.ParseArray(str, Array.Empty()); + return true; + } + + public static bool TryParseEnum(string str, Type type, out Enum value) + { + value = default; + try + { + value = Enum.Parse(type, str, true) as Enum; + return true; + } + catch (Exception e) + { + FARLogger.Exception(e, "While parsing enum"); + return false; + } + } + + private static bool TryParse(string str, out object value, TryParseDelegate parseDelegate) + { + value = default; + if (!parseDelegate.Invoke(str, out T v)) + return false; + value = v; + return true; + } + + public static void AddValue( + ConfigNode node, + string id, + object value, + Type valueType, + bool isPatch = false, + int? index = null + ) + { + if (isPatch) + { + id = index != null ? $"@{id},{((int)index).ToString()}" : $"%{id}"; + } + + if (valueType.IsEnum) + { + node.AddValue(id, value); + return; + } + + if (serializers.TryGetValue(valueType, out Serializer io)) + { + io.Save(node, id, value); + return; + } + + FARLogger.DebugFormat("Unknown value type {0}", valueType); + node.AddValue(id, value); + } + + public static bool TryGetValue(string str, out object value, Type valueType) + { + value = null; + if (str == null) + return false; + if (valueType.IsEnum) + { + if (!TryParseEnum(str, valueType, out Enum e)) + return false; + value = e; + return true; + } + + if (serializers.TryGetValue(valueType, out Serializer io)) + { + if (!io.Parse(str, out object o)) + return false; + value = o; + return true; + } + + FARLogger.DebugFormat("Unknown value type {0}", valueType); + return false; + } + + public static bool TryGetValue(ConfigNode node, string id, out object value, Type valueType) + { + string str = node.GetValue(id); + return TryGetValue(str, out value, valueType); + } + + public static void MakeTopNode( + ConfigNode node, + ConfigNode child, + string id, + string name = null, + bool isPatch = false + ) + { + string nodeName; + if (isPatch) + { + nodeName = $"@{id}"; + if (name != null) + nodeName += $"[{name}]"; + nodeName += ":FOR[FerramAerospaceResearch]"; + } + else + { + if (name != null) + child.AddValue("name", name); + nodeName = id; + } + + node.AddNode(nodeName, child); + } + + public static void AddNode( + ConfigNode node, + ConfigNode child, + string id, + string name = null, + bool isPatch = false, + int? index = null + ) + { + string nodeName; + if (isPatch) + { + nodeName = $"@{id}"; + if (name != null) + nodeName += $"[{name}]"; + if (index != null) + nodeName += $",{((int)index).ToString()}"; + } + else + { + if (name != null && !child.HasValue("name")) + child.AddValue("name", name); + if (index != null && !child.HasValue("index")) + child.AddValue("index", (int)index); + nodeName = id; + } + + node.AddNode(nodeName, child); + } + + private class Serializer + { + public delegate bool TryParseDelegate(string str, out object value); + + public delegate void SaveDelegate(ConfigNode node, string name, object value); + + public TryParseDelegate Parse; + public SaveDelegate Save; + } + } +} diff --git a/GameData/FerramAerospaceResearch/Assets/farshaders_linux.far b/GameData/FerramAerospaceResearch/Assets/farshaders_linux.far index a2cb00e7b..fd3bd0a88 100644 Binary files a/GameData/FerramAerospaceResearch/Assets/farshaders_linux.far and b/GameData/FerramAerospaceResearch/Assets/farshaders_linux.far differ diff --git a/GameData/FerramAerospaceResearch/Assets/farshaders_macosx.far b/GameData/FerramAerospaceResearch/Assets/farshaders_macosx.far index f83a439f5..08a687f31 100644 Binary files a/GameData/FerramAerospaceResearch/Assets/farshaders_macosx.far and b/GameData/FerramAerospaceResearch/Assets/farshaders_macosx.far differ diff --git a/GameData/FerramAerospaceResearch/Assets/farshaders_windows.far b/GameData/FerramAerospaceResearch/Assets/farshaders_windows.far index 7a0f963cb..460f0b321 100644 Binary files a/GameData/FerramAerospaceResearch/Assets/farshaders_windows.far and b/GameData/FerramAerospaceResearch/Assets/farshaders_windows.far differ diff --git a/GameData/FerramAerospaceResearch/FAR.version b/GameData/FerramAerospaceResearch/FAR.version index f21fad2ab..e810d5880 100644 --- a/GameData/FerramAerospaceResearch/FAR.version +++ b/GameData/FerramAerospaceResearch/FAR.version @@ -8,9 +8,9 @@ }, "VERSION" : { "MAJOR" : 0, - "MINOR" : 15, - "PATCH" : 11, - "BUILD" : 4 + "MINOR" : 16, + "PATCH" : 0, + "BUILD" : 0 }, "KSP_VERSION_MIN" : { "MAJOR" : 1, @@ -19,7 +19,7 @@ }, "KSP_VERSION_MAX" : { "MAJOR" : 1, - "MINOR" : 9, + "MINOR" : 10, "PATCH" : 99 } } diff --git a/GameData/FerramAerospaceResearch/FARConfig.cfg b/GameData/FerramAerospaceResearch/FARConfig.cfg new file mode 100644 index 000000000..f3f91f834 --- /dev/null +++ b/GameData/FerramAerospaceResearch/FARConfig.cfg @@ -0,0 +1,386 @@ +FARConfig +{ + Settings { + // KSP has some special math for calculating exposed area of parts + // which ends up being greater than the geometric value, disable + // this only if a mod overrides convection calculations. Note that + // this will likely return greater values than stock so heating will + // be increased + exposedAreaUsesKSPHack = true + + // limit exposed area to radiative area value + exposedAreaLimited = true + } + + Debug { + // level can also be set with an empty file FARLogger_ in Plugins directory + // until MM finishes loading patches, the level will then revert to this config value + // one of [debug, info, warning, assert, error, exception] (in increasing order) case insensitive + logLevel = info + + // debug option to dump all reflected configs on load, mainly to make sure they are correctly + // saved + dumpOnLoad = false + } + + FlightLog { + // directory where to save log files, either relative to KSP root or absolute path + directory = Logs/FerramAerospaceResearch + + // log file name format, variables are enclosed in between <<< and >>> + // currently only + // VESSEL_NAME -> name of the vessel logged + // DATETIME -> computer datetime string + // are supported + nameFormat = <<>>_<<>>.csv + + // custom DATETIME format + // see https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings + // for formatting options + datetimeFormat = yyyy_MM_dd_HH_mm_ss + + // milliseconds between each log, the exact log times will depend on frame time + period = 50 + + // number of logs between flushes to file + flushPeriod = 10 + } + + GuiColors { + ClColor = 0.000,1.000,1.000 + CdColor = 1.000,0.000,0.000 + CmColor = 1.000,0.9215686,0.01568628 + L_DColor = 0.000,1.000,0.000 + } + + Textures { + // paths to textures relative to GameData, no extension since KSP loads them + // available loaders: + // default - textures are loaded by FAR using Unity + // GameDatabase - textures are taken from KSP GameDatabase + TEXTURE { + name = iconButtonBlizzy + url = FerramAerospaceResearch/Textures/icon_button_blizzy + loader = GameDatabase + } + + TEXTURE { + name = iconButtonStock + url = FerramAerospaceResearch/Textures/icon_button_stock + loader = GameDatabase + } + + TEXTURE { + name = spriteDebugVoxel + url = FerramAerospaceResearch/Textures/sprite_debug_voxel + loader = GameDatabase + } + } + + Shaders { + // paths to bundles relative to GameData + bundleLinux = FerramAerospaceResearch/Assets/farshaders_linux.far + bundleWindows = FerramAerospaceResearch/Assets/farshaders_windows.far + bundleMac = FerramAerospaceResearch/Assets/farshaders_macosx.far + + // loaders: + // default - use Shader.Find + // bundle - load from shader bundle + // bundled shaders + SHADER{ + name = debugVoxel + url = FerramAerospaceResearch/Debug Voxel Mesh + loader = bundle + + // specific value to this shader which controls the alpha cuttoff to make voxels appear + // at correct depths + _Cutoff = 0.45 + } + + // KSP shaders + SHADER{ + name = lineRenderer + url = Hidden/Internal-Colored + loader = default + } + + SHADER{ + name = debugVoxelFallback + url = Sprites/Default + loader = default + } + } + + Voxelization { + // check out colorcet (Python) for generating more maps + default = glasbey_bw + + ColorMap { + // similar color as the old debug voxels + name = old + color = 0.18, 0, 0.106 + } + + ColorMap { + // same as colorcet.glasbey_bw + name = glasbey_bw + + color = 0.843137, 0.000000, 0.000000 + color = 0.549020, 0.235294, 1.000000 + color = 0.007843, 0.533333, 0.000000 + color = 0.000000, 0.674510, 0.780392 + color = 0.596078, 1.000000, 0.000000 + color = 1.000000, 0.498039, 0.819608 + color = 0.423529, 0.000000, 0.309804 + color = 1.000000, 0.647059, 0.188235 + color = 0.000000, 0.000000, 0.615686 + color = 0.525490, 0.439216, 0.407843 + color = 0.000000, 0.286275, 0.258824 + color = 0.309804, 0.164706, 0.000000 + color = 0.000000, 0.992157, 0.811765 + color = 0.737255, 0.717647, 1.000000 + color = 0.584314, 0.705882, 0.478431 + color = 0.752941, 0.015686, 0.725490 + color = 0.145098, 0.400000, 0.635294 + color = 0.156863, 0.000000, 0.254902 + color = 0.862745, 0.701961, 0.686275 + color = 0.996078, 0.960784, 0.564706 + color = 0.313725, 0.270588, 0.356863 + color = 0.643137, 0.486275, 0.000000 + color = 1.000000, 0.443137, 0.400000 + color = 0.247059, 0.505882, 0.431373 + color = 0.509804, 0.000000, 0.050980 + color = 0.639216, 0.482353, 0.701961 + color = 0.203922, 0.305882, 0.000000 + color = 0.607843, 0.894118, 1.000000 + color = 0.921569, 0.000000, 0.466667 + color = 0.176471, 0.000000, 0.039216 + color = 0.368627, 0.564706, 1.000000 + color = 0.000000, 0.780392, 0.125490 + color = 0.345098, 0.003922, 0.666667 + color = 0.000000, 0.117647, 0.000000 + color = 0.603922, 0.278431, 0.000000 + color = 0.588235, 0.623529, 0.650980 + color = 0.607843, 0.258824, 0.360784 + color = 0.000000, 0.121569, 0.196078 + color = 0.784314, 0.768627, 0.000000 + color = 1.000000, 0.815686, 1.000000 + color = 0.000000, 0.745098, 0.603922 + color = 0.215686, 0.082353, 1.000000 + color = 0.176471, 0.145098, 0.145098 + color = 0.874510, 0.345098, 1.000000 + color = 0.745098, 0.905882, 0.752941 + color = 0.498039, 0.270588, 0.596078 + color = 0.321569, 0.309804, 0.235294 + color = 0.847059, 0.400000, 0.000000 + color = 0.392157, 0.454902, 0.219608 + color = 0.756863, 0.450980, 0.533333 + color = 0.431373, 0.454902, 0.541176 + color = 0.501961, 0.615686, 0.011765 + color = 0.745098, 0.545098, 0.396078 + color = 0.388235, 0.200000, 0.223529 + color = 0.792157, 0.803922, 0.854902 + color = 0.423529, 0.921569, 0.513725 + color = 0.133333, 0.250980, 0.411765 + color = 0.635294, 0.498039, 1.000000 + color = 0.996078, 0.011765, 0.796078 + color = 0.462745, 0.737255, 0.992157 + color = 0.850980, 0.764706, 0.509804 + color = 0.807843, 0.639216, 0.807843 + color = 0.427451, 0.313725, 0.000000 + color = 0.000000, 0.411765, 0.454902 + color = 0.278431, 0.623529, 0.368627 + color = 0.580392, 0.776471, 0.749020 + color = 0.976471, 1.000000, 0.000000 + color = 0.752941, 0.329412, 0.270588 + color = 0.000000, 0.396078, 0.235294 + color = 0.356863, 0.313725, 0.658824 + color = 0.325490, 0.125490, 0.392157 + color = 0.309804, 0.372549, 1.000000 + color = 0.494118, 0.560784, 0.466667 + color = 0.725490, 0.031373, 0.980392 + color = 0.545098, 0.572549, 0.764706 + color = 0.701961, 0.000000, 0.207843 + color = 0.533333, 0.376471, 0.494118 + color = 0.623529, 0.000000, 0.458824 + color = 1.000000, 0.870588, 0.768627 + color = 0.317647, 0.031373, 0.000000 + color = 0.101961, 0.031373, 0.000000 + color = 0.298039, 0.537255, 0.713725 + color = 0.000000, 0.874510, 0.874510 + color = 0.784314, 1.000000, 0.980392 + color = 0.188235, 0.207843, 0.082353 + color = 1.000000, 0.152941, 0.278431 + color = 1.000000, 0.592157, 0.666667 + color = 0.015686, 0.000000, 0.101961 + color = 0.788235, 0.376471, 0.694118 + color = 0.764706, 0.635294, 0.215686 + color = 0.486275, 0.309804, 0.227451 + color = 0.976471, 0.619608, 0.466667 + color = 0.337255, 0.396078, 0.392157 + color = 0.819608, 0.576471, 1.000000 + color = 0.176471, 0.121569, 0.411765 + color = 0.254902, 0.105882, 0.203922 + color = 0.686275, 0.576471, 0.596078 + color = 0.384314, 0.619608, 0.600000 + color = 0.741176, 0.870588, 0.482353 + color = 1.000000, 0.368627, 0.580392 + color = 0.058824, 0.160784, 0.137255 + color = 0.721569, 0.745098, 0.674510 + color = 0.454902, 0.231373, 0.396078 + color = 0.062745, 0.000000, 0.050980 + color = 0.498039, 0.431373, 0.741176 + color = 0.619608, 0.419608, 0.231373 + color = 1.000000, 0.274510, 0.000000 + color = 0.498039, 0.000000, 0.529412 + color = 1.000000, 0.807843, 0.243137 + color = 0.188235, 0.231373, 0.262745 + color = 0.996078, 0.647059, 1.000000 + color = 0.541176, 0.007843, 0.243137 + color = 0.462745, 0.172549, 0.003922 + color = 0.039216, 0.541176, 0.588235 + color = 0.019608, 0.000000, 0.321569 + color = 0.556863, 0.839216, 0.196078 + color = 0.325490, 0.768627, 0.450980 + color = 0.278431, 0.349020, 0.443137 + color = 0.345098, 0.007843, 0.133333 + color = 0.650980, 0.133333, 0.003922 + color = 0.564706, 0.576471, 0.298039 + color = 0.000000, 0.262745, 0.117647 + color = 0.505882, 0.000000, 0.819608 + color = 0.184314, 0.149020, 0.247059 + color = 0.749020, 0.223529, 0.517647 + color = 0.960784, 1.000000, 0.835294 + color = 0.000000, 0.827451, 1.000000 + color = 0.415686, 0.000000, 0.972549 + color = 0.611765, 0.733333, 0.823529 + color = 0.478431, 0.850980, 0.670588 + color = 0.411765, 0.341176, 0.364706 + color = 0.000000, 0.411765, 0.019608 + color = 0.211765, 0.211765, 0.611765 + color = 0.003922, 0.513725, 0.278431 + color = 0.266667, 0.117647, 0.094118 + color = 0.027451, 0.647059, 0.937255 + color = 1.000000, 0.505882, 0.188235 + color = 0.654902, 0.333333, 0.721569 + color = 0.407843, 0.352941, 0.513725 + color = 0.450980, 1.000000, 1.000000 + color = 0.850980, 0.529412, 0.007843 + color = 0.733333, 0.827451, 1.000000 + color = 0.556863, 0.215686, 0.184314 + color = 0.654902, 0.627451, 0.501961 + color = 0.000000, 0.490196, 0.890196 + color = 0.556863, 0.494118, 0.560784 + color = 0.600000, 0.266667, 0.533333 + color = 0.000000, 0.945098, 0.207843 + color = 0.682353, 0.666667, 0.788235 + color = 0.627451, 0.380392, 0.384314 + color = 0.298039, 0.227451, 0.466667 + color = 0.423529, 0.509804, 0.513725 + color = 0.945098, 0.866667, 0.905882 + color = 1.000000, 0.733333, 0.827451 + color = 0.219608, 0.647059, 0.137255 + color = 0.705882, 1.000000, 0.658824 + color = 0.047059, 0.070588, 0.027451 + color = 0.843137, 0.321569, 0.431373 + color = 0.584314, 0.623529, 0.996078 + color = 0.490196, 0.498039, 0.000000 + color = 0.462745, 0.623529, 0.725490 + color = 0.858824, 0.529412, 0.498039 + color = 0.066667, 0.074510, 0.098039 + color = 0.831373, 0.509804, 0.831373 + color = 0.623529, 0.000000, 0.749020 + color = 0.862745, 0.937255, 1.000000 + color = 0.556863, 0.670588, 0.603922 + color = 0.443137, 0.392157, 0.258824 + color = 0.290196, 0.235294, 0.243137 + color = 0.031373, 0.305882, 0.372549 + color = 0.611765, 0.721569, 0.266667 + color = 0.847059, 0.870588, 0.835294 + color = 0.796078, 1.000000, 0.423529 + color = 0.701961, 0.392157, 0.921569 + color = 0.274510, 0.364706, 0.200000 + color = 0.000000, 0.619608, 0.490196 + color = 0.760784, 0.254902, 0.000000 + color = 0.309804, 0.737255, 0.733333 + color = 0.850980, 0.545098, 0.694118 + color = 0.356863, 0.450980, 0.713725 + color = 0.294118, 0.254902, 0.003922 + color = 0.584314, 0.513725, 0.368627 + color = 0.286275, 0.454902, 0.545098 + color = 1.000000, 0.450980, 1.000000 + color = 0.513725, 0.415686, 0.113725 + color = 0.862745, 0.811765, 1.000000 + color = 0.494118, 0.419608, 0.996078 + color = 0.388235, 0.462745, 0.376471 + color = 1.000000, 0.756863, 0.572549 + color = 0.349020, 0.368627, 0.000000 + color = 0.894118, 0.035294, 0.901961 + color = 0.725490, 0.694118, 0.717647 + color = 0.827451, 0.176471, 0.254902 + color = 0.196078, 0.258824, 0.215686 + color = 0.850980, 0.639216, 0.388235 + color = 0.356863, 0.545098, 0.200000 + color = 0.184314, 0.121569, 0.000000 + color = 0.596078, 0.905882, 0.843137 + color = 0.164706, 0.384314, 0.341176 + color = 0.807843, 0.447059, 0.301961 + color = 0.364706, 0.239216, 0.156863 + color = 0.000000, 0.349020, 0.850980 + color = 0.678431, 0.580392, 0.839216 + color = 0.419608, 0.117647, 0.580392 + color = 0.705882, 0.003922, 0.368627 + color = 0.254902, 0.000000, 0.274510 + color = 0.615686, 1.000000, 0.811765 + color = 0.894118, 0.282353, 0.615686 + color = 0.890196, 0.890196, 0.278431 + color = 0.862745, 0.886275, 0.647059 + color = 0.000000, 0.156863, 0.352941 + color = 0.666667, 0.356863, 0.509804 + color = 0.000000, 0.000000, 0.862745 + color = 0.294118, 0.305882, 0.317647 + color = 0.854902, 0.749020, 0.835294 + color = 0.000000, 0.301961, 0.600000 + color = 0.533333, 0.392157, 0.619608 + color = 0.415686, 0.117647, 0.113725 + color = 0.556863, 0.321569, 0.772549 + color = 0.721569, 0.854902, 0.874510 + color = 0.866667, 0.701961, 0.992157 + color = 0.482353, 0.282353, 0.329412 + color = 0.298039, 0.450980, 0.000000 + color = 0.270588, 0.000000, 0.466667 + color = 0.698039, 0.372549, 0.000000 + color = 0.572549, 0.819608, 0.525490 + color = 0.333333, 0.200000, 0.298039 + color = 0.411765, 0.690196, 0.521569 + color = 0.670588, 0.576471, 0.690196 + color = 0.905882, 0.329412, 0.258824 + color = 0.560784, 0.549020, 0.541176 + color = 0.439216, 0.678431, 0.317647 + color = 0.670588, 0.486275, 0.454902 + color = 0.000000, 0.203922, 0.235294 + color = 0.145098, 0.058824, 0.074510 + color = 0.905882, 0.690196, 0.000000 + color = 0.478431, 0.800000, 0.862745 + color = 0.094118, 0.078431, 0.227451 + color = 0.615686, 0.321569, 0.223529 + color = 0.733333, 0.482353, 0.192157 + color = 0.717647, 0.792157, 0.580392 + color = 0.192157, 0.031373, 0.000000 + color = 0.639216, 0.584314, 0.023529 + color = 0.000000, 0.854902, 0.729412 + color = 0.454902, 0.627451, 0.870588 + color = 0.388235, 0.235294, 0.450980 + color = 1.000000, 0.854902, 0.560784 + color = 0.466667, 0.721569, 0.000000 + color = 0.250980, 0.184314, 0.113725 + color = 0.345098, 0.529412, 0.349020 + color = 0.176471, 0.000000, 0.129412 + color = 0.960784, 0.631373, 0.831373 + color = 0.854902, 0.000000, 0.666667 + color = 0.462745, 0.160784, 0.286275 + color = 0.741176, 0.898039, 0.000000 + color = 0.764706, 0.760784, 0.364706 + } + } +} diff --git a/GameData/FerramAerospaceResearch/FARGUIColors.cfg b/GameData/FerramAerospaceResearch/FARGUIColors.cfg deleted file mode 100644 index c36340cc8..000000000 --- a/GameData/FerramAerospaceResearch/FARGUIColors.cfg +++ /dev/null @@ -1,8 +0,0 @@ -FARGUIColors -{ - name = Default - ClColor = 0.000,1.000,1.000 - CdColor = 1.000,0.000,0.000 - CmColor = 1.000,0.922,0.016 - L_DColor = 0.000,1.000,0.000 -} diff --git a/GameData/FerramAerospaceResearch/FARVoxelGeometryOverrides.cfg b/GameData/FerramAerospaceResearch/FARVoxelGeometryOverrides.cfg index 46a8fba39..ab0e8c8ee 100644 --- a/GameData/FerramAerospaceResearch/FARVoxelGeometryOverrides.cfg +++ b/GameData/FerramAerospaceResearch/FARVoxelGeometryOverrides.cfg @@ -4,7 +4,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = True - %ignoreIfNoRenderer = true } } @PART[adapterMk3-Mk2]:AFTER[FerramAerospaceResearch] @@ -12,7 +11,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[adapterMk3-Size2Slant]:AFTER[FerramAerospaceResearch] @@ -20,7 +18,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[adapterSize2-Mk2]:AFTER[FerramAerospaceResearch] @@ -28,7 +25,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[InflatableHeatShield]:AFTER[FerramAerospaceResearch] @@ -36,7 +32,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = True - %ignoreIfNoRenderer = true %rebuildOnAnimation = true } } @@ -73,7 +68,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[JetEngine]:AFTER[FerramAerospaceResearch] @@ -81,7 +75,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[turboFanSize2]:AFTER[FerramAerospaceResearch] @@ -89,7 +82,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[LiquidEngineKE-1]:AFTER[FerramAerospaceResearch] @@ -97,7 +89,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[Size3AdvancedEngine]:AFTER[FerramAerospaceResearch] @@ -105,7 +96,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[Size2LFB]:AFTER[FerramAerospaceResearch] @@ -113,7 +103,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[liquidEngine3_v2]:AFTER[FerramAerospaceResearch] @@ -121,7 +110,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[nuclearEngine]:AFTER[FerramAerospaceResearch] @@ -129,7 +117,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[liquidEngine]:AFTER[FerramAerospaceResearch] @@ -137,21 +124,18 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[LiquidEngineLV-T91]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[LiquidEngineLV-TX87]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[LiquidEngineRE-I2]:AFTER[FerramAerospaceResearch] @@ -159,7 +143,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[engineLargeSkipper]:AFTER[FerramAerospaceResearch] @@ -167,14 +150,12 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[liquidEngine2-2_v2]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[liquidEngine1-2]:AFTER[FerramAerospaceResearch] @@ -182,7 +163,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[LiquidEngineRK-7]:AFTER[FerramAerospaceResearch] @@ -190,7 +170,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[solidBooster_v2]:AFTER[FerramAerospaceResearch] @@ -198,7 +177,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[solidBooster_sm_v2]:AFTER[FerramAerospaceResearch] @@ -206,7 +184,6 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[LiquidEngineRV-1]:AFTER[FerramAerospaceResearch] @@ -214,21 +191,18 @@ @MODULE[GeometryPartModule] { %forceUseMeshes = true - %ignoreIfNoRenderer = true } } @PART[SSME]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[toroidalAerospike]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @@ -281,34 +255,29 @@ { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[HeatShield1]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[HeatShield2]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[HeatShield3]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } @PART[HeatShield1p5]:AFTER[FerramAerospaceResearch] { @MODULE[GeometryPartModule] { - %ignoreIfNoRenderer = true } } diff --git a/GameData/FerramAerospaceResearch/FerramAerospaceResearch.cfg b/GameData/FerramAerospaceResearch/FerramAerospaceResearch.cfg index 03b13884b..5364dffaa 100644 --- a/GameData/FerramAerospaceResearch/FerramAerospaceResearch.cfg +++ b/GameData/FerramAerospaceResearch/FerramAerospaceResearch.cfg @@ -60,7 +60,7 @@ { !MODULE[ModuleLiftingSurface] { } } -@PART[*]:HAS[KzFairingBaseShielding]:FOR[FerramAerospaceResearch] +@PART[*]:HAS[@MODULE[KzFairingBaseShielding]]:FOR[FerramAerospaceResearch] { !MODULE[KzFairingBaseShielding] { } } diff --git a/GameData/FerramAerospaceResearch/Localization/Localization.cfg b/GameData/FerramAerospaceResearch/Localization/Localization.cfg index fe95df6f8..5c836f356 100644 --- a/GameData/FerramAerospaceResearch/Localization/Localization.cfg +++ b/GameData/FerramAerospaceResearch/Localization/Localization.cfg @@ -192,7 +192,7 @@ FAREditorSimGraphTime = Time (s) FAREditorSimGraphParams = Params - FAREditorSimInit = Init + FAREditorSimInit = Init\u0020 FAREditorSimEndTime = EndTime: FAREditorSimTimestep = dt: FAREditorSimRunButton = Run Simulation @@ -279,6 +279,9 @@ FARFlightGUIAtmDens = Atm Density:\u0020 FARFlightGUIFltDataBtn = Flt Data FARFlightGUIFltSettings = Flt Settings + FARFlightGUIFltLogging = Flt Log + FARFlightGUIFltLogPeriod = Log Period + FARFlightGUIFltLogFlushPeriod = Flush Period FARFlightGUIFltAssistance = Flight Assistance Toggles: FARFlightSettingsTitle = FAR Settings @@ -352,7 +355,7 @@ RCLStatusCut = CUT RCLSettingMinPres = Min pressure - RCLSettingAlt = Altitude + RCLSettingAlt = Altitude\t\t RCLStatusSpare = Spare chutes RCLStatusChuteTemp = Chute temp RCLTempUnit = °C @@ -397,7 +400,7 @@ RCLGUI8 = Drag coefficient <<1>> RCLGUI9 = Predeployed diameter: <<1>>m\nArea: <<2>>m² RCLGUI10 = Deployed diameter: <<1>>m\nArea: <<2>>m² - + RCLGUISafe = Deployment safety: safe RCLGUIRisky = Deployment safety: risky RCLGUIDang = Deployment safety: dangerous diff --git a/GameData/FerramAerospaceResearch/Localization/Localization_de-de.cfg b/GameData/FerramAerospaceResearch/Localization/Localization_de-de.cfg index c8b5130e8..00823a967 100644 --- a/GameData/FerramAerospaceResearch/Localization/Localization_de-de.cfg +++ b/GameData/FerramAerospaceResearch/Localization/Localization_de-de.cfg @@ -285,6 +285,9 @@ Localization FARFlightGUIAtmDens = Atm Dichte:\u0020 FARFlightGUIFltDataBtn = Flt Daten FARFlightGUIFltSettings = Flt Einstellungen + FARFlightGUIFltLogging = Flt Log + FARFlightGUIFltLogPeriod = Log Period + FARFlightGUIFltLogFlushPeriod = Flush Period FARFlightGUIFltAssistance = Flughilfe Einstellungen: FARFlightSettingsTitle = FAR Einstellungen diff --git a/GameData/FerramAerospaceResearch/Localization/Localization_ru.cfg b/GameData/FerramAerospaceResearch/Localization/Localization_ru.cfg index bd2149219..3b497cc35 100644 --- a/GameData/FerramAerospaceResearch/Localization/Localization_ru.cfg +++ b/GameData/FerramAerospaceResearch/Localization/Localization_ru.cfg @@ -25,8 +25,8 @@ FARAbbrevMach = ч. Маха FAREditorTitle = Анализ FAR - - //Next menu items are not shown correctly with dynamic menu button width + + //Next menu items are not shown correctly with dynamic menu button width FAREditorModeStatic = Статический анализ FAREditorModeDataStab = Данные + Коэфф-ты устойчивости FAREditorModeDerivSim = Симуляция устойчивости @@ -255,12 +255,15 @@ FARFlightGUIWindowSelect0 = Полётные данные FARFlightGUIWindowSelect1 = Авт Стаб FARFlightGUIWindowSelect2 = Возд Скор - FARFlightGUIWindowSelect3 = Визуал-ия Аэрод-ки + FARFlightGUIWindowSelect3 = Визуал-ия Аэрод-ки\u0020 FARFlightGUIReynolds = Ч. Рейнольдса: 「0:E2」 FARFlightGUIAtmDens = Плотн. возд.:\u0020 FARFlightGUIFltDataBtn = Полётные данные FARFlightGUIFltSettings = Установки полёта + FARFLightGUIFltLogging = Flt Log + FARFlightGUIFltLogPeriod = Log Period + FARFlightGUIFltLogFlushPeriod = Flush Period FARFlightGUIFltAssistance = Перекл помощь пилот-я: FARFlightSettingsTitle = Настройки FAR @@ -334,13 +337,13 @@ RCLStatusCut = ОТЦЕПЛЕН RCLSettingMinPres = Мин. давление - RCLSettingAlt = Высота + RCLSettingAlt = Высота\t\t RCLStatusSpare = Запасных куполов RCLStatusChuteTemp = Темп. парашюта RCLTempUnit = °C RCLStatusMaxTemp = Термостойкость купола - RCLEventDeploy = Выпуск + RCLEventDeploy = Выпуск\u0020 RCLEventCut = Отцепить RCLEventDisarm = Снять со взвода RCLEventRepack = Уложить @@ -379,7 +382,7 @@ RCLGUI8 = Коэфф. сопр-я <<1>> RCLGUI9 = Диаметр вытянутого: <<1>>м\nПлощадь: <<2>>м² RCLGUI10 = Диаметр раскрытого: <<1>>м\nПлощадь: <<2>>м² - + RCLGUISafe = Риск обрыва: безопасно RCLGUIRisky = Риск обрыва: рискованно RCLGUIDang = Риск обрыва: опасно diff --git a/GameData/FerramAerospaceResearch/Localization/Localization_zh-cn.cfg b/GameData/FerramAerospaceResearch/Localization/Localization_zh-cn.cfg index 8abb487c7..b45be5023 100644 --- a/GameData/FerramAerospaceResearch/Localization/Localization_zh-cn.cfg +++ b/GameData/FerramAerospaceResearch/Localization/Localization_zh-cn.cfg @@ -192,7 +192,7 @@ FAREditorSimGraphTime = 时间 (s) FAREditorSimGraphParams = 参数 - FAREditorSimInit = 初始化 + FAREditorSimInit = 初始化\u0020 FAREditorSimEndTime = 终止时间: FAREditorSimTimestep = 步进时间: FAREditorSimRunButton = 运行模拟 @@ -279,6 +279,9 @@ FARFlightGUIAtmDens = 大气密度:\u0020 FARFlightGUIFltDataBtn = 飞行数据 FARFlightGUIFltSettings = 飞行设定 + FARFlightGUIFltLogging = Flt Log + FARFlightGUIFltLogPeriod = Log Period + FARFlightGUIFltLogFlushPeriod = Flush Period FARFlightGUIFltAssistance = 飞行辅助切换: FARFlightSettingsTitle = FAR设置 diff --git a/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.Base.dll b/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.Base.dll new file mode 100644 index 000000000..b1305ab7f Binary files /dev/null and b/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.Base.dll differ diff --git a/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.dll b/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.dll index 8abc2cac4..550f12b90 100644 Binary files a/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.dll and b/GameData/FerramAerospaceResearch/Plugins/FerramAerospaceResearch.dll differ diff --git a/GameData/FerramAerospaceResearch/Plugins/ferramGraph.dll b/GameData/FerramAerospaceResearch/Plugins/ferramGraph.dll index 28d6d0a60..a0a7e978e 100644 Binary files a/GameData/FerramAerospaceResearch/Plugins/ferramGraph.dll and b/GameData/FerramAerospaceResearch/Plugins/ferramGraph.dll differ diff --git a/GameData/FerramAerospaceResearch/Textures/icon_button_blizzy.png b/GameData/FerramAerospaceResearch/Textures/icon_button_blizzy.png index aee6ec36a..fa5013408 100644 Binary files a/GameData/FerramAerospaceResearch/Textures/icon_button_blizzy.png and b/GameData/FerramAerospaceResearch/Textures/icon_button_blizzy.png differ diff --git a/GameData/FerramAerospaceResearch/Textures/icon_button_stock.png b/GameData/FerramAerospaceResearch/Textures/icon_button_stock.png index e322602c9..89e1e82c8 100644 Binary files a/GameData/FerramAerospaceResearch/Textures/icon_button_stock.png and b/GameData/FerramAerospaceResearch/Textures/icon_button_stock.png differ diff --git a/GameData/FerramAerospaceResearch/Textures/sprite_debug_voxel.png b/GameData/FerramAerospaceResearch/Textures/sprite_debug_voxel.png index ca949e154..9c383e108 100644 Binary files a/GameData/FerramAerospaceResearch/Textures/sprite_debug_voxel.png and b/GameData/FerramAerospaceResearch/Textures/sprite_debug_voxel.png differ diff --git a/README.md b/README.md index 89fc4183b..4aded61ed 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -Ferram Aerospace Research Continued v0.15.11.4 "Mach" +Ferram Aerospace Research Continued v0.16.0.0 "Mader" ========================= Aerodynamics model for Kerbal Space Program - Serious thanks: + Serious thanks: * a.g., for tons of bugfixes and code-refactorings - * stupid_chris, for the RealChuteLite implementation + * stupid_chris, for the RealChuteLite implementation * Taverius, for correcting a ton of incorrect values - * Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts + * Tetryds, for finding lots of bugs and issues and not letting me get away with them, and work on example crafts * sarbian, for refactoring code for working with MechJeb, and the Module Manager updates * ialdabaoth (who is awesome), who originally created Module Manager * Regex, for adding RPM support @@ -64,6 +64,33 @@ Set all the other winglet/control surface values to zero CHANGELOG ======================================================= +0.16.0.0V "Mader"------------------------------------ + +Update to MM 4.1.4 +Update to KSP 1.10 + +Added more config options (see `FARConfig.cfg`): + +* Additional log messages can be enabled +* Log FAR flight variables to text file +* Debug voxels are now colored by part (customizable) +* Removed `FARGUIColors.cfg` and integrated it into `FARConfig.cfg` + +Added new DLL `FerramAerospaceResearch.Base.dll` which is independent of KSP +Unchanged configs should no longer be saved to new files +Update Chinese localization (thanks [@tinygrox](https://github.com/tinygrox), [#88](https://github.com/dkavolis/Ferram-Aerospace-Research/pull/88)) +Workaround for `KSPUpgradePipeline` with removed stock control surface modules +Fix KSP resetting shielded state on decouple +Heating should now be closer (and higher) to stock values, KSP applies magic scaling to areas which made FAR calculated exposed areas significantly smaller than stock (can be reverted with MM patch) +Meshes used for voxelization are now displayed in log with `debug` FAR log level +Fix inconsistent voxelization when changing from VAB/SPH to Flight scene and reverting ([#89](https://github.com/dkavolis/Ferram-Aerospace-Research/issues/89)) +Fix voxelization starting before part is set up in editor +Ignore launch clamps in editor simulations +Fix NRE with MechJeb on destruction ([#93](https://github.com/dkavolis/Ferram-Aerospace-Research/issues/93)) +Resized stock button image to 36x36 px +Simulation buttons are now disabled while voxelization is active +Invisible meshes are ignored for voxelization by default + 0.15.11.4V "Mach"------------------------------------ Update to MM 4.1.3 diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.far b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.far index a2cb00e7b..fd3bd0a88 100644 Binary files a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.far and b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.far differ diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.manifest b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.manifest index b64888abf..d7d975244 100644 --- a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.manifest +++ b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_linux.manifest @@ -1,9 +1,9 @@ ManifestFileVersion: 0 -CRC: 3767505300 +CRC: 3687521154 Hashes: AssetFileHash: serializedVersion: 2 - Hash: b96b25a77315c66e802b66c6ec872e56 + Hash: 265412303d4f7b52bde22d10c79abaa5 TypeTreeHash: serializedVersion: 2 Hash: 677a1d6a6e8c5d2da1d9d0fadde392d8 diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.far b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.far index f83a439f5..08a687f31 100644 Binary files a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.far and b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.far differ diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.manifest b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.manifest index 1c33137db..f4859603a 100644 --- a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.manifest +++ b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_macosx.manifest @@ -1,9 +1,9 @@ ManifestFileVersion: 0 -CRC: 3026478533 +CRC: 1597964080 Hashes: AssetFileHash: serializedVersion: 2 - Hash: 3b0603a5918b00647b820271c16011a3 + Hash: b2dcc0766f16a1f4cfd92f86b022e53d TypeTreeHash: serializedVersion: 2 Hash: 677a1d6a6e8c5d2da1d9d0fadde392d8 diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.far b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.far index 7a0f963cb..460f0b321 100644 Binary files a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.far and b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.far differ diff --git a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.manifest b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.manifest index 26f33a309..5888a601b 100644 --- a/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.manifest +++ b/Unity/FerramAerospaceResearch/AssetBundles/farshaders_windows.manifest @@ -1,9 +1,9 @@ ManifestFileVersion: 0 -CRC: 2321529484 +CRC: 1324268531 Hashes: AssetFileHash: serializedVersion: 2 - Hash: a23f1ba139204971af4e1913ddd139d0 + Hash: 304ed4f11411d31aac77b104d6fc503d TypeTreeHash: serializedVersion: 2 Hash: 677a1d6a6e8c5d2da1d9d0fadde392d8 diff --git a/Unity/FerramAerospaceResearch/Assets/Plugins.meta b/Unity/FerramAerospaceResearch/Assets/Plugins.meta new file mode 100644 index 000000000..ea6e3add7 --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bab452c2a4b0ee1478bdf63d517be6d0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs b/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs new file mode 100644 index 000000000..fbef9005b --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using FerramAerospaceResearch; +using Unity.Collections; +using Unity.Jobs; + +// a very minimal MonoBehaviour that references FerramAerospaceResearch so that Burst picks up its jobs +public class BurstCompileFARJobs : MonoBehaviour +{ + void Start() + { + Debug.Log(FerramAerospaceResearch.Version.LongString); + } + +} diff --git a/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs.meta b/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs.meta new file mode 100644 index 000000000..91044e07a --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Plugins/BurstCompileFARJobs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b3a3e5374852b84880c938232b6c2df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll b/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll new file mode 100644 index 000000000..b1305ab7f Binary files /dev/null and b/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll differ diff --git a/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll.meta b/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll.meta new file mode 100644 index 000000000..09d1a9b88 --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Plugins/FerramAerospaceResearch.Base.dll.meta @@ -0,0 +1,81 @@ +fileFormatVersion: 2 +guid: 3744d96ddb68b1248bc516e0352c6505 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + '': Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 0 + Exclude OSXUniversal: 0 + Exclude Win: 0 + Exclude Win64: 0 + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Facebook: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Facebook: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Scenes.meta b/Unity/FerramAerospaceResearch/Assets/Scenes.meta new file mode 100644 index 000000000..01dc9d8e1 --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 06ff07add40b11d419d2afac1b72010e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity b/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity new file mode 100644 index 000000000..310e3bbfa --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity @@ -0,0 +1,249 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1900725046 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1900725049} + - component: {fileID: 1900725048} + - component: {fileID: 1900725047} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1900725047 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900725046} + m_Enabled: 1 +--- !u!20 &1900725048 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900725046} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1900725049 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900725046} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2008401368} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2008401367 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2008401368} + - component: {fileID: 2008401369} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2008401368 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2008401367} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1900725049} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2008401369 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2008401367} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1269053971, guid: 3744d96ddb68b1248bc516e0352c6505, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity.meta b/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity.meta new file mode 100644 index 000000000..354f69f0b --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Scenes/BurstLink.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9c5db93f47e8ae1448ad5780180da2bf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Scripts.meta b/Unity/FerramAerospaceResearch/Assets/Scripts.meta new file mode 100644 index 000000000..ca257d750 --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fd84c48372bcf840c97402e6a9ca295f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Assets/Shaders/DebugVoxelMesh.shader b/Unity/FerramAerospaceResearch/Assets/Shaders/DebugVoxelMesh.shader index 91eb5ef3f..89b4f7415 100644 --- a/Unity/FerramAerospaceResearch/Assets/Shaders/DebugVoxelMesh.shader +++ b/Unity/FerramAerospaceResearch/Assets/Shaders/DebugVoxelMesh.shader @@ -56,6 +56,7 @@ Shader "FerramAerospaceResearch/Debug Voxel Mesh" { struct Input { float2 uv_MainTex; + fixed4 color : COLOR; }; fixed4 _Color; @@ -63,7 +64,7 @@ Shader "FerramAerospaceResearch/Debug Voxel Mesh" { void surf(Input IN, inout SurfaceOutput o) { // Albedo comes from a texture tinted by color - fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; + fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color * IN.color; o.Albedo = c.rgb; o.Alpha = c.a; diff --git a/Unity/FerramAerospaceResearch/Assets/TextMesh Pro.meta b/Unity/FerramAerospaceResearch/Assets/TextMesh Pro.meta new file mode 100644 index 000000000..f9da8b5e3 --- /dev/null +++ b/Unity/FerramAerospaceResearch/Assets/TextMesh Pro.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f54d1bd14bd3ca042bd867b519fee8cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/FerramAerospaceResearch/Packages/manifest.json b/Unity/FerramAerospaceResearch/Packages/manifest.json index 9d8b1d541..dd774dd4c 100644 --- a/Unity/FerramAerospaceResearch/Packages/manifest.json +++ b/Unity/FerramAerospaceResearch/Packages/manifest.json @@ -1,7 +1,8 @@ { "dependencies": { "com.unity.assetbundlebrowser": "1.7.0", - "com.unity.ide.rider": "1.1.1", + "com.unity.burst": "1.3.1", + "com.unity.collections": "0.1.1-preview", "com.unity.ide.vscode": "1.0.7", "com.unity.package-manager-ui": "2.2.0", "com.unity.test-framework": "1.0.18", diff --git a/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneLinux64.json b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneLinux64.json new file mode 100644 index 000000000..a8d5b4e5f --- /dev/null +++ b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneLinux64.json @@ -0,0 +1,15 @@ +{ + "MonoBehaviour": { + "Version": 3, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "UsePlatformSDKLinker": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX64": -1 + } +} diff --git a/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneOSX.json b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneOSX.json new file mode 100644 index 000000000..a8d5b4e5f --- /dev/null +++ b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneOSX.json @@ -0,0 +1,15 @@ +{ + "MonoBehaviour": { + "Version": 3, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "UsePlatformSDKLinker": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX64": -1 + } +} diff --git a/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneWindows.json b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneWindows.json new file mode 100644 index 000000000..fe76bef80 --- /dev/null +++ b/Unity/FerramAerospaceResearch/ProjectSettings/BurstAotSettings_StandaloneWindows.json @@ -0,0 +1,16 @@ +{ + "MonoBehaviour": { + "Version": 3, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "UsePlatformSDKLinker": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX32": -1, + "CpuTargetsX64": -1 + } +} diff --git a/Unity/FerramAerospaceResearch/ProjectSettings/ProjectSettings.asset b/Unity/FerramAerospaceResearch/ProjectSettings/ProjectSettings.asset index b20ce12d4..a7b0882ae 100644 --- a/Unity/FerramAerospaceResearch/ProjectSettings/ProjectSettings.asset +++ b/Unity/FerramAerospaceResearch/ProjectSettings/ProjectSettings.asset @@ -531,7 +531,8 @@ PlayerSettings: scriptingRuntimeVersion: 1 gcIncremental: 0 gcWBarrierValidation: 0 - apiCompatibilityLevelPerPlatform: {} + apiCompatibilityLevelPerPlatform: + Standalone: 3 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: FerramAerospaceResearch diff --git a/Unity/FerramAerospaceResearch/ProjectSettings/UnityConnectSettings.asset b/Unity/FerramAerospaceResearch/ProjectSettings/UnityConnectSettings.asset index 1cc5485b8..c3ae9a020 100644 --- a/Unity/FerramAerospaceResearch/ProjectSettings/UnityConnectSettings.asset +++ b/Unity/FerramAerospaceResearch/ProjectSettings/UnityConnectSettings.asset @@ -3,29 +3,29 @@ --- !u!310 &1 UnityConnectSettings: m_ObjectHideFlags: 0 - m_Enabled: 0 + serializedVersion: 1 + m_Enabled: 1 m_TestMode: 0 - m_TestEventUrl: - m_TestConfigUrl: + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com m_TestInitMode: 0 CrashReportingSettings: - m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes + m_EventUrl: https://perf-events.cloud.unity3d.com m_Enabled: 0 + m_LogBufferSize: 10 m_CaptureEditorExceptions: 1 UnityPurchasingSettings: m_Enabled: 0 m_TestMode: 0 UnityAnalyticsSettings: m_Enabled: 0 - m_InitializeOnStartup: 1 m_TestMode: 0 - m_TestEventUrl: - m_TestConfigUrl: + m_InitializeOnStartup: 1 UnityAdsSettings: m_Enabled: 0 m_InitializeOnStartup: 1 m_TestMode: 0 - m_EnabledPlatforms: 4294967295 m_IosGameId: m_AndroidGameId: m_GameIds: {} diff --git a/bin/Debug/FerramAerospaceResearch.dll b/bin/Debug/FerramAerospaceResearch.dll deleted file mode 100644 index b829875fd..000000000 Binary files a/bin/Debug/FerramAerospaceResearch.dll and /dev/null differ diff --git a/bin/Debug/ferramGraph.dll b/bin/Debug/ferramGraph.dll deleted file mode 100644 index f621f4e6d..000000000 Binary files a/bin/Debug/ferramGraph.dll and /dev/null differ diff --git a/buildtools b/buildtools index 01b6d0ed9..e9ed8fda2 160000 --- a/buildtools +++ b/buildtools @@ -1 +1 @@ -Subproject commit 01b6d0ed9b5c86c5adbcc0f56071f0fb6ffe7992 +Subproject commit e9ed8fda26b1d205f19525a6adb641b0614d0b6b diff --git a/config.json b/config.json index 108b82c18..1c2d39d0e 100644 --- a/config.json +++ b/config.json @@ -7,24 +7,28 @@ "ModDir": "$(SolutionDir)$(ModDirRelative)", "PluginDir": "$(ModDir)Plugins/", "AssetDir": "$(ModDir)Assets/", - "KSP_DIR_INSTALL": "C:/Zaidimai/KSP 1.9.0/", + "KSP_DIR_INSTALL": "C:/Zaidimai/KSP 1.10/", "KSPGameData": "$(KSP_DIR_INSTALL)GameData/", "GameDir": "$(KSPGameData)$(ModName)/", "VersionMajor": 0, - "VersionMinor": 15, - "VersionBuild": 11, - "VersionRevision": 4, - "VersionName": "Mach", - "Year": 2019, + "VersionMinor": 16, + "VersionBuild": 0, + "VersionRevision": 0, + "VersionName": "Mader", + "Year": 2020, "NumericalVersion": "$(VersionMajor).$(VersionMinor).$(VersionBuild).$(VersionRevision)", "VersionString": "$(NumericalVersion) \"$(VersionName)\"", "VersionRegex": "\\d+\\.\\d+\\.\\d+(?:\\.\\d+)?\\s*\"\\w+\"", "KSPMajorMin": 1, "KSPMajorMax": 1, "KSPMinorMin": 8, - "KSPMinorMax": 9, - "UnityDir": "Unity/$(ModName)/", - "AssetBundleDir": "$(UnityDir)AssetBundles/" + "KSPMinorMax": 10, + "UnityDir": "$(SolutionDir)Unity/$(ModName)/", + "AssetBundleDir": "$(UnityDir)AssetBundles/", + "UnityAssetsDir": "$(UnityDir)Assets/", + "UnityPluginsDir": "$(UnityAssetsDir)Plugins/", + "BurstOuputDir": "$(SolutionDir)Unity/Burst/", + "BurstOuputName": "lib_burst_generated" }, "post_build": { "clean": [], @@ -38,6 +42,18 @@ "destination": "$(AssetDir)" } ], + "[FerramAerospaceResearch.Base]": { + "install": [ + { + "source": "$(TargetDir)$(TargetName).*", + "destination": "$(PluginDir)" + }, + { + "source": "$(TargetDir)$(TargetName).*", + "destination": "$(UnityPluginsDir)" + } + ] + }, "[FerramAerospaceResearch]": { "clean": [ "$(GameDir)" @@ -74,7 +90,7 @@ ] }, { - "pattern": "$(ModName)/FARUtils/FARVersion.cs", + "pattern": "$(ModName).Base/Version.cs", "substitutions": [ { "search": "Major = \\d+;", @@ -112,7 +128,7 @@ ] }, { - "pattern": "$(ModName)/Properties/AssemblyInfo.cs", + "pattern": "$(ModName)*/Properties/AssemblyInfo.cs", "substitutions": [ { "search": "(Copyright .* )\\d+", @@ -184,5 +200,50 @@ ] } ] + }, + "burst_compile": { + "bcl": "$(UnityDir)Library/PackageCache/com.unity.burst@1.3.1/.Runtime/bcl.exe", + "debug": true, + "targets": [ + { + "platform": "Windows", + "include": null, + "safety_checks": false, + "fastmath": false, + "targets": [ + "X64_SSE2", + "X64_SSE4", + "AVX", + "AVX2" + ], + "enable_guard": false, + "float_precision": "Standard", + "float_mode": "Default", + "debug": "None", + "debugMode": false, + "output": "$(BurstOuputDir)windows/$(BurstOuputName)", + "verbose": false, + "log_timings": true, + "root_assemblies": [ + "$(PluginDir)*.dll", + "$(KSP_DIR_INSTALL)KSP_x64_Data/Managed/*.dll" + ], + "assembly_folders": [ + "$(KSP_DIR_INSTALL)KSP_x64_Data/Managed", + "$(PluginDir)" + ], + "include_root_assembly_references": true + }, + { + "platform": "Linux", + "include": "Windows", + "output": "$(BurstOuputDir)linux/$(BurstOuputName)" + }, + { + "platform": "macOS", + "include": "Windows", + "output": "$(BurstOuputDir)macos/$(BurstOuputName)" + } + ] } } diff --git a/ferramGraph/ferramDrawingExtensions.cs b/ferramGraph/ferramDrawingExtensions.cs index 4d79e5f65..98880a560 100644 --- a/ferramGraph/ferramDrawingExtensions.cs +++ b/ferramGraph/ferramDrawingExtensions.cs @@ -1,6 +1,6 @@ /* Name: FerramGraph (Graph GUI Plugin) * Version: 1.3 (KSP 0.22+) -Copyright 2019, Daumantas Kavolis, aka dkavolis +Copyright 2020, Daumantas Kavolis, aka dkavolis This file is part of FerramGraph. diff --git a/ferramGraph/ferram_graph.cs b/ferramGraph/ferram_graph.cs index 5e1791d42..d838f0549 100644 --- a/ferramGraph/ferram_graph.cs +++ b/ferramGraph/ferram_graph.cs @@ -1,6 +1,6 @@ /* Name: FerramGraph (Graph GUI Plugin) * Version: 1.3 (KSP 0.22+) -Copyright 2019, Michael Ferrara, aka Ferram4 +Copyright 2020, Michael Ferrara, aka Ferram4 This file is part of FerramGraph. diff --git a/icons/icon_button.svg b/icons/icon_button.svg index 1ea92329f..f2e200327 100644 --- a/icons/icon_button.svg +++ b/icons/icon_button.svg @@ -9,16 +9,16 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="36" - height="36" - viewBox="0 0 9.5249997 9.5249997" + width="38" + height="38" + viewBox="0 0 10.054166 10.054166" version="1.1" id="svg4573" - inkscape:version="0.92.3 (2405546, 2018-03-11)" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" sodipodi:docname="icon_button.svg" - inkscape:export-filename="D:\git\Ferram-Aerospace-Research\Resources\icon_button_blizzy.png" - inkscape:export-xdpi="64" - inkscape:export-ydpi="64"> + inkscape:export-filename="D:\git\Ferram-Aerospace-Research\GameData\FerramAerospaceResearch\Textures\icon_button_stock.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + inkscape:window-width="2560" + inkscape:window-height="1417" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" /> @@ -49,7 +49,7 @@ image/svg+xml - + @@ -57,12 +57,12 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" - transform="translate(0,-287.475)"> + transform="translate(0,-286.94583)"> + inkscape:export-filename="D:\git\Ferram-Aerospace-Research\GameData\FerramAerospaceResearch\Textures\sprite_debug_voxel.png" + inkscape:export-xdpi="576" + inkscape:export-ydpi="576"> + style="fill:#ffffff;fill-opacity:0.39195979;stroke:#aaaaaa;stroke-width:0.30000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:9.69999981;stroke-dasharray:none;stroke-opacity:1" /> + style="fill:none;stroke:#aaaaaa;stroke-width:0.30000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:9.69999981;stroke-dasharray:none;stroke-opacity:1" /> + style="fill:none;stroke:#aaaaaa;stroke-width:0.30000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:9.69999981;stroke-dasharray:none;stroke-opacity:1" />